import { defineAsyncComponent, h } from 'vue'; import { toast } from 'vue-sonner'; import { getTeam } from '../../data/team'; import router from '../../router'; import { confirmDialog, icon, renderDialog } from '../../utils/components'; import { planTitle } from '../../utils/format'; import type { ColumnField, DialogConfig, FilterField, Tab, TabList } from './types'; import { getUpsellBanner } from '.'; import { isMobile } from '../../utils/device'; import { getToastErrorMessage } from '../../utils/toast'; export function getAppsTab(forSite: boolean) { return { label: '应用', icon: icon('grid'), route: 'apps', type: 'list', condition: docResource => forSite && docResource.pg?.status !== 'Archived', list: getAppsTabList(forSite) } satisfies Tab as Tab; } function getAppsTabList(forSite: boolean) { const options = forSite ? siteAppListOptions : benchAppListOptions; const list: TabList = { pagetype: '', filters: () => ({}), ...options, columns: getAppsTabColumns(forSite), searchField: !forSite ? 'title' : undefined, filterControls: r => { if (forSite) return []; else return [ { type: 'select', label: '分支', class: !isMobile() ? 'w-24' : '', fieldname: 'branch', options: [ '', ...new Set(r.listResource.data?.map(i => String(i.branch)) || []) ] }, { type: 'select', label: '所有者', class: !isMobile() ? 'w-24' : '', fieldname: 'repository_owner', options: [ '', ...new Set( r.listResource.data?.map( i => String(i.repository_url).split('/').at(-2) || '' ) || [] ) ] } ] satisfies FilterField[]; } }; return list; } function getAppsTabColumns(forSite: boolean) { const appTabColumns: ColumnField[] = [ { label: '应用', fieldname: 'title', width: 1, suffix(row) { if (!row.is_app_patched) { return; } return h( 'div', { title: '应用已打补丁', class: 'rounded-full bg-gray-100 p-1' }, h(icon('hash', 'w-3 h-3')) ); }, format: (value, row) => value || row.app_title }, { label: '计划', width: 0.75, class: 'text-gray-600 text-sm', format(_, row) { const planText = planTitle(row.plan_info); if (planText) return `${planText}/月`; else return '免费'; } }, { label: '仓库', fieldname: 'repository_url', format: value => String(value).split('/').slice(-2).join('/'), link: value => String(value) }, { label: '分支', fieldname: 'branch', type: 'Badge', width: 1, link: (value, row) => { return `${row.repository_url}/tree/${value}`; } }, { label: '提交', fieldname: 'hash', type: 'Badge', width: 1, link: (value, row) => { return `${row.repository_url}/commit/${value}`; }, format(value) { return String(value).slice(0, 7); } }, { label: '提交信息', fieldname: 'commit_message', width: '30rem' } ]; if (forSite) return appTabColumns; return appTabColumns.filter(c => c.label !== '计划'); } const siteAppListOptions: Partial = { pagetype: '站点应用', filters: res => { return { parenttype: 'Site', parent: res.pg?.name }; }, primaryAction({ listResource: apps, documentResource: site }) { return { label: '安装应用', slots: { prefix: icon('plus') }, onClick() { const InstallAppDialog = defineAsyncComponent( () => import('../../components/site/InstallAppDialog.vue') ); renderDialog( h(InstallAppDialog, { site: site.name, onInstalled() { apps.reload(); } }) ); } }; }, rowActions({ row, listResource: apps, documentResource: site }) { let $team = getTeam(); return [ { label: '在 Desk 中查看', condition: () => $team.pg?.is_desk_user, onClick() { window.open(`/app/app-source/${row.name}`, '_blank'); } }, { label: '更改计划', condition: () => row.plan_info && row.plans.length > 1, onClick() { let SiteAppPlanChangeDialog = defineAsyncComponent( () => import('../../components/site/SiteAppPlanSelectDialog.vue') ); renderDialog( h(SiteAppPlanChangeDialog, { app: row, currentPlan: row.plans.find( (plan: Record) => plan.name === row.plan_info.name ), onPlanChanged() { apps.reload(); } }) ); } }, { label: '卸载', condition: () => row.app !== 'jingrow', onClick() { const dialogConfig: DialogConfig = { title: `卸载应用`, message: `您确定要从站点 ${site.pg?.name} 卸载应用 ${row.title} 吗?
所有与此应用相关的文档类型和模块将被移除。`, onSuccess({ hide }) { if (site.uninstallApp.loading) return; toast.promise( site.uninstallApp.submit({ app: row.app }), { loading: '正在安排应用卸载...', success: (jobId: string) => { hide(); router.push({ name: 'Site Job', params: { name: site.name, id: jobId } }); return '应用卸载已安排'; }, error: (e: Error) => getToastErrorMessage(e) } ); } }; confirmDialog(dialogConfig); } } ]; } }; const benchAppListOptions: Partial = { pagetype: 'Bench App', filters: res => { return { parenttype: 'Bench', parent: res.pg?.name }; }, rowActions({ row }) { let $team = getTeam(); return [ { label: '在 Desk 中查看', condition: () => $team.pg?.is_desk_user, onClick() { window.open(`/app/app-release/${row.release}`, '_blank'); } } ]; } };