Skip to content

Commit

Permalink
Merge pull request #1378 from creative-commoners/pulls/1.13/archive-text
Browse files Browse the repository at this point in the history
ENH Use archive text when file archiving is enabled
  • Loading branch information
GuySartorelli committed Aug 8, 2023
2 parents cda12f6 + fa0fef2 commit 3e5afba
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 59 deletions.
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
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.",
"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.",
"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
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
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.'
),
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.'),
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
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 = {
archiveFiles: false
};

/**
Expand Down
87 changes: 61 additions & 26 deletions client/src/containers/BulkDeleteConfirmation/BulkDeleteMessage.js
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.'
].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.'
].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
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 = {
archiveFiles: false
};

export default DeletionModal;
12 changes: 10 additions & 2 deletions client/src/containers/Gallery/Gallery.js
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
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

0 comments on commit 3e5afba

Please sign in to comment.