feat: add admin file health filters
This commit is contained in:
@@ -12,6 +12,7 @@ import type {
|
|||||||
AdminFileDetailViewItem,
|
AdminFileDetailViewItem,
|
||||||
AdminFileInsightSeverity,
|
AdminFileInsightSeverity,
|
||||||
AdminFilePatchPayload,
|
AdminFilePatchPayload,
|
||||||
|
AdminFileHealthFilter,
|
||||||
AdminFileListParams,
|
AdminFileListParams,
|
||||||
AdminFilePolicyAction,
|
AdminFilePolicyAction,
|
||||||
AdminFilePolicyActionRequest,
|
AdminFilePolicyActionRequest,
|
||||||
@@ -39,6 +40,12 @@ const emptySummary = (): AdminFileSummary => ({
|
|||||||
textCount: 0,
|
textCount: 0,
|
||||||
fileCount: 0,
|
fileCount: 0,
|
||||||
chunkedCount: 0,
|
chunkedCount: 0,
|
||||||
|
healthAttentionCount: 0,
|
||||||
|
healthDangerCount: 0,
|
||||||
|
healthWarningCount: 0,
|
||||||
|
expiringSoonCount: 0,
|
||||||
|
storageIssueCount: 0,
|
||||||
|
neverRetrievedCount: 0,
|
||||||
storageUsed: 0,
|
storageUsed: 0,
|
||||||
usedCount: 0
|
usedCount: 0
|
||||||
})
|
})
|
||||||
@@ -72,6 +79,12 @@ type DetailPolicyActionOption = {
|
|||||||
description: string
|
description: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HealthFilterOption = {
|
||||||
|
value: AdminFileHealthFilter
|
||||||
|
label: string
|
||||||
|
count?: number
|
||||||
|
}
|
||||||
|
|
||||||
const emptyBatchEditForm = (): AdminBatchEditForm => ({
|
const emptyBatchEditForm = (): AdminBatchEditForm => ({
|
||||||
mode: 'expiresAt',
|
mode: 'expiresAt',
|
||||||
expired_at: '',
|
expired_at: '',
|
||||||
@@ -106,6 +119,7 @@ export function useAdminFiles() {
|
|||||||
keyword: '',
|
keyword: '',
|
||||||
status: 'all',
|
status: 'all',
|
||||||
type: 'all',
|
type: 'all',
|
||||||
|
health: 'all',
|
||||||
sortBy: 'created_at',
|
sortBy: 'created_at',
|
||||||
sortOrder: 'desc'
|
sortOrder: 'desc'
|
||||||
})
|
})
|
||||||
@@ -157,6 +171,7 @@ export function useAdminFiles() {
|
|||||||
keyword: params.value.keyword,
|
keyword: params.value.keyword,
|
||||||
status: params.value.status === 'all' ? undefined : params.value.status,
|
status: params.value.status === 'all' ? undefined : params.value.status,
|
||||||
type: params.value.type === 'all' ? undefined : params.value.type,
|
type: params.value.type === 'all' ? undefined : params.value.type,
|
||||||
|
health: params.value.health === 'all' ? undefined : params.value.health,
|
||||||
sortBy: params.value.sortBy,
|
sortBy: params.value.sortBy,
|
||||||
sortOrder: params.value.sortOrder
|
sortOrder: params.value.sortOrder
|
||||||
}))
|
}))
|
||||||
@@ -165,9 +180,49 @@ export function useAdminFiles() {
|
|||||||
() =>
|
() =>
|
||||||
Boolean(params.value.keyword?.trim()) ||
|
Boolean(params.value.keyword?.trim()) ||
|
||||||
params.value.status !== 'all' ||
|
params.value.status !== 'all' ||
|
||||||
params.value.type !== 'all'
|
params.value.type !== 'all' ||
|
||||||
|
params.value.health !== 'all'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const healthFilterOptions = computed<HealthFilterOption[]>(() => [
|
||||||
|
{ value: 'all', label: t('fileManage.healthFilters.all'), count: summary.value.totalFiles },
|
||||||
|
{
|
||||||
|
value: 'attention',
|
||||||
|
label: t('fileManage.healthFilters.attention'),
|
||||||
|
count: summary.value.healthAttentionCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'danger',
|
||||||
|
label: t('fileManage.healthFilters.danger'),
|
||||||
|
count: summary.value.healthDangerCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'warning',
|
||||||
|
label: t('fileManage.healthFilters.warning'),
|
||||||
|
count: summary.value.healthWarningCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'expiring_soon',
|
||||||
|
label: t('fileManage.healthFilters.expiringSoon'),
|
||||||
|
count: summary.value.expiringSoonCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'storage_issue',
|
||||||
|
label: t('fileManage.healthFilters.storageIssue'),
|
||||||
|
count: summary.value.storageIssueCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'never_retrieved',
|
||||||
|
label: t('fileManage.healthFilters.neverRetrieved'),
|
||||||
|
count: summary.value.neverRetrievedCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'healthy',
|
||||||
|
label: t('fileManage.healthFilters.healthy'),
|
||||||
|
count: Math.max(summary.value.totalFiles - summary.value.healthAttentionCount, 0)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
const detailPolicyActionOptions = computed<DetailPolicyActionOption[]>(() => [
|
const detailPolicyActionOptions = computed<DetailPolicyActionOption[]>(() => [
|
||||||
{
|
{
|
||||||
action: 'extend_24h',
|
action: 'extend_24h',
|
||||||
@@ -237,6 +292,19 @@ export function useAdminFiles() {
|
|||||||
textCount: files.filter((file) => file.isTextFile).length,
|
textCount: files.filter((file) => file.isTextFile).length,
|
||||||
fileCount: files.filter((file) => !file.isTextFile).length,
|
fileCount: files.filter((file) => !file.isTextFile).length,
|
||||||
chunkedCount: files.filter((file) => file.isChunkedFile).length,
|
chunkedCount: files.filter((file) => file.isChunkedFile).length,
|
||||||
|
healthAttentionCount: files.filter((file) =>
|
||||||
|
['danger', 'warning'].includes(file.statusInsightSeverity)
|
||||||
|
).length,
|
||||||
|
healthDangerCount: files.filter((file) => file.statusInsightSeverity === 'danger').length,
|
||||||
|
healthWarningCount: files.filter((file) => file.statusInsightSeverity === 'warning').length,
|
||||||
|
expiringSoonCount: files.filter((file) => file.statusInsightReasons.includes('expires_soon'))
|
||||||
|
.length,
|
||||||
|
storageIssueCount: files.filter((file) =>
|
||||||
|
file.statusInsightReasons.includes('storage_metadata_incomplete')
|
||||||
|
).length,
|
||||||
|
neverRetrievedCount: files.filter((file) =>
|
||||||
|
file.statusInsightReasons.includes('never_retrieved')
|
||||||
|
).length,
|
||||||
storageUsed: files.reduce((totalSize, file) => totalSize + normalizeCount(file.size), 0),
|
storageUsed: files.reduce((totalSize, file) => totalSize + normalizeCount(file.size), 0),
|
||||||
usedCount: files.reduce(
|
usedCount: files.reduce(
|
||||||
(totalUsed, file) => totalUsed + normalizeCount(file.usedCount ?? file.used_count),
|
(totalUsed, file) => totalUsed + normalizeCount(file.usedCount ?? file.used_count),
|
||||||
@@ -244,29 +312,6 @@ export function useAdminFiles() {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const createFileViewItem = (file: FileListItem): AdminFileViewItem => {
|
|
||||||
const isTextFile = inferIsText(file)
|
|
||||||
const isExpiredFile = inferIsExpired(file)
|
|
||||||
const isChunkedFile = inferIsChunked(file)
|
|
||||||
const remainingDownloadsValue = getRemainingDownloads(file)
|
|
||||||
const usedCount = normalizeCount(file.usedCount ?? file.used_count)
|
|
||||||
|
|
||||||
return {
|
|
||||||
...file,
|
|
||||||
displayName: file.name || `${file.prefix}${file.suffix}` || file.code,
|
|
||||||
displaySize: formatFileSize(file.size),
|
|
||||||
displayExpiredAt: file.expired_at
|
|
||||||
? formatTimestamp(file.expired_at)
|
|
||||||
: t('send.expiration.units.forever'),
|
|
||||||
displayUsage: `${usedCount} ${t('common.times')}`,
|
|
||||||
isTextFile,
|
|
||||||
isExpiredFile,
|
|
||||||
isChunkedFile,
|
|
||||||
remainingDownloadsValue,
|
|
||||||
canPreviewText: isTextFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizeInsightSeverity = (
|
const normalizeInsightSeverity = (
|
||||||
severity: AdminFileInsightSeverity | undefined
|
severity: AdminFileInsightSeverity | undefined
|
||||||
): AdminFileInsightSeverity => {
|
): AdminFileInsightSeverity => {
|
||||||
@@ -279,6 +324,45 @@ export function useAdminFiles() {
|
|||||||
return 'neutral'
|
return 'neutral'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createFileViewItem = (file: FileListItem): AdminFileViewItem => {
|
||||||
|
const isTextFile = inferIsText(file)
|
||||||
|
const isExpiredFile = inferIsExpired(file)
|
||||||
|
const isChunkedFile = inferIsChunked(file)
|
||||||
|
const remainingDownloadsValue = getRemainingDownloads(file)
|
||||||
|
const usedCount = normalizeCount(file.usedCount ?? file.used_count)
|
||||||
|
const statusInsights = file.statusInsights ?? file.status_insights
|
||||||
|
const isPermanentFile =
|
||||||
|
!file.expired_at &&
|
||||||
|
(file.expired_count === null || file.expired_count === undefined || file.expired_count < 0)
|
||||||
|
const statusInsightState =
|
||||||
|
statusInsights?.state ??
|
||||||
|
(isExpiredFile ? 'expired' : isPermanentFile ? 'permanent' : 'available')
|
||||||
|
const statusInsightNextAction =
|
||||||
|
statusInsights?.nextAction ?? statusInsights?.next_action ?? 'monitor'
|
||||||
|
const statusInsightSeverity = normalizeInsightSeverity(statusInsights?.severity)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...file,
|
||||||
|
displayName: file.name || `${file.prefix}${file.suffix}` || file.code,
|
||||||
|
displaySize: formatFileSize(file.size),
|
||||||
|
displayExpiredAt: file.expired_at
|
||||||
|
? formatTimestamp(file.expired_at)
|
||||||
|
: t('send.expiration.units.forever'),
|
||||||
|
displayUsage: `${usedCount} ${t('common.times')}`,
|
||||||
|
displayHealthState: t(`fileManage.insightStates.${statusInsightState}`),
|
||||||
|
displayHealthAction: t(`fileManage.insightActions.${statusInsightNextAction}`),
|
||||||
|
isTextFile,
|
||||||
|
isExpiredFile,
|
||||||
|
isChunkedFile,
|
||||||
|
remainingDownloadsValue,
|
||||||
|
canPreviewText: isTextFile,
|
||||||
|
statusInsightSeverity,
|
||||||
|
statusInsightState,
|
||||||
|
statusInsightNextAction,
|
||||||
|
statusInsightReasons: statusInsights?.reasons || []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const formatTimelineValue = (item: AdminFileDetailTimelineItem) => {
|
const formatTimelineValue = (item: AdminFileDetailTimelineItem) => {
|
||||||
if (item.key === 'download_limit') {
|
if (item.key === 'download_limit') {
|
||||||
if (item.status === 'unlimited') return t('fileManage.unlimited')
|
if (item.status === 'unlimited') return t('fileManage.unlimited')
|
||||||
@@ -627,6 +711,7 @@ export function useAdminFiles() {
|
|||||||
params.value.keyword = ''
|
params.value.keyword = ''
|
||||||
params.value.status = 'all'
|
params.value.status = 'all'
|
||||||
params.value.type = 'all'
|
params.value.type = 'all'
|
||||||
|
params.value.health = 'all'
|
||||||
params.value.sortBy = 'created_at'
|
params.value.sortBy = 'created_at'
|
||||||
params.value.sortOrder = 'desc'
|
params.value.sortOrder = 'desc'
|
||||||
clearSelection()
|
clearSelection()
|
||||||
@@ -645,6 +730,12 @@ export function useAdminFiles() {
|
|||||||
await loadFiles()
|
await loadFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setHealthFilter = async (health: AdminFileHealthFilter) => {
|
||||||
|
params.value.health = health
|
||||||
|
params.value.page = 1
|
||||||
|
await loadFiles()
|
||||||
|
}
|
||||||
|
|
||||||
const handlePageChange = async (page: number | string) => {
|
const handlePageChange = async (page: number | string) => {
|
||||||
if (typeof page === 'string') return
|
if (typeof page === 'string') return
|
||||||
if (page < 1 || page > totalPages.value) return
|
if (page < 1 || page > totalPages.value) return
|
||||||
@@ -1010,6 +1101,7 @@ export function useAdminFiles() {
|
|||||||
batchEditForm,
|
batchEditForm,
|
||||||
detailPolicyActionOptions,
|
detailPolicyActionOptions,
|
||||||
downloadingFileId,
|
downloadingFileId,
|
||||||
|
healthFilterOptions,
|
||||||
hasSelectedFiles,
|
hasSelectedFiles,
|
||||||
params,
|
params,
|
||||||
previewFile,
|
previewFile,
|
||||||
@@ -1050,6 +1142,7 @@ export function useAdminFiles() {
|
|||||||
openTextPreview,
|
openTextPreview,
|
||||||
refreshFiles,
|
refreshFiles,
|
||||||
resetFilters,
|
resetFilters,
|
||||||
|
setHealthFilter,
|
||||||
setStatusFilter,
|
setStatusFilter,
|
||||||
setTypeFilter,
|
setTypeFilter,
|
||||||
toggleCurrentPageSelection,
|
toggleCurrentPageSelection,
|
||||||
|
|||||||
@@ -395,12 +395,23 @@ export default {
|
|||||||
storageUsed: 'Storage Used',
|
storageUsed: 'Storage Used',
|
||||||
statusLabel: 'Status',
|
statusLabel: 'Status',
|
||||||
typeLabel: 'Type',
|
typeLabel: 'Type',
|
||||||
|
healthLabel: 'Health',
|
||||||
all: 'All',
|
all: 'All',
|
||||||
active: 'Available',
|
active: 'Available',
|
||||||
expired: 'Expired',
|
expired: 'Expired',
|
||||||
fileType: 'File',
|
fileType: 'File',
|
||||||
textType: 'Text',
|
textType: 'Text',
|
||||||
chunkedType: 'Chunked',
|
chunkedType: 'Chunked',
|
||||||
|
healthFilters: {
|
||||||
|
all: 'All',
|
||||||
|
attention: 'Needs Attention',
|
||||||
|
danger: 'Issues',
|
||||||
|
warning: 'Warnings',
|
||||||
|
expiringSoon: 'Expiring Soon',
|
||||||
|
storageIssue: 'Storage Issues',
|
||||||
|
neverRetrieved: 'Never Retrieved',
|
||||||
|
healthy: 'Healthy'
|
||||||
|
},
|
||||||
sortBy: 'Sort',
|
sortBy: 'Sort',
|
||||||
unlimited: 'Unlimited',
|
unlimited: 'Unlimited',
|
||||||
remaining: '{count} left',
|
remaining: '{count} left',
|
||||||
|
|||||||
@@ -393,12 +393,23 @@ export default {
|
|||||||
storageUsed: '占用空间',
|
storageUsed: '占用空间',
|
||||||
statusLabel: '状态',
|
statusLabel: '状态',
|
||||||
typeLabel: '类型',
|
typeLabel: '类型',
|
||||||
|
healthLabel: '健康',
|
||||||
all: '全部',
|
all: '全部',
|
||||||
active: '可取件',
|
active: '可取件',
|
||||||
expired: '已过期',
|
expired: '已过期',
|
||||||
fileType: '文件',
|
fileType: '文件',
|
||||||
textType: '文本',
|
textType: '文本',
|
||||||
chunkedType: '分片',
|
chunkedType: '分片',
|
||||||
|
healthFilters: {
|
||||||
|
all: '全部',
|
||||||
|
attention: '需关注',
|
||||||
|
danger: '异常',
|
||||||
|
warning: '预警',
|
||||||
|
expiringSoon: '即将过期',
|
||||||
|
storageIssue: '存储异常',
|
||||||
|
neverRetrieved: '未取件',
|
||||||
|
healthy: '健康'
|
||||||
|
},
|
||||||
sortBy: '排序',
|
sortBy: '排序',
|
||||||
unlimited: '不限次数',
|
unlimited: '不限次数',
|
||||||
remaining: '剩余 {count} 次',
|
remaining: '剩余 {count} 次',
|
||||||
|
|||||||
+26
-4
@@ -28,6 +28,8 @@ export interface FileListItem {
|
|||||||
is_expired?: boolean
|
is_expired?: boolean
|
||||||
isChunked?: boolean
|
isChunked?: boolean
|
||||||
is_chunked?: boolean
|
is_chunked?: boolean
|
||||||
|
statusInsights?: AdminFileDetailStatusInsights
|
||||||
|
status_insights?: AdminFileDetailStatusInsights
|
||||||
remainingDownloads?: number | null
|
remainingDownloads?: number | null
|
||||||
remaining_downloads?: number | null
|
remaining_downloads?: number | null
|
||||||
usedCount?: number
|
usedCount?: number
|
||||||
@@ -41,11 +43,17 @@ export interface AdminFileViewItem extends FileListItem {
|
|||||||
displaySize: string
|
displaySize: string
|
||||||
displayExpiredAt: string
|
displayExpiredAt: string
|
||||||
displayUsage: string
|
displayUsage: string
|
||||||
|
displayHealthState: string
|
||||||
|
displayHealthAction: string
|
||||||
isTextFile: boolean
|
isTextFile: boolean
|
||||||
isExpiredFile: boolean
|
isExpiredFile: boolean
|
||||||
isChunkedFile: boolean
|
isChunkedFile: boolean
|
||||||
remainingDownloadsValue: number | null
|
remainingDownloadsValue: number | null
|
||||||
canPreviewText: boolean
|
canPreviewText: boolean
|
||||||
|
statusInsightSeverity: AdminFileInsightSeverity
|
||||||
|
statusInsightState: string
|
||||||
|
statusInsightNextAction: string
|
||||||
|
statusInsightReasons: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminFileSummary {
|
export interface AdminFileSummary {
|
||||||
@@ -55,12 +63,29 @@ export interface AdminFileSummary {
|
|||||||
textCount: number
|
textCount: number
|
||||||
fileCount: number
|
fileCount: number
|
||||||
chunkedCount: number
|
chunkedCount: number
|
||||||
|
healthAttentionCount: number
|
||||||
|
healthDangerCount: number
|
||||||
|
healthWarningCount: number
|
||||||
|
expiringSoonCount: number
|
||||||
|
storageIssueCount: number
|
||||||
|
neverRetrievedCount: number
|
||||||
storageUsed: number
|
storageUsed: number
|
||||||
usedCount: number
|
usedCount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AdminFileStatusFilter = 'all' | 'active' | 'expired'
|
export type AdminFileStatusFilter = 'all' | 'active' | 'expired'
|
||||||
export type AdminFileTypeFilter = 'all' | 'file' | 'text' | 'chunked'
|
export type AdminFileTypeFilter = 'all' | 'file' | 'text' | 'chunked'
|
||||||
|
export type AdminFileHealthFilter =
|
||||||
|
| 'all'
|
||||||
|
| 'attention'
|
||||||
|
| 'danger'
|
||||||
|
| 'warning'
|
||||||
|
| 'healthy'
|
||||||
|
| 'expired'
|
||||||
|
| 'expiring_soon'
|
||||||
|
| 'storage_issue'
|
||||||
|
| 'never_retrieved'
|
||||||
|
| 'permanent'
|
||||||
export type AdminFileSortBy = 'created_at' | 'expired_at' | 'name' | 'size' | 'used_count' | 'code'
|
export type AdminFileSortBy = 'created_at' | 'expired_at' | 'name' | 'size' | 'used_count' | 'code'
|
||||||
export type AdminFileSortOrder = 'asc' | 'desc'
|
export type AdminFileSortOrder = 'asc' | 'desc'
|
||||||
|
|
||||||
@@ -70,6 +95,7 @@ export interface AdminFileListParams {
|
|||||||
keyword?: string
|
keyword?: string
|
||||||
status?: AdminFileStatusFilter
|
status?: AdminFileStatusFilter
|
||||||
type?: AdminFileTypeFilter
|
type?: AdminFileTypeFilter
|
||||||
|
health?: AdminFileHealthFilter
|
||||||
sortBy?: AdminFileSortBy
|
sortBy?: AdminFileSortBy
|
||||||
sortOrder?: AdminFileSortOrder
|
sortOrder?: AdminFileSortOrder
|
||||||
}
|
}
|
||||||
@@ -241,10 +267,6 @@ export interface AdminFileDetailViewItem extends AdminFileViewItem {
|
|||||||
filePathValue?: string | null
|
filePathValue?: string | null
|
||||||
uuidFileNameValue?: string | null
|
uuidFileNameValue?: string | null
|
||||||
uploadIdValue?: string | null
|
uploadIdValue?: string | null
|
||||||
statusInsightSeverity: AdminFileInsightSeverity
|
|
||||||
statusInsightState: string
|
|
||||||
statusInsightNextAction: string
|
|
||||||
statusInsightReasons: string[]
|
|
||||||
statusInsightMetrics?: AdminFileDetailInsightMetrics
|
statusInsightMetrics?: AdminFileDetailInsightMetrics
|
||||||
detailTimeline: AdminFileDetailTimelineViewItem[]
|
detailTimeline: AdminFileDetailTimelineViewItem[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,24 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
|
<span class="inline-flex items-center text-xs font-medium" :class="[mutedTextClass]">
|
||||||
|
<ActivityIcon class="mr-1 h-3.5 w-3.5" />
|
||||||
|
{{ t('fileManage.healthLabel') }}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
v-for="option in healthFilterOptions"
|
||||||
|
:key="option.value"
|
||||||
|
type="button"
|
||||||
|
class="rounded-lg px-3 py-1.5 text-xs font-medium transition-colors"
|
||||||
|
:class="getHealthFilterClass(option.value)"
|
||||||
|
@click="setHealthFilter(option.value)"
|
||||||
|
>
|
||||||
|
<span>{{ option.label }}</span>
|
||||||
|
<span v-if="typeof option.count === 'number'">({{ option.count }})</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span class="inline-flex items-center text-xs font-medium" :class="[mutedTextClass]">
|
<span class="inline-flex items-center text-xs font-medium" :class="[mutedTextClass]">
|
||||||
<ArchiveIcon class="mr-1 h-3.5 w-3.5" />
|
<ArchiveIcon class="mr-1 h-3.5 w-3.5" />
|
||||||
@@ -297,6 +315,22 @@
|
|||||||
<p class="mt-0.5 truncate text-xs" :class="[mutedTextClass]">
|
<p class="mt-0.5 truncate text-xs" :class="[mutedTextClass]">
|
||||||
{{ file.suffix || t('fileManage.textType') }}
|
{{ file.suffix || t('fileManage.textType') }}
|
||||||
</p>
|
</p>
|
||||||
|
<div class="mt-2 flex max-w-sm flex-wrap items-center gap-1.5">
|
||||||
|
<span
|
||||||
|
class="inline-flex max-w-full items-center rounded-full px-2 py-0.5 text-xs font-medium"
|
||||||
|
:class="getInsightBadgeClass(file.statusInsightSeverity)"
|
||||||
|
:title="file.displayHealthAction"
|
||||||
|
>
|
||||||
|
{{ file.displayHealthState }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="max-w-[16rem] truncate text-xs"
|
||||||
|
:class="[mutedTextClass]"
|
||||||
|
:title="file.displayHealthAction"
|
||||||
|
>
|
||||||
|
{{ file.displayHealthAction }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -997,6 +1031,7 @@ import { computed, onMounted, type Component } from 'vue'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import type {
|
import type {
|
||||||
AdminBatchEditMode,
|
AdminBatchEditMode,
|
||||||
|
AdminFileHealthFilter,
|
||||||
AdminFileInsightSeverity,
|
AdminFileInsightSeverity,
|
||||||
AdminFilePolicyAction,
|
AdminFilePolicyAction,
|
||||||
AdminFileSortBy,
|
AdminFileSortBy,
|
||||||
@@ -1064,6 +1099,7 @@ const {
|
|||||||
batchEditForm,
|
batchEditForm,
|
||||||
detailPolicyActionOptions,
|
detailPolicyActionOptions,
|
||||||
downloadingFileId,
|
downloadingFileId,
|
||||||
|
healthFilterOptions,
|
||||||
hasSelectedFiles,
|
hasSelectedFiles,
|
||||||
params,
|
params,
|
||||||
previewFile,
|
previewFile,
|
||||||
@@ -1103,6 +1139,7 @@ const {
|
|||||||
openTextPreview,
|
openTextPreview,
|
||||||
refreshFiles,
|
refreshFiles,
|
||||||
resetFilters,
|
resetFilters,
|
||||||
|
setHealthFilter,
|
||||||
setStatusFilter,
|
setStatusFilter,
|
||||||
setTypeFilter,
|
setTypeFilter,
|
||||||
toggleCurrentPageSelection,
|
toggleCurrentPageSelection,
|
||||||
@@ -1353,6 +1390,9 @@ const getStatusFilterClass = (value: AdminFileStatusFilter) =>
|
|||||||
|
|
||||||
const getTypeFilterClass = (value: AdminFileTypeFilter) => getPillClass(params.value.type === value)
|
const getTypeFilterClass = (value: AdminFileTypeFilter) => getPillClass(params.value.type === value)
|
||||||
|
|
||||||
|
const getHealthFilterClass = (value: AdminFileHealthFilter) =>
|
||||||
|
getPillClass(params.value.health === value)
|
||||||
|
|
||||||
const getBatchEditModeClass = (value: AdminBatchEditMode) => {
|
const getBatchEditModeClass = (value: AdminBatchEditMode) => {
|
||||||
if (batchEditForm.value.mode === value) {
|
if (batchEditForm.value.mode === value) {
|
||||||
return isDarkMode.value
|
return isDarkMode.value
|
||||||
|
|||||||
Reference in New Issue
Block a user