feat: media duplicate purge, part 3 of 3: the SPA (Settings "Media cleanup" card, PurgeDuplicatesDialog, Media Duplicates toolbar button)
This commit is contained in:
1 parent
1a55a39425
commit
2303b12377
26 files changed
+3856
-83
No files matched your search
@@ -0,0 +1,107 @@
|
||||
import { t } from '@/i18n'
|
||||
import { ApiError } from '@/composables/useApi'
|
||||
import type { PurgeSettings } from '@/composables/useMediaPurge'
|
||||
import { formatMediaDate, pluralArticles } from '@/lib/mediaFormat'
|
||||
|
||||
export const MIN_INTERVAL_DAYS = 1
|
||||
export const MAX_INTERVAL_DAYS = 365
|
||||
export const DEFAULT_INTERVAL_DAYS = 30
|
||||
export const PURGE_TOAST_DURATION_MS = 5000
|
||||
export const REVIEW_DUPLICATES_PATH = '/media?filter=duplicates'
|
||||
export const PURGE_STALE_COPY =
|
||||
'The library changed, so nothing was purged. Check the new summary and try again.'
|
||||
export const PURGE_BUSY_COPY = 'A purge is already running.'
|
||||
|
||||
const HTTP_UNAUTHORIZED = 401
|
||||
const HTTP_FORBIDDEN = 403
|
||||
const WHOLE_NUMBER = /^\d+$/
|
||||
const SVG_EXTENSION = /\.svg$/i
|
||||
const PNG_EXTENSION = /\.png$/i
|
||||
|
||||
export function isForbidden(error: unknown) {
|
||||
return error instanceof ApiError && error.status === HTTP_FORBIDDEN
|
||||
}
|
||||
|
||||
export function isHandledGlobally(error: unknown) {
|
||||
return error instanceof ApiError && (error.status === HTTP_UNAUTHORIZED || isForbidden(error))
|
||||
}
|
||||
|
||||
export function parseIntervalDays(text: string) {
|
||||
const trimmed = text.trim()
|
||||
if (!WHOLE_NUMBER.test(trimmed)) {
|
||||
return null
|
||||
}
|
||||
const days = Number.parseInt(trimmed, 10)
|
||||
return days >= MIN_INTERVAL_DAYS && days <= MAX_INTERVAL_DAYS ? days : null
|
||||
}
|
||||
|
||||
export function pluralCopies(count: number) {
|
||||
return t(count === 1 ? '1 copy' : '{0} copies', [count])
|
||||
}
|
||||
|
||||
export function pluralGroups(count: number) {
|
||||
return t(count === 1 ? '1 group' : '{0} groups', [count])
|
||||
}
|
||||
|
||||
export function mergedCopies(count: number) {
|
||||
return t('{0} merged', [pluralCopies(count)])
|
||||
}
|
||||
|
||||
export function lastPurgeLine(settings: PurgeSettings | null) {
|
||||
if (!settings?.last_purge_at) {
|
||||
return t('Never run')
|
||||
}
|
||||
return t('Last purge: {0} · {1} merged · {2} updated', [
|
||||
formatMediaDate(settings.last_purge_at),
|
||||
pluralCopies(settings.last_purge_merged ?? 0),
|
||||
pluralArticles(settings.last_purge_articles_updated ?? 0),
|
||||
])
|
||||
}
|
||||
|
||||
export function nextPurgeLine(iso: string) {
|
||||
return t('Next purge: {0}', [formatMediaDate(iso)])
|
||||
}
|
||||
|
||||
export function previewSummary(counts: { groups: number; copies: number; articles: number }) {
|
||||
return t('{0} · {1} will be deleted · {2} will be updated', [
|
||||
pluralGroups(counts.groups),
|
||||
pluralCopies(counts.copies),
|
||||
pluralArticles(counts.articles),
|
||||
])
|
||||
}
|
||||
|
||||
export function keptLine(usedIn: number) {
|
||||
return t('Kept · used in {0}', [pluralArticles(usedIn)])
|
||||
}
|
||||
|
||||
export function moreGroupsLine(more: number) {
|
||||
return t(more === 1 ? 'and 1 more group' : 'and {0} more groups', [more])
|
||||
}
|
||||
|
||||
export function thumbnailSource(url: string, filename: string) {
|
||||
let contentType = ''
|
||||
if (SVG_EXTENSION.test(filename)) {
|
||||
contentType = 'image/svg+xml'
|
||||
} else if (PNG_EXTENSION.test(filename)) {
|
||||
contentType = 'image/png'
|
||||
}
|
||||
return { url, content_type: contentType, sha256: '' }
|
||||
}
|
||||
|
||||
export function purgedToast(result: { merged: number; articles_updated: number }) {
|
||||
return {
|
||||
id: 'media-purged',
|
||||
color: 'success' as const,
|
||||
icon: 'i-lucide-circle-check',
|
||||
get title() {
|
||||
return t('Duplicates purged')
|
||||
},
|
||||
get description() {
|
||||
return t('{0} merged. {1} updated.', [
|
||||
pluralCopies(result.merged),
|
||||
pluralArticles(result.articles_updated),
|
||||
])
|
||||
},
|
||||
duration: PURGE_TOAST_DURATION_MS,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user