diff --git a/src/components/common/DataTable.vue b/src/components/common/DataTable.vue index 04b8831..806d4ff 100644 --- a/src/components/common/DataTable.vue +++ b/src/components/common/DataTable.vue @@ -2,10 +2,16 @@
-
+

{{ title }}

+
+ +
- @@ -34,7 +43,7 @@ diff --git a/src/composables/useAdminFiles.ts b/src/composables/useAdminFiles.ts index d0dd6d7..5719e13 100644 --- a/src/composables/useAdminFiles.ts +++ b/src/composables/useAdminFiles.ts @@ -79,6 +79,7 @@ const isLegacyEndpointUnavailable = (error: unknown) => { const legacyForeverExpiresAt = '2099-12-31T23:59' const detailPolicyDownloadLimit = 5 +const hourInMilliseconds = 60 * 60 * 1000 const dayInMilliseconds = 24 * 60 * 60 * 1000 type DetailPolicyActionOption = { @@ -99,7 +100,9 @@ type HealthFilterOption = { const emptyBatchEditForm = (): AdminBatchEditForm => ({ mode: 'expiresAt', expired_at: '', - expired_count: null + expired_count: null, + relative_expire_value: null, + relative_expire_unit: 'hours' }) const metadataTagSeparatorPattern = /[,,\n]+/ @@ -269,6 +272,12 @@ export function useAdminFiles() { ) const selectedCount = computed(() => selectedFileIds.value.size) const hasSelectedFiles = computed(() => selectedCount.value > 0) + const selectedFilesOnCurrentPage = computed(() => + tableData.value.filter((file) => selectedFileIds.value.has(file.id)) + ) + const selectedHasPermanentFiles = computed(() => + selectedFilesOnCurrentPage.value.some((file) => file.isPermanentFile) + ) const isAllCurrentPageSelected = computed( () => tableData.value.length > 0 && currentPageSelectedCount.value === tableData.value.length ) @@ -429,7 +438,7 @@ export function useAdminFiles() { ) const batchPolicyActionOptions = computed( - () => createPolicyActionOptions(false) + () => createPolicyActionOptions(selectedHasPermanentFiles.value) ) const inferIsText = (file: FileListItem) => { @@ -571,6 +580,7 @@ export function useAdminFiles() { displayHealthAction: t(`fileManage.insightActions.${statusInsightNextAction}`), isTextFile, isExpiredFile, + isPermanentFile, isChunkedFile, remainingDownloadsValue, canPreviewText: isTextFile, @@ -823,6 +833,23 @@ export function useAdminFiles() { } } + if (form.mode === 'relativeExpire') { + if ( + form.relative_expire_value === null || + !Number.isFinite(form.relative_expire_value) || + form.relative_expire_value <= 0 + ) { + return null + } + const duration = + form.relative_expire_value * + (form.relative_expire_unit === 'days' ? dayInMilliseconds : hourInMilliseconds) + return { + ids, + expired_at: formatLocalDateTime(new Date(Date.now() + duration)) + } + } + return { ids, clearExpiredAt: true, @@ -1425,10 +1452,11 @@ export function useAdminFiles() { const applySelectedPolicyAction = async (action: AdminFilePolicyAction) => { if (!hasSelectedFiles.value || isBatchActionRunning.value) return + const selectedAction = batchPolicyActionOptions.value.find((option) => option.action === action) + if (selectedAction?.disabled) return const ids = Array.from(selectedFileIds.value) - const actionLabel = - batchPolicyActionOptions.value.find((option) => option.action === action)?.label || action + const actionLabel = selectedAction?.label || action if ( !window.confirm( t('fileManage.batchPolicyActionConfirm', { @@ -1690,6 +1718,7 @@ export function useAdminFiles() { selectedFileDetail, selectedCount, selectedFileIds, + selectedHasPermanentFiles, selectedViewPresetId, storageUsedText, summary, diff --git a/src/i18n/locales/en-US.ts b/src/i18n/locales/en-US.ts index 643f462..67859b6 100644 --- a/src/i18n/locales/en-US.ts +++ b/src/i18n/locales/en-US.ts @@ -485,6 +485,12 @@ export default { batchEditSelected: 'Update the selected {count} files', batchEditMode: 'Update Mode', batchEditExpiresAt: 'Set Expiration Time', + batchEditRelativeExpire: 'Expire After Duration', + batchEditRelativeExpireValue: 'Expiration Duration', + batchEditRelativeExpirePlaceholder: 'Enter amount', + batchEditRelativeExpireUnit: 'Unit', + batchEditRelativeExpireHours: 'Hours', + batchEditRelativeExpireDays: 'Days', batchEditDownloadLimit: 'Set Retrieval Limit', batchEditForever: 'Make Permanent', batchEditForeverHint: 'Clear the expiration time and make retrievals unlimited.', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 17a4a90..0b46a10 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -483,6 +483,12 @@ export default { batchEditSelected: '将更新选中的 {count} 个文件', batchEditMode: '更新方式', batchEditExpiresAt: '设置过期时间', + batchEditRelativeExpire: '设为一段时间后消失', + batchEditRelativeExpireValue: '消失时间', + batchEditRelativeExpirePlaceholder: '输入数量', + batchEditRelativeExpireUnit: '单位', + batchEditRelativeExpireHours: '小时', + batchEditRelativeExpireDays: '天', batchEditDownloadLimit: '设置取件次数', batchEditForever: '设为永久有效', batchEditForeverHint: '清空过期时间,并将取件次数设为不限。', diff --git a/src/types/file.ts b/src/types/file.ts index 50fc5a4..ddc4fd5 100644 --- a/src/types/file.ts +++ b/src/types/file.ts @@ -47,6 +47,7 @@ export interface AdminFileViewItem extends FileListItem { displayHealthAction: string isTextFile: boolean isExpiredFile: boolean + isPermanentFile: boolean isChunkedFile: boolean remainingDownloadsValue: number | null canPreviewText: boolean @@ -393,12 +394,16 @@ export interface AdminBatchPolicyActionResponse extends AdminBatchUpdateFilesRes action?: AdminFilePolicyAction | string } -export type AdminBatchEditMode = 'expiresAt' | 'downloadLimit' | 'forever' +export type AdminBatchExpireUnit = 'hours' | 'days' + +export type AdminBatchEditMode = 'expiresAt' | 'relativeExpire' | 'downloadLimit' | 'forever' export interface AdminBatchEditForm { mode: AdminBatchEditMode expired_at: string expired_count: number | null + relative_expire_value: number | null + relative_expire_unit: AdminBatchExpireUnit } export interface FileUploadResponse { diff --git a/src/views/manage/FileManageView.vue b/src/views/manage/FileManageView.vue index 2c2a8bf..e15dd31 100644 --- a/src/views/manage/FileManageView.vue +++ b/src/views/manage/FileManageView.vue @@ -261,85 +261,86 @@ -
- - -
- - - {{ t('fileManage.clearSelection') }} - - - - {{ option.label }} - - - - {{ t('fileManage.batchEdit') }} - - - - {{ t('fileManage.batchDelete') }} - -
-
- + +
+ :class="[isDarkMode ? 'text-gray-400' : 'text-gray-500']" + > {{ header }}