import { toast } from 'vue-sonner'; import { getTeam } from '../../data/team'; import { confirmDialog, icon, renderDialog } from '../../utils/components'; import { h } from 'vue'; import PatchAppDialog from '../../components/group/PatchAppDialog.vue'; import { ColumnField, FilterField, Tab } from './types'; import { isMobile } from '../../utils/device'; const statusTheme = { Applied: 'green', 'Not Applied': 'gray', 'In Process': 'orange', Failure: 'red' }; type Status = keyof typeof statusTheme; export function getPatchesTab(forBench: boolean) { return { label: '补丁', icon: icon('hash'), route: 'patches', type: 'list', list: { experimental: true, // If removing this, uncheck App Patch pagetype beta flag. documentation: 'https://jingrow.com/docs/benches/app-patches', pagetype: 'App Patch', filters: res => ({ [forBench ? 'bench' : 'group']: res.name }), searchField: 'filename', filterControls: r => [ { type: 'select', label: '状态', fieldname: 'status', options: ['', 'Not Applied', 'In Process', 'Failed', 'Applied'] }, { type: 'select', label: '应用', fieldname: 'app', class: !isMobile() ? 'w-24' : '', options: [ '', ...new Set(r.listResource.data?.map(i => String(i.app)) || []) ] } ] satisfies FilterField[], columns: getPatchesTabColumns(forBench), primaryAction({ listResource: apps, documentResource: pg }) { return { label: '应用补丁', slots: { prefix: icon('plus') }, onClick() { const group = pg.pagetype === 'Bench' ? pg.pg.group : pg.name; renderDialog(h(PatchAppDialog, { group: group, app: '' })); } }; }, rowActions({ row, listResource }) { let team = getTeam(); return [ { label: '在桌面查看', condition: () => team.pg?.is_desk_user, onClick() { window.open( `${window.location.protocol}//${window.location.host}/app/app-patch/${row.name}`, '_blank' ); } }, { label: '应用补丁', condition: () => row.status !== 'In Process', onClick: () => { toast.promise( listResource.runDocMethod.submit({ method: 'apply_patch', name: String(row.name) }), { loading: '正在创建应用补丁的任务', success: () => '补丁应用正在进行中', error: () => '应用补丁失败' } ); } }, { label: '回滚补丁', condition: () => row.status !== 'In Process', onClick: () => { toast.promise( listResource.runDocMethod.submit({ method: 'revert_patch', name: String(row.name) }), { loading: '正在创建回滚补丁的任务', success: () => '补丁回滚正在进行中', error: () => '回滚补丁失败' } ); } }, { label: '删除', condition: () => row.status === 'Not Applied', onClick: () => { confirmDialog({ title: '删除补丁', message: '确定要删除此补丁吗?', onSuccess: ({ hide }) => { toast.promise( listResource.delete.submit(row.name, { onSuccess: () => hide() }), { loading: '正在删除...', success: () => '补丁已删除', error: () => '删除补丁失败' } ); } }); } } ]; } } } satisfies Tab; } function getPatchesTabColumns(forBench: boolean) { const columns: ColumnField[] = [ { label: '文件名', fieldname: 'filename', width: forBench ? '400px' : '300px' }, { label: '应用', fieldname: 'app', width: 0.4 }, { label: '状态', type: 'Badge', fieldname: 'status', theme: value => statusTheme[value as Status], width: 0.4 }, { label: '工作台', fieldname: 'bench', width: 0.8 }, { label: '补丁链接', fieldname: 'url', width: forBench ? undefined : '300px', format(value) { if (!value) { return '-'; } const url = new URL(value); return url.hostname + url.pathname; }, link: value => String(value) } ]; if (forBench) return columns.filter(f => f.fieldname !== 'bench'); return columns; }