Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH Use archive text when file archiving is enabled #1378

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions client/lang/src/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,31 @@
"AssetAdmin.BACK": "Back",
"AssetAdmin.BACK_DESCRIPTION": "Navigate up a level",
"AssetAdmin.BULK_ACTIONS_CONFIRM": "Are you sure you want to %s these files?",
"AssetAdmin.BULK_ACTIONS_ARCHIVE": "Archive",
"AssetAdmin.BULK_ACTIONS_ARCHIVE_ITEMS_CONFIRM": "You're about to archive %s file(s) which may be used in your site's content. Carefully check the file usage on the files before archiving the folder.",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message is knowingly wrong where it says archiving the folder instead of archiving the file(s) - this is because this text is tested in a jest test that will be updated in #1379

"AssetAdmin.BULK_ACTIONS_ARCHIVE_FAIL_02": "%s folders/files were successfully archived, but %s files were not able to be archived.",
"AssetAdmin.BULK_ACTIONS_ARCHIVE_FOLDER_CONFIRM": "Are you sure you want to archive this folder?",
"AssetAdmin.BULK_ACTIONS_ARCHIVE_FOLDERS_CONFIRM": "Are you sure you want to archive these folders?",
"AssetAdmin.BULK_ACTIONS_ARCHIVE_SUCCESS_02": "%s folders/files were successfully archived.",
"AssetAdmin.BULK_ACTIONS_ARCHIVE_WARNING": "Ensure files are removed from content areas prior to archiving them, otherwise they will appear as broken links.",
"AssetAdmin.BULK_ACTIONS_DELETE": "Delete",
"AssetAdmin.BULK_ACTIONS_DELETE_CONFIRM": "Are you sure you want to delete these files?",
"AssetAdmin.BULK_ACTIONS_DELETE_FAIL": "%s folders/files were successfully archived, but %s files were not able to be archived.",
"AssetAdmin.BULK_ACTIONS_DELETE_FAIL_02": "%s folders/files were successfully deleted, but %s files were not able to be deleted.",
"AssetAdmin.BULK_ACTIONS_DELETE_FOLDER": "These folders contain files which are currently in use, you must move or delete their contents before you can delete the folder.",
"AssetAdmin.BULK_ACTIONS_DELETE_FOLDER_CONFIRM": "Are you sure you want to delete this folder?",
"AssetAdmin.BULK_ACTIONS_DELETE_FOLDERS_CONFIRM": "Are you sure you want to delete these folders?",
"AssetAdmin.BULK_ACTIONS_DELETE_ITEMS_CONFIRM": "You're about to delete %s file(s) which may be used in your site's content. Carefully check the file usage on the files before deleting the folder.",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message is knowingly wrong where it says deleting the folder instead of deleting the file(s) - this is because this text is tested in a jest test that will be updated in #1379

"AssetAdmin.BULK_ACTIONS_DELETE_MULTI_CONFIRM": "There are %s files currently in use, are you sure you want to delete these files?",
"AssetAdmin.BULK_ACTIONS_DELETE_SINGLE_CONFIRM": "This file is currently in use in %s places, are you sure you want to delete it?",
"AssetAdmin.BULK_ACTIONS_DELETE_SUCCESS": "%s folders/files were successfully archived.",
"AssetAdmin.BULK_ACTIONS_DELETE_SUCCESS_02": "%s folders/files were successfully deleted.",
"AssetAdmin.BULK_ACTIONS_DELETE_WARNING": "Ensure files are removed from content areas prior to deleting them, otherwise they will appear as broken links.",
"AssetAdmin.BULK_ACTIONS_PLACEHOLDER": "Select an action...",
"AssetAdmin.CANCEL": "Cancel",
"AssetAdmin.CONFIRMDELETE": "Are you sure you want to delete this record?",
"AssetAdmin.CONFIRM_FILE_ARCHIVE": "Confirm archive",
"AssetAdmin.CONFIRM_FILE_DELETION": "Confirm deletion",
"AssetAdmin.CREATED": "First uploaded",
"AssetAdmin.DELETE": "Delete",
"AssetAdmin.DIM": "Dimensions",
Expand Down
12 changes: 12 additions & 0 deletions client/src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export default {
items.every(item => item && item.canDelete)
),
},
// Archive is the same as Delete just with a different label and icon
// There is logic to choose which bulk-action to use in Gallery.js
{
value: 'archive',
label: i18n._t('AssetAdmin.BULK_ACTIONS_ARCHIVE', 'Archive'),
className: 'font-icon-box',
destructive: true,
callback: null, // defined in <Gallery> for now
canApply: (items) => (
items.every(item => item && item.canDelete)
),
},
{
value: 'edit',
label: i18n._t('AssetAdmin.BULK_ACTIONS_EDIT', 'Edit'),
Expand Down
23 changes: 17 additions & 6 deletions client/src/containers/AssetAdmin/AssetAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,21 +357,31 @@ class AssetAdmin extends Component {
})
.then((resultItems) => {
const successes = resultItems.filter((result) => result).length;
const { archiveFiles } = this.props.sectionConfig;
if (successes !== ids.length) {
let transKey = 'AssetAdmin.BULK_ACTIONS_DELETE_FAIL_02';
let transDefault = '%s folders/files were successfully deleted, but %s files were not able to be deleted.';
if (archiveFiles) {
transKey = 'AssetAdmin.BULK_ACTIONS_ARCHIVE_FAIL_02';
transDefault = '%s folders/files were successfully archived, but %s files were not able to be archived.';
}
this.props.actions.toasts.error(
i18n.sprintf(
i18n._t(
'AssetAdmin.BULK_ACTIONS_DELETE_FAIL',
'%s folders/files were successfully deleted, but %s files were not able to be deleted.'
),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This key was wrong because in en.json the text is archived instead of deleted

i18n._t(transKey, transDefault),
successes,
ids.length - successes
)
);
} else {
let transKey = 'AssetAdmin.BULK_ACTIONS_DELETE_SUCCESS_02';
let transDefault = '%s folders/files were successfully deleted.';
if (archiveFiles) {
transKey = 'AssetAdmin.BULK_ACTIONS_ARCHIVE_SUCCESS_02';
transDefault = '%s folders/files were successfully archived.';
}
this.props.actions.toasts.success(
i18n.sprintf(
i18n._t('AssetAdmin.BULK_ACTIONS_DELETE_SUCCESS', '%s folders/files were successfully deleted.'),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This key was wrong because in en.json the text is archived instead of deleted

i18n._t(transKey, transDefault),
successes
)
);
Expand Down Expand Up @@ -674,6 +684,7 @@ class AssetAdmin extends Component {

render() {
const { folder, folderId, query, getUrl, type, maxFiles, toolbarChildren } = this.props;
const { archiveFiles } = this.props.sectionConfig;

const showBackButton = Boolean(folderId || hasFilters(query.filter));
const searchFormSchemaUrl = this.props.sectionConfig.form.fileSearchForm.schemaUrl;
Expand Down Expand Up @@ -723,7 +734,7 @@ class AssetAdmin extends Component {
{this.renderGallery()}
{this.renderEditor()}
</div>
<BulkDeleteConfirmation onConfirm={this.handleDelete} />
<BulkDeleteConfirmation onConfirm={this.handleDelete} archiveFiles={archiveFiles} />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import i18n from 'i18n';
const BulkDeleteConfirmation = ({
loading, LoadingComponent, transition,
files, descendantFileCounts,
onModalClose, onCancel, onConfirm
onModalClose, onCancel, onConfirm, archiveFiles
}) => {
let body = null;
const transKey = archiveFiles ? 'AssetAdmin.ARCHIVE' : 'AssetAdmin.DELETE';
const transDefault = archiveFiles ? 'Archive' : 'Delete';
let actions = [
{
label: i18n._t('AssetAdmin.DELETE', 'Delete'),
label: i18n._t(transKey, transDefault),
handler: () => onConfirm(files.map(({ id }) => id)),
color: 'danger'
},
Expand All @@ -42,7 +44,7 @@ const BulkDeleteConfirmation = ({
const folderDescendantFileTotals = getFolderDescendantFileTotals(files, descendantFileCounts);
const fileTotalItems = getFileTotalItems(files);

const bodyProps = { folderCount, folderDescendantFileTotals, fileTotalItems };
const bodyProps = { folderCount, folderDescendantFileTotals, fileTotalItems, archiveFiles };
body = <BulkDeleteMessage {...bodyProps} />;

if (folderDescendantFileTotals.totalItems || fileTotalItems) {
Expand All @@ -53,10 +55,10 @@ const BulkDeleteConfirmation = ({
color: 'primary'
},
{
label: i18n._t('AssetAdmin.DELETE', 'Delete'),
label: i18n._t(transKey, transDefault),
handler: () => onConfirm(files.map(({ id }) => id)),
color: 'danger',
},
}
];
}
}
Expand All @@ -72,6 +74,7 @@ const BulkDeleteConfirmation = ({
actions={actions}
onCancel={onCancel}
onClosed={onModalClose}
archiveFiles={archiveFiles}
/>);
};

Expand All @@ -84,6 +87,11 @@ BulkDeleteConfirmation.propTypes = {
onCancel: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
onConfirm: PropTypes.func.isRequired,
archiveFiles: PropTypes.bool,
};

BulkDeleteConfirmation.defaultProps = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding default props for now for existing jest tests to pass, will be removed in #1379 and .isRequred will be added to the propType

archiveFiles: false
};

/**
Expand Down
87 changes: 61 additions & 26 deletions client/src/containers/BulkDeleteConfirmation/BulkDeleteMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,79 @@ import { descendantFileTotalsShape } from './helpers';
* @param {object} fileTotalItems
* @returns {string}
*/
const confirmationMessage = (folderCount, folderDescendantFileTotals, fileTotalItems) => {
const confirmationMessage = (
folderCount,
folderDescendantFileTotals,
fileTotalItems,
archiveFiles
) => {
const fileCount = folderDescendantFileTotals.totalCount + fileTotalItems;
if (fileCount > 0) {
let transKey = 'AssetAdmin.BULK_ACTIONS_DELETE_ITEMS_CONFIRM';
let transDefault = [
"You're about to delete %s file(s) which may be used in your site's content.",
'Carefully check the file usage on the files before deleting the folder.'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message is knowingly wrong where it says deleting the folder instead of deleting the file(s) - this is because this text is tested in a jest test that will be updated in #1379

].join(' ');
if (archiveFiles) {
transKey = 'AssetAdmin.BULK_ACTIONS_ARCHIVE_ITEMS_CONFIRM';
transDefault = [
"You're about to archive %s file(s) which may be used in your site's content.",
'Carefully check the file usage on the files before archiving the folder.'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message is knowingly wrong where it says archiving the folder instead of archiving the file(s) - this is because this text is tested in a jest test that will be updated in #1379

].join(' ');
}
return i18n.sprintf(
i18n._t(
'AssetAdmin.BULK_ACTIONS_DELETE_ITEMS_CONFIRM',
[
"You're about to delete %s file(s) which may be used in your site's content.",
'Carefully check the file usage on the files before deleting the folder.'
].join(' ')
),
i18n._t(transKey, transDefault),
fileCount
);
} else if (folderCount === 1) {
return i18n._t(
'AssetAdmin.BULK_ACTIONS_DELETE_FOLDER_CONFIRM',
'Are you sure you want to delete this folder?'
);
let transKey = 'AssetAdmin.BULK_ACTIONS_DELETE_FOLDER_CONFIRM';
let transDefault = 'Are you sure you want to delete this folder?';
if (archiveFiles) {
transKey = 'AssetAdmin.BULK_ACTIONS_ARCHIVE_FOLDER_CONFIRM';
transDefault = 'Are you sure you want to archive this folder?';
}
return i18n._t(transKey, transDefault);
}
return i18n._t(
'AssetAdmin.BULK_ACTIONS_DELETE_FOLDERS_CONFIRM',
'Are you sure you want to delete these folders?'
);
let transKey = 'AssetAdmin.BULK_ACTIONS_DELETE_FOLDERS_CONFIRM';
let transDefault = 'Are you sure you want to delete these folders?';
if (archiveFiles) {
transKey = 'AssetAdmin.BULK_ACTIONS_ARCHIVE_FOLDERS_CONFIRM';
transDefault = 'Are you sure you want to archive these folders?';
}
return i18n._t(transKey, transDefault);
};

/**
* Display a context dependent confirmation message.
*/
const BulkDeleteMessage = ({ folderCount, folderDescendantFileTotals, fileTotalItems }) => (
<Fragment>
<p>{confirmationMessage(folderCount, folderDescendantFileTotals, fileTotalItems)}</p>
{(folderDescendantFileTotals.totalItems > 0 || fileTotalItems > 0) &&
<p>{i18n._t(
'AssetAdmin.BULK_ACTIONS_DELETE_WARNING',
'Ensure files are removed from content areas prior to deleting them, otherwise they will appear as broken links.'
)}</p>}
</Fragment>
);
const BulkDeleteMessage = ({
folderCount,
folderDescendantFileTotals,
fileTotalItems,
archiveFiles
}) => {
let transKey = 'AssetAdmin.BULK_ACTIONS_DELETE_WARNING';
let transDefault = 'Ensure files are removed from content areas prior to deleting them, otherwise they will '
+ 'appear as broken links.';
if (archiveFiles) {
transKey = 'AssetAdmin.BULK_ACTIONS_ARCHIVE_WARNING';
transDefault = 'Ensure files are removed from content areas prior to archiving them, otherwise they will '
+ 'appear as broken links.';
}
const message = confirmationMessage(
folderCount,
folderDescendantFileTotals,
fileTotalItems,
archiveFiles
);
return (
<Fragment>
<p>{message}</p>
{(folderDescendantFileTotals.totalItems > 0 || fileTotalItems > 0) &&
<p>{i18n._t(transKey, transDefault)}</p>}
</Fragment>
);
};

BulkDeleteMessage.propTypes = {
folderCount: PropTypes.number,
Expand Down
39 changes: 26 additions & 13 deletions client/src/containers/BulkDeleteConfirmation/DeletionModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';

const DeletionModal = ({ isOpen, body, onCancel, actions }) => (
<Modal isOpen={isOpen} toggle={onCancel}>
<ModalHeader toggle={onCancel}>
{i18n._t('AssetAdmin.CONFIRM_FILE_DELETION', 'Confirm deletion')}
</ModalHeader>
<ModalBody>{body}</ModalBody>
<ModalFooter>
{actions.map(({ label, handler, color }) => (
<Button key={label} color={color} onClick={handler}>{label}</Button>
))}
</ModalFooter>
</Modal>
const DeletionModal = ({ isOpen, body, onCancel, actions, archiveFiles }) => {
let transKey = 'AssetAdmin.CONFIRM_FILE_DELETION';
let transDefault = 'Confirm deletion';
if (archiveFiles) {
transKey = 'AssetAdmin.CONFIRM_FILE_ARCHIVE';
transDefault = 'Confirm archive';
}
return (
<Modal isOpen={isOpen} toggle={onCancel}>
<ModalHeader toggle={onCancel}>
{i18n._t(transKey, transDefault)}
</ModalHeader>
<ModalBody>{body}</ModalBody>
<ModalFooter>
{actions.map(({ label, handler, color }) => (
<Button key={label} color={color} onClick={handler}>{label}</Button>
))}
</ModalFooter>
</Modal>
);
};

DeletionModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
Expand All @@ -25,7 +33,12 @@ DeletionModal.propTypes = {
label: PropTypes.string.isRequired,
handler: PropTypes.func,
color: PropTypes.string
}))
})),
archiveFiles: PropTypes.bool,
};

DeletionModal.defaultProps = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding default props for now for existing jest tests to pass, will be removed in #1379 and .isRequred will be added to the propType

archiveFiles: false
};

export default DeletionModal;
12 changes: 10 additions & 2 deletions client/src/containers/Gallery/Gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import PropTypes from 'prop-types';
*/
const ACTION_TYPES = {
DELETE: 'delete',
ARCHIVE: 'archive',
EDIT: 'edit',
MOVE: 'move',
PUBLISH: 'publish',
Expand Down Expand Up @@ -698,21 +699,28 @@ class Gallery extends Component {
* @returns {XML}
*/
renderBulkActions() {
const { type, dialog, maxFilesSelect, files, selectedFiles } = this.props;
const { type, dialog, maxFilesSelect, files, selectedFiles, sectionConfig } = this.props;

// When rendering gallery in modal or in select mode, filter all action but insert.
const actionFilter = (type === ACTION_TYPES.SELECT || dialog)
? action => action.value === ACTION_TYPES.INSERT
: action => action.value !== ACTION_TYPES.INSERT;

// Used to choose whether the text should be "Delete" or "Archive"
const deleteButtonFilter = (sectionConfig.archiveFiles)
? action => action.value !== ACTION_TYPES.DELETE
: action => action.value !== ACTION_TYPES.ARCHIVE;

const actions = CONSTANTS.BULK_ACTIONS
.filter(actionFilter)
.filter(deleteButtonFilter)
.map((action) => {
if (action.callback) {
return action;
}
switch (action.value) {
case ACTION_TYPES.DELETE: {
case ACTION_TYPES.DELETE:
case ACTION_TYPES.ARCHIVE: {
return {
...action,
callback: (event, items) => {
Expand Down
5 changes: 4 additions & 1 deletion code/Controller/AssetAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
use SilverStripe\Versioned\Versioned;
use SilverStripe\View\Requirements;
use SilverStripe\View\SSViewer;
use SilverStripe\VersionedAdmin\Extensions\FileArchiveExtension;

/**
* AssetAdmin is the 'file store' section of the CMS.
Expand Down Expand Up @@ -267,7 +268,9 @@ public function getClientConfig()
'acceptedFiles' => implode(',', array_map(function ($ext) {
return $ext[0] != '.' ? ".$ext" : $ext;
}, $validator->getAllowedExtensions() ?? []))
]
],
'archiveFiles' => class_exists(FileArchiveExtension::class)
&& File::singleton()->isArchiveFieldEnabled(),
]);
}

Expand Down
Loading