From 63e0ba48e601b89e923c06a7043cd2b6ed08ee32 Mon Sep 17 00:00:00 2001 From: jingrow Date: Tue, 22 Apr 2025 01:47:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AE=A1=E5=88=92=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=A0=BC=E5=BC=8F=EF=BC=8C=E4=BF=AE=E5=A4=8D=E7=AB=99?= =?UTF-8?q?=E7=82=B9=E5=BA=94=E7=94=A8=E5=88=97=E8=A1=A8=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard/src2/components/DateTimeControl.vue | 2 +- .../src2/components/SiteUpdateDialog.vue | 2 +- dashboard/src2/data/session.js | 110 -------- dashboard/src2/objects/common/apps.ts | 256 ------------------ dashboard/src2/objects/site.js | 1 + 5 files changed, 3 insertions(+), 368 deletions(-) delete mode 100644 dashboard/src2/data/session.js delete mode 100644 dashboard/src2/objects/common/apps.ts diff --git a/dashboard/src2/components/DateTimeControl.vue b/dashboard/src2/components/DateTimeControl.vue index f2463cd..8831d55 100644 --- a/dashboard/src2/components/DateTimeControl.vue +++ b/dashboard/src2/components/DateTimeControl.vue @@ -82,7 +82,7 @@ export default { let days = []; for (let i = 0; i < 7; i++) { days.push({ - label: dayjs().add(i, 'day').format('dddd, MMMM D'), + label: dayjs().add(i, 'day').format('YYYY-MM-DD'), value: dayjs().add(i, 'day').format('YYYY-MM-DD') }); } diff --git a/dashboard/src2/components/SiteUpdateDialog.vue b/dashboard/src2/components/SiteUpdateDialog.vue index 48e1f0a..feb9b94 100644 --- a/dashboard/src2/components/SiteUpdateDialog.vue +++ b/dashboard/src2/components/SiteUpdateDialog.vue @@ -100,7 +100,7 @@ export default { return dayjsIST(this.scheduledTime).format('YYYY-MM-DDTHH:mm'); }, scheduledTimeInLocal() { - return dayjs(this.scheduledTime).format('lll'); + return dayjs(this.scheduledTime).format('YYYY-MM-DD HH:mm'); }, listOptions() { return { diff --git a/dashboard/src2/data/session.js b/dashboard/src2/data/session.js deleted file mode 100644 index 1a49ab1..0000000 --- a/dashboard/src2/data/session.js +++ /dev/null @@ -1,110 +0,0 @@ -import { computed, reactive } from 'vue'; -import { createResource } from 'jingrow-ui'; -import { clear } from 'idb-keyval'; -import router from '../router'; - -export let session = reactive({ - login: createResource({ - url: 'login', - makeParams({ email, password }) { - return { - usr: email, - pwd: password - }; - } - }), - logout: createResource({ - url: 'logout', - async onSuccess() { - session.user = getSessionUser(); - await router.replace({ name: 'Login' }); - localStorage.removeItem('current_team'); - // On logout, reset posthog user identity and device id - if (window.posthog?.__loaded) { - posthog.reset(true); - } - - // clear all cache from the session - clear(); - - window.location.reload(); - } - }), - logoutWithoutReload: createResource({ - url: 'logout', - async onSuccess() { - session.user = getSessionUser(); - localStorage.removeItem('current_team'); - // On logout, reset posthog user identity and device id - if (window.posthog?.__loaded) { - posthog.reset(true); - } - - clear(); - } - }), - roles: createResource({ - url: 'jcloud.api.account.get_permission_roles', - cache: ['roles', localStorage.getItem('current_team')], - initialData: [] - }), - isTeamAdmin: computed( - () => - session.roles.data.length - ? session.roles.data.some(role => role.admin_access) - : false // if no roles, assume not admin and has member access - ), - hasBillingAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_billing) - : true - ), - hasWebhookConfigurationAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_webhook_configuration) - : true - ), - hasAppsAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_apps) - : true - ), - hasPartnerAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_partner) - : true - ), - hasSiteCreationAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_site_creation) - : true - ), - hasBenchCreationAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_bench_creation) - : true - ), - hasServerCreationAccess: computed(() => - session.roles.data.length - ? session.roles.data.some(role => role.allow_server_creation) - : true - ), - user: getSessionUser(), - isLoggedIn: computed(() => !!session.user), - isSystemUser: getSessionCookies().get('system_user') === 'yes' -}); - -export default session; - -export function getSessionUser() { - let cookies = getSessionCookies(); - let sessionUser = cookies.get('user_id'); - if (!sessionUser || sessionUser === 'Guest') { - sessionUser = null; - } - return sessionUser; -} - -function getSessionCookies() { - return new URLSearchParams(document.cookie.split('; ').join('&')); -} diff --git a/dashboard/src2/objects/common/apps.ts b/dashboard/src2/objects/common/apps.ts deleted file mode 100644 index f17b754..0000000 --- a/dashboard/src2/objects/common/apps.ts +++ /dev/null @@ -1,256 +0,0 @@ -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'); - } - } - ]; - } -}; \ No newline at end of file diff --git a/dashboard/src2/objects/site.js b/dashboard/src2/objects/site.js index 634a2ed..0bd7e9c 100644 --- a/dashboard/src2/objects/site.js +++ b/dashboard/src2/objects/site.js @@ -153,6 +153,7 @@ export default { 'Archived': '已归档', 'Pending': '待处理', 'Installing': '安装中', + 'Update Available': '可更新', 'Running': '运行中', 'Success': '成功', 'Failure': '失败'