@oj-module/cli 0.2.1 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devkit/README.md +14 -3
- package/devkit/SKILL.md +16 -4
- package/devkit/framework-dev.md +8 -6
- package/devkit/manual.md +243 -23
- package/package.json +2 -2
- package/shell-dist/assets/runtime.js +143 -8
- package/shell-dist/index.html +2 -2
- package/shell-dist/versions.json +3 -3
- package/src/args.ts +67 -0
- package/src/build.ts +11 -3
- package/src/bundle.ts +197 -0
- package/src/contract/__tests__/handler-scan.test.ts +82 -0
- package/src/contract/check.ts +2 -1
- package/src/contract/handler-scan.ts +32 -0
- package/src/deterministic-tar.ts +120 -0
- package/src/dev.ts +4 -2
- package/src/enable.ts +28 -0
- package/src/index.ts +63 -2
- package/src/info.ts +3 -2
- package/src/init.ts +147 -14
- package/src/install.ts +268 -0
- package/src/keygen.ts +88 -0
- package/src/layout.ts +31 -0
- package/src/lifecycle/__tests__/authoring.test.ts +109 -0
- package/src/lifecycle/__tests__/bundle.test.ts +150 -0
- package/src/lifecycle/__tests__/deterministic-tar.test.ts +145 -0
- package/src/lifecycle/__tests__/fixtures/README.md +59 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/EXPECTED-VIOLATIONS.md +27 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/api/src/Demo/manifest.yaml +6 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/manifest.yaml +40 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/entry.ts +14 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/locales/en-US.json +12 -0
- package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/locales/zh-CN.json +12 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +9 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +6 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/ping/api.ts +9 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +9 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +96 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/entry.ts +23 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/locales/en-US.json +29 -0
- package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/locales/zh-CN.json +29 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz +0 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.bad.sig +7 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.sig +7 -0
- package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.unknown.sig +7 -0
- package/src/lifecycle/__tests__/fixtures/sig/gen-signed-fixtures.d.mts +21 -0
- package/src/lifecycle/__tests__/fixtures/sig/gen-signed-fixtures.mjs +196 -0
- package/src/lifecycle/__tests__/helpers.ts +78 -0
- package/src/lifecycle/__tests__/install.test.ts +514 -0
- package/src/lifecycle/__tests__/keygen.test.ts +61 -0
- package/src/lifecycle/__tests__/manifest-contract.test.ts +228 -0
- package/src/lifecycle/__tests__/publish.test.ts +80 -0
- package/src/lifecycle/__tests__/sig-fixtures.test.ts +100 -0
- package/src/lifecycle/__tests__/sign.test.ts +131 -0
- package/src/lifecycle/__tests__/smoke.test.ts +61 -0
- package/src/lifecycle/__tests__/trust.test.ts +177 -0
- package/src/lifecycle/__tests__/uninstall.test.ts +87 -0
- package/src/lifecycle/keygen.ts +40 -0
- package/src/lifecycle/sign.ts +74 -0
- package/src/manifest-contract.ts +696 -0
- package/src/oj-cert.ts +19 -0
- package/src/oj-cmd.ts +3 -3
- package/src/preview.ts +2 -2
- package/src/publish.ts +150 -0
- package/src/sign.ts +128 -0
- package/src/site.ts +146 -0
- package/src/trust.ts +116 -0
- package/src/uninstall.ts +29 -0
- package/src/usage.ts +35 -1
- package/templates/README.md +46 -7
- package/templates/api/config.yaml +47 -0
- package/templates/api/seed.mysql.sql +1 -1
- package/templates/api/seed.pg.sql +1 -1
- package/templates/api/src/_platform/_lifecycle/atomic.ts +98 -0
- package/templates/api/src/_platform/_lifecycle/history.ts +31 -0
- package/templates/api/src/_platform/_lifecycle/installer.ts +1080 -0
- package/templates/api/src/_platform/_lifecycle/lock.ts +148 -0
- package/templates/api/src/_platform/_lifecycle/semver.ts +61 -0
- package/templates/api/src/_platform/_lifecycle/sha384.ts +187 -0
- package/templates/api/src/_platform/_lifecycle/state.ts +256 -0
- package/templates/api/src/_platform/_lifecycle/steps/deploy-web.ts +182 -0
- package/templates/api/src/_platform/_lifecycle/steps/download.ts +90 -0
- package/templates/api/src/_platform/_lifecycle/steps/extract.ts +239 -0
- package/templates/api/src/_platform/_lifecycle/steps/migrate.ts +363 -0
- package/templates/api/src/_platform/_lifecycle/steps/preflight.ts +590 -0
- package/templates/api/src/_platform/_lifecycle/steps/register.ts +211 -0
- package/templates/api/src/_platform/_lifecycle/steps/reload.ts +81 -0
- package/templates/api/src/_platform/_lifecycle/steps/smoke.ts +216 -0
- package/templates/api/src/_platform/_lifecycle/steps/verify.ts +207 -0
- package/templates/api/src/_platform/_lifecycle/tasks.ts +119 -0
- package/templates/api/src/_platform/_lifecycle/text-edit.ts +110 -0
- package/templates/api/src/_platform/_lifecycle/tgz-guard.ts +41 -0
- package/templates/api/src/_platform/_lifecycle/trust.ts +229 -0
- package/templates/api/src/_platform/_lifecycle/types.ts +94 -0
- package/templates/api/src/_platform/_lifecycle/uninstall.ts +283 -0
- package/templates/api/src/_platform/_lifecycle/verify-checks.ts +228 -0
- package/templates/api/src/_platform/_lifecycle/verify-report.ts +92 -0
- package/templates/api/src/_platform/_shared/service/access.ts +2 -2
- package/templates/api/src/_platform/_shared/service/settings.ts +10 -1
- package/templates/api/src/_platform/_shared/service/solution-perms.ts +14 -7
- package/templates/api/src/_platform/_shared/site-facade.ts +44 -0
- package/templates/api/src/_platform/manifest.yaml +1 -0
- package/templates/api/src/_platform/market/api.ts +883 -0
- package/templates/api/src/_platform/market/bootstrap.ts +39 -0
- package/templates/api/src/_platform/migrations/0010__sys_solution_route.mysql.sql +17 -0
- package/templates/api/src/_platform/migrations/0010__sys_solution_route.pg.sql +16 -0
- package/templates/api/src/_platform/migrations/0010__sys_solution_route.sql +18 -0
- package/templates/api/src/_platform/migrations/0011__sys_setting_group_label.mysql.sql +2 -0
- package/templates/api/src/_platform/migrations/0011__sys_setting_group_label.sql +4 -0
- package/templates/api/src/_platform/migrations/0012__market_history.mysql.sql +13 -0
- package/templates/api/src/_platform/migrations/0012__market_history.pg.sql +12 -0
- package/templates/api/src/_platform/migrations/0012__market_history.sql +14 -0
- package/templates/api/src/_platform/schema.yaml +21 -4
- package/templates/api/src/_platform/seed.sql +2 -2
- package/templates/api/src/_platform/solutions/api.ts +212 -0
- package/templates/api/src/demo/manifest.yaml +5 -0
- package/templates/api/src/demo/migrations/0001__create_todos.sql +9 -0
- package/templates/api/src/demo/schema.yaml +11 -0
- package/templates/api/src/demo/seed.sql +5 -0
- package/templates/api/src/demo/todos/api.ts +59 -0
- package/templates/api/src/home/line/api.ts +57 -0
- package/templates/api/src/home/manifest.yaml +6 -0
- package/templates/api/src/home/migrations/0001__create_home_tables.sql +13 -0
- package/templates/api/src/home/pie/api.ts +40 -0
- package/templates/api/src/home/schema.yaml +14 -0
- package/templates/api/src/home/seed.sql +70 -0
- package/templates/api/src/system/oplog/api.ts +44 -2
- package/templates/api/tests/fixture.ts +16 -0
- package/templates/api/tests/lifecycle/atomic-state.spec.ts +183 -0
- package/templates/api/tests/lifecycle/bootstrap.spec.ts +116 -0
- package/templates/api/tests/lifecycle/deploy-smoke.spec.ts +492 -0
- package/templates/api/tests/lifecycle/installer.spec.ts +1218 -0
- package/templates/api/tests/lifecycle/market-api.spec.ts +971 -0
- package/templates/api/tests/lifecycle/migrate.spec.ts +575 -0
- package/templates/api/tests/lifecycle/preflight.spec.ts +255 -0
- package/templates/api/tests/lifecycle/register.spec.ts +194 -0
- package/templates/api/tests/lifecycle/semver.spec.ts +43 -0
- package/templates/api/tests/lifecycle/sha384.spec.ts +48 -0
- package/templates/api/tests/lifecycle/sig-fixtures.spec.ts +65 -0
- package/templates/api/tests/lifecycle/solutions-api.spec.ts +98 -0
- package/templates/api/tests/lifecycle/steps-fs.spec.ts +623 -0
- package/templates/api/tests/lifecycle/text-edit.spec.ts +177 -0
- package/templates/api/tests/lifecycle/tgz-guard.spec.ts +103 -0
- package/templates/api/tests/lifecycle/trust.spec.ts +310 -0
- package/templates/api/tests/lifecycle/uninstall.spec.ts +386 -0
- package/templates/api/tests/lifecycle/verify-checks.spec.ts +385 -0
- package/templates/api/tests/lifecycle/verify-report.spec.ts +290 -0
- package/templates/api/tests/rbac-settings.spec.ts +8 -0
- package/templates/init.include.yaml +56 -0
- package/templates/openapi.json +527 -0
- package/templates/package.json +52 -0
- package/templates/web/src/_platform/__client/api.schemas.ts +8 -0
- package/templates/web/src/_platform/__client/api.ts +335 -0
- package/templates/web/src/about/entry.ts +42 -0
- package/templates/web/src/about/locales/en-US.json +16 -0
- package/templates/web/src/about/locales/zh-CN.json +16 -0
- package/templates/web/src/about/pages/constants.ts +20 -0
- package/templates/web/src/about/pages/index.tsx +135 -0
- package/templates/web/src/access/entry.ts +74 -0
- package/templates/web/src/access/locales/en-US.json +46 -0
- package/templates/web/src/access/locales/zh-CN.json +46 -0
- package/templates/web/src/access/pages/access-mode/index.tsx +16 -0
- package/templates/web/src/access/pages/admin-visible/index.tsx +16 -0
- package/templates/web/src/access/pages/button-control/index.tsx +181 -0
- package/templates/web/src/access/pages/common-visible/index.tsx +16 -0
- package/templates/web/src/access/pages/page-control/index.tsx +142 -0
- package/templates/web/src/demo/__client/api.schemas.ts +20 -0
- package/templates/web/src/demo/__client/api.ts +89 -0
- package/templates/web/src/exception/entry.ts +80 -0
- package/templates/web/src/exception/locales/en-US.json +13 -0
- package/templates/web/src/exception/locales/zh-CN.json +13 -0
- package/templates/web/src/exception/pages/403/index.tsx +30 -0
- package/templates/web/src/exception/pages/404/index.tsx +30 -0
- package/templates/web/src/exception/pages/500/index.tsx +30 -0
- package/templates/web/src/exception/pages/unknown-component/index.tsx +38 -0
- package/templates/web/src/home/__client/api.schemas.ts +22 -0
- package/templates/web/src/home/__client/api.ts +113 -0
- package/templates/web/src/login/locales/en-US.json +6 -0
- package/templates/web/src/login/locales/zh-CN.json +6 -0
- package/templates/web/src/login/pages/login.tsx +67 -18
- package/templates/web/src/oj-market/__tests__/CardGrid.test.tsx +93 -0
- package/templates/web/src/oj-market/__tests__/HistoryDrawer.test.tsx +28 -0
- package/templates/web/src/oj-market/__tests__/InstallDialog.test.tsx +69 -0
- package/templates/web/src/oj-market/__tests__/RollbackDialog.test.tsx +43 -0
- package/templates/web/src/oj-market/__tests__/UninstallConfirm.test.tsx +30 -0
- package/templates/web/src/oj-market/__tests__/marketClient.fake.ts +70 -0
- package/templates/web/src/oj-market/__tests__/poll.test.ts +24 -0
- package/templates/web/src/oj-market/__tests__/render.tsx +14 -0
- package/templates/web/src/oj-market/__tests__/runtime-stub.ts +14 -0
- package/templates/web/src/oj-market/__tests__/semver.test.ts +26 -0
- package/templates/web/src/oj-market/api/MarketClientProvider.tsx +12 -0
- package/templates/web/src/oj-market/api/client.ts +135 -0
- package/templates/web/src/oj-market/api/context.ts +11 -0
- package/templates/web/src/oj-market/api/defaultClient.ts +7 -0
- package/templates/web/src/oj-market/components/CardGrid.tsx +76 -0
- package/templates/web/src/oj-market/components/CardItem.tsx +102 -0
- package/templates/web/src/oj-market/components/DetailDrawer.tsx +53 -0
- package/templates/web/src/oj-market/components/HistoryDrawer.tsx +75 -0
- package/templates/web/src/oj-market/components/InstallDialog.tsx +112 -0
- package/templates/web/src/oj-market/components/RollbackDialog.tsx +79 -0
- package/templates/web/src/oj-market/components/UninstallConfirm.tsx +74 -0
- package/templates/web/src/oj-market/entry.ts +27 -0
- package/templates/web/src/oj-market/hooks/useMarket.ts +91 -0
- package/templates/web/src/oj-market/locales/en-US.json +100 -0
- package/templates/web/src/oj-market/locales/zh-CN.json +100 -0
- package/templates/web/src/oj-market/pages/MarketApp.tsx +136 -0
- package/templates/web/src/oj-market/types.ts +84 -0
- package/templates/web/src/oj-market/utils/poll.ts +36 -0
- package/templates/web/src/oj-market/utils/semver.ts +14 -0
- package/templates/web/src/outside/entry.ts +80 -0
- package/templates/web/src/outside/locales/en-US.json +10 -0
- package/templates/web/src/outside/locales/zh-CN.json +10 -0
- package/templates/web/src/personal-center/entry.ts +1 -10
- package/templates/web/src/personal-center/locales/en-US.json +1 -5
- package/templates/web/src/personal-center/locales/zh-CN.json +1 -5
- package/templates/web/src/route-nest/entry.ts +73 -0
- package/templates/web/src/route-nest/locales/en-US.json +9 -0
- package/templates/web/src/route-nest/locales/zh-CN.json +9 -0
- package/templates/web/src/route-nest/pages/menu1/menu1-1/index.tsx +5 -0
- package/templates/web/src/route-nest/pages/menu1/menu1-2/index.tsx +5 -0
- package/templates/web/src/route-nest/pages/menu2/index.tsx +5 -0
- package/templates/web/src/system/__client/api.schemas.ts +162 -0
- package/templates/web/src/system/__client/api.ts +382 -0
- package/templates/web/src/system/pages/oplog/index.tsx +1 -1
- package/templates/web/src/system/pages/roles/index.tsx +1 -0
- package/templates/web/src/system/pages/settings/index.tsx +1 -1
- package/templates/web/src/system/pages/users/index.tsx +1 -1
- package/templates/web.config.ts +32 -40
- package/vendor/host-versions.json +3 -3
- package/templates/pnpm-workspace.yaml +0 -14
- package/templates/web/src/personal-center/pages/settings/index.tsx +0 -5
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { IndexRow, TaskRecord } from "../types";
|
|
2
|
+
import { Typography } from "antd";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { useMarketClient } from "../api/context";
|
|
6
|
+
import { CardGrid } from "../components/CardGrid";
|
|
7
|
+
import { DetailDrawer } from "../components/DetailDrawer";
|
|
8
|
+
import { HistoryDrawer } from "../components/HistoryDrawer";
|
|
9
|
+
import { InstallDialog } from "../components/InstallDialog";
|
|
10
|
+
import { RollbackDialog } from "../components/RollbackDialog";
|
|
11
|
+
import { UninstallConfirm } from "../components/UninstallConfirm";
|
|
12
|
+
import { useMarketIndex } from "../hooks/useMarket";
|
|
13
|
+
|
|
14
|
+
/** 市场应用主页面:组装卡片网格 + 详情/安装/卸载/回滚/历史交互面(单一容器,DRY 编排) */
|
|
15
|
+
export default function MarketApp() {
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
const client = useMarketClient();
|
|
18
|
+
const index = useMarketIndex();
|
|
19
|
+
|
|
20
|
+
const [detailRow, setDetailRow] = useState<IndexRow | null>(null);
|
|
21
|
+
const [installRow, setInstallRow] = useState<IndexRow | null>(null);
|
|
22
|
+
const [installVersion, setInstallVersion] = useState<string | null>(null);
|
|
23
|
+
const [installMode, setInstallMode] = useState<"install" | "upgrade" | "rollback">("install");
|
|
24
|
+
const [uninstallRow, setUninstallRow] = useState<IndexRow | null>(null);
|
|
25
|
+
const [rollbackRow, setRollbackRow] = useState<IndexRow | null>(null);
|
|
26
|
+
const [historyRow, setHistoryRow] = useState<IndexRow | null>(null);
|
|
27
|
+
const [busyName, setBusyName] = useState<string | null>(null);
|
|
28
|
+
|
|
29
|
+
const rows = index.status === "ok" ? index.data : [];
|
|
30
|
+
|
|
31
|
+
// 安装/升级:目标版本缺省(取 latest);已装视为升级
|
|
32
|
+
const handleInstall = (row: IndexRow) => {
|
|
33
|
+
setDetailRow(null);
|
|
34
|
+
setInstallRow(row);
|
|
35
|
+
setInstallVersion(null);
|
|
36
|
+
setInstallMode(row.installed != null ? "upgrade" : "install");
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// 回滚:先开版本选择抽屉,选中旧版后转安装(降级安装,显式 version)
|
|
40
|
+
const handleRollback = (row: IndexRow) => {
|
|
41
|
+
setDetailRow(null);
|
|
42
|
+
setRollbackRow(row);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const handleRollbackChosen = (row: IndexRow, version: string) => {
|
|
46
|
+
setRollbackRow(null);
|
|
47
|
+
setInstallRow(row);
|
|
48
|
+
setInstallVersion(version);
|
|
49
|
+
setInstallMode("rollback");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleEnableToggle = async (row: IndexRow) => {
|
|
53
|
+
setBusyName(row.name);
|
|
54
|
+
try {
|
|
55
|
+
await client.enable({ name: row.name, enabled: row.enabled !== true });
|
|
56
|
+
index.retry();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
setBusyName(null);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const handleUninstallConfirmed = async (row: IndexRow) => {
|
|
64
|
+
setBusyName(row.name);
|
|
65
|
+
try {
|
|
66
|
+
await client.uninstall(row.name);
|
|
67
|
+
setUninstallRow(null);
|
|
68
|
+
index.retry();
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
setBusyName(null);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handleInstallDone = (_rec: TaskRecord) => {
|
|
76
|
+
index.retry();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div style={{ padding: 24 }} data-testid="market-app">
|
|
81
|
+
<Typography.Title level={4}>{t("oj-market:card:title")}</Typography.Title>
|
|
82
|
+
<Typography.Paragraph type="secondary">{t("oj-market:card:subtitle")}</Typography.Paragraph>
|
|
83
|
+
|
|
84
|
+
<CardGrid
|
|
85
|
+
loading={index.status === "loading"}
|
|
86
|
+
error={index.status === "error" ? index.error : null}
|
|
87
|
+
rows={rows}
|
|
88
|
+
busyName={busyName}
|
|
89
|
+
onInstall={handleInstall}
|
|
90
|
+
onEnableToggle={handleEnableToggle}
|
|
91
|
+
onDetails={r => setDetailRow(r)}
|
|
92
|
+
onHistory={r => setHistoryRow(r)}
|
|
93
|
+
onUninstall={r => setUninstallRow(r)}
|
|
94
|
+
onRollback={handleRollback}
|
|
95
|
+
onRetry={index.retry}
|
|
96
|
+
/>
|
|
97
|
+
|
|
98
|
+
<DetailDrawer
|
|
99
|
+
row={detailRow}
|
|
100
|
+
open={detailRow != null}
|
|
101
|
+
onClose={() => setDetailRow(null)}
|
|
102
|
+
onInstall={handleInstall}
|
|
103
|
+
onHistory={(r) => {
|
|
104
|
+
setDetailRow(null);
|
|
105
|
+
setHistoryRow(r);
|
|
106
|
+
}}
|
|
107
|
+
onRollback={handleRollback}
|
|
108
|
+
/>
|
|
109
|
+
|
|
110
|
+
<InstallDialog
|
|
111
|
+
row={installRow}
|
|
112
|
+
open={installRow != null}
|
|
113
|
+
onClose={() => setInstallRow(null)}
|
|
114
|
+
onDone={handleInstallDone}
|
|
115
|
+
version={installVersion}
|
|
116
|
+
mode={installMode}
|
|
117
|
+
/>
|
|
118
|
+
|
|
119
|
+
<UninstallConfirm
|
|
120
|
+
row={uninstallRow}
|
|
121
|
+
open={uninstallRow != null}
|
|
122
|
+
onClose={() => setUninstallRow(null)}
|
|
123
|
+
onConfirmed={handleUninstallConfirmed}
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
<RollbackDialog
|
|
127
|
+
row={rollbackRow}
|
|
128
|
+
open={rollbackRow != null}
|
|
129
|
+
onClose={() => setRollbackRow(null)}
|
|
130
|
+
onRollback={handleRollbackChosen}
|
|
131
|
+
/>
|
|
132
|
+
|
|
133
|
+
<HistoryDrawer row={historyRow} open={historyRow != null} onClose={() => setHistoryRow(null)} />
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// 市场领域类型(形状对齐宿主 _platform 编排面真源 + 本仓 market_history 表)。
|
|
2
|
+
// 真源:templates/api/src/_platform/_lifecycle/types.ts:47 (TaskRecord) 与 market/api.ts:IndexRow。
|
|
3
|
+
// 任何形状漂移以 templates 源码为准——实现前已核对(2026-10-17)。
|
|
4
|
+
|
|
5
|
+
/** 安装阶段名(契约附录 A 十阶段逐字 + lock_commit/audit/done 终态) */
|
|
6
|
+
export type InstallStage = "preflight" | "downloading" | "verifying" | "extracting" | "migrating" | "lock_commit" | "registering" | "deploying_web" | "reloading" | "smoke" | "audit" | "done";
|
|
7
|
+
|
|
8
|
+
/** 任务状态(§10.2 三态 + partial:锁后失败部分生效) */
|
|
9
|
+
export type TaskStatus = "running" | "done" | "failed" | "partial";
|
|
10
|
+
|
|
11
|
+
/** 阶段明细日志(UI 详情日志区数据源) */
|
|
12
|
+
export interface TaskStageLog {
|
|
13
|
+
stage: InstallStage
|
|
14
|
+
ok: boolean
|
|
15
|
+
message: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 失败/partial 终态:reason + retryable + 指引文案 key(契约附录 A) */
|
|
19
|
+
export interface TaskError {
|
|
20
|
+
reason: string
|
|
21
|
+
retryable: boolean
|
|
22
|
+
hintKey?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 安装任务记录(§10.2 + stages 明细日志;落 .install-tasks/<id>.json,800ms 轮询消费面) */
|
|
26
|
+
export interface TaskRecord {
|
|
27
|
+
id: string
|
|
28
|
+
name: string
|
|
29
|
+
version: string
|
|
30
|
+
status: TaskStatus
|
|
31
|
+
stage: InstallStage | null
|
|
32
|
+
/** 0-100 整体进度 */
|
|
33
|
+
progress: number
|
|
34
|
+
message: string
|
|
35
|
+
stages: TaskStageLog[]
|
|
36
|
+
error?: TaskError
|
|
37
|
+
startedAt: number
|
|
38
|
+
finishedAt?: number
|
|
39
|
+
appliedSeq?: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** 卡片数据源行(GET /_platform/market/index):CDN bundles.yaml ⊕ 本地 sidecar state */
|
|
43
|
+
export interface IndexRow {
|
|
44
|
+
name: string
|
|
45
|
+
latest: string | null
|
|
46
|
+
installed: string | null
|
|
47
|
+
enabled: boolean | null
|
|
48
|
+
upgradable: boolean
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 安装输入(POST /_platform/market/install) */
|
|
52
|
+
export interface InstallInput {
|
|
53
|
+
name: string
|
|
54
|
+
version?: string | null
|
|
55
|
+
source?: "cdn" | "file"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 启用/停用输入(POST /_platform/market/enable) */
|
|
59
|
+
export interface EnableInput {
|
|
60
|
+
name: string
|
|
61
|
+
enabled: boolean
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** 市场操作历史动作 */
|
|
65
|
+
export type HistoryAction = "install" | "uninstall" | "enable" | "disable" | "upgrade" | "rollback";
|
|
66
|
+
|
|
67
|
+
/** 市场操作历史记录(本仓 market_history 表,只读消费) */
|
|
68
|
+
export interface MarketHistory {
|
|
69
|
+
id: number
|
|
70
|
+
solution: string
|
|
71
|
+
version: string
|
|
72
|
+
action: HistoryAction
|
|
73
|
+
status: string
|
|
74
|
+
operator: string | null
|
|
75
|
+
message: string | null
|
|
76
|
+
created_at: number
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 卸载影响面预检(P3 U1 语义;服务端返回供前端二次确认) */
|
|
80
|
+
export interface UninstallImpact {
|
|
81
|
+
name: string
|
|
82
|
+
affectedRoles: number
|
|
83
|
+
affectedUsers: number
|
|
84
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// 通用轮询工具(§10.2:市场任务 800ms 轮询、退避上限 5s、超时 30min 由调用方配置)。
|
|
2
|
+
// 纯函数、无副作用、可独立单测。
|
|
3
|
+
|
|
4
|
+
export interface PollOptions {
|
|
5
|
+
/** 轮询间隔(默认 800ms) */
|
|
6
|
+
intervalMs?: number
|
|
7
|
+
/** 整体超时(默认 30min) */
|
|
8
|
+
timeoutMs?: number
|
|
9
|
+
/** 中断信号 */
|
|
10
|
+
signal?: AbortSignal
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 反复执行 fn,直到 isDone(value) 为真或超时。
|
|
15
|
+
* 超时返回最近一次取值(由调用方标记超时态),不抛错——避免轮询中断业务。
|
|
16
|
+
*/
|
|
17
|
+
export async function poll<T>(
|
|
18
|
+
fn: () => Promise<T>,
|
|
19
|
+
isDone: (value: T) => boolean,
|
|
20
|
+
opts: PollOptions = {},
|
|
21
|
+
): Promise<T> {
|
|
22
|
+
const interval = opts.intervalMs ?? 800;
|
|
23
|
+
const timeout = opts.timeoutMs ?? 30 * 60 * 1000;
|
|
24
|
+
const start = Date.now();
|
|
25
|
+
// 轮询循环:每轮先取最新值,终态即返回,超时则返回当前值
|
|
26
|
+
for (;;) {
|
|
27
|
+
if (opts.signal?.aborted)
|
|
28
|
+
throw new DOMException("aborted", "AbortError");
|
|
29
|
+
const value = await fn();
|
|
30
|
+
if (isDone(value))
|
|
31
|
+
return value;
|
|
32
|
+
if (Date.now() - start > timeout)
|
|
33
|
+
return value;
|
|
34
|
+
await new Promise<void>(resolve => setTimeout(resolve, interval));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// 版本比较(镜像 oj-module _lifecycle/semver 的最小口径,前端本地副本——宿主 semver 在
|
|
2
|
+
// 服务端隔离层,前端不可 import;点分/连字符预发布字段逐段数值比)。返回 <0 / 0 / >0。
|
|
3
|
+
// 用途:双版本卡片 upgradable 对比展示 + 回滚候选过滤(候选 = 版本 < 已装版本)。
|
|
4
|
+
export function compareVersions(a: string, b: string): number {
|
|
5
|
+
const pa = String(a).split(/[.\-]/).map(x => Number.parseInt(x, 10) || 0);
|
|
6
|
+
const pb = String(b).split(/[.\-]/).map(x => Number.parseInt(x, 10) || 0);
|
|
7
|
+
const n = Math.max(pa.length, pb.length);
|
|
8
|
+
for (let i = 0; i < n; i++) {
|
|
9
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
10
|
+
if (d !== 0)
|
|
11
|
+
return d < 0 ? -1 : 1;
|
|
12
|
+
}
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { AppRouteRecordRaw, ModuleDefinition } from "@oj-module/runtime";
|
|
2
|
+
import { AntDesignOutlined, ContainerOutlined } from "@ant-design/icons";
|
|
3
|
+
|
|
4
|
+
import { EmbeddedIcon, ExternalIcon, Iframe, OutsidePageIcon, RiReactjsLine } from "@oj-module/runtime";
|
|
5
|
+
import { createElement } from "react";
|
|
6
|
+
import { Outlet } from "react-router";
|
|
7
|
+
|
|
8
|
+
const routes: AppRouteRecordRaw[] = [
|
|
9
|
+
{
|
|
10
|
+
path: "/outside",
|
|
11
|
+
handle: {
|
|
12
|
+
layout: "container",
|
|
13
|
+
icon: createElement(OutsidePageIcon),
|
|
14
|
+
title: "outside:menu.outside",
|
|
15
|
+
order: 40,
|
|
16
|
+
},
|
|
17
|
+
children: [
|
|
18
|
+
{
|
|
19
|
+
path: "/outside/embedded",
|
|
20
|
+
Component: Outlet,
|
|
21
|
+
handle: {
|
|
22
|
+
icon: createElement(EmbeddedIcon),
|
|
23
|
+
title: "outside:menu.embedded",
|
|
24
|
+
},
|
|
25
|
+
children: [
|
|
26
|
+
{
|
|
27
|
+
path: "/outside/embedded/ant-design",
|
|
28
|
+
Component: Iframe,
|
|
29
|
+
handle: {
|
|
30
|
+
icon: createElement(AntDesignOutlined),
|
|
31
|
+
title: "outside:menu.antd",
|
|
32
|
+
iframeLink: "https://ant.design/",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
path: "/outside/embedded/project-docs",
|
|
37
|
+
Component: Iframe,
|
|
38
|
+
handle: {
|
|
39
|
+
icon: createElement(ContainerOutlined),
|
|
40
|
+
title: "outside:menu.projectDocs",
|
|
41
|
+
iframeLink: "https://condorheroblog.github.io/react-antd-admin/docs/",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
path: "/outside/external-link",
|
|
48
|
+
Component: Outlet,
|
|
49
|
+
handle: {
|
|
50
|
+
icon: createElement(ExternalIcon),
|
|
51
|
+
title: "outside:menu.externalLink",
|
|
52
|
+
},
|
|
53
|
+
children: [
|
|
54
|
+
{
|
|
55
|
+
path: "/outside/external-link/react-docs",
|
|
56
|
+
Component: Iframe,
|
|
57
|
+
handle: {
|
|
58
|
+
icon: createElement(RiReactjsLine),
|
|
59
|
+
title: "outside:menu.reactDocs",
|
|
60
|
+
externalLink: "https://react.dev/",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const mod: ModuleDefinition = {
|
|
70
|
+
name: "outside",
|
|
71
|
+
description: "外部链接模块",
|
|
72
|
+
version: "1.0.0",
|
|
73
|
+
routes,
|
|
74
|
+
i18n: {
|
|
75
|
+
"zh-CN": () => import("./locales/zh-CN.json"),
|
|
76
|
+
"en-US": () => import("./locales/en-US.json"),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default mod;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { AppRouteRecordRaw, ModuleDefinition, UploadApiProvider } from "@oj-module/runtime";
|
|
2
|
-
import { ProfileCardIcon, RiAccountCircleLine,
|
|
2
|
+
import { ProfileCardIcon, RiAccountCircleLine, useAuthStore } from "@oj-module/runtime";
|
|
3
3
|
|
|
4
4
|
import { createElement, lazy } from "react";
|
|
5
5
|
|
|
6
6
|
const MyProfile = lazy(() => import("./pages/my-profile"));
|
|
7
|
-
const Settings = lazy(() => import("./pages/settings"));
|
|
8
7
|
|
|
9
8
|
const routes: AppRouteRecordRaw[] = [
|
|
10
9
|
{
|
|
@@ -24,14 +23,6 @@ const routes: AppRouteRecordRaw[] = [
|
|
|
24
23
|
icon: createElement(ProfileCardIcon),
|
|
25
24
|
},
|
|
26
25
|
},
|
|
27
|
-
{
|
|
28
|
-
path: "/personal-center/settings",
|
|
29
|
-
Component: Settings,
|
|
30
|
-
handle: {
|
|
31
|
-
title: "personal-center:menu.settings",
|
|
32
|
-
icon: createElement(RiUserSettingsLine),
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
26
|
],
|
|
36
27
|
},
|
|
37
28
|
];
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"accountSecurity": "Account Security",
|
|
3
|
-
"generalSettings": "General Settings",
|
|
4
|
-
"notificationSettings": "Notification Settings",
|
|
5
2
|
"menu": {
|
|
6
3
|
"personalCenter": "Personal Center",
|
|
7
|
-
"profile": "My Profile"
|
|
8
|
-
"settings": "Settings"
|
|
4
|
+
"profile": "My Profile"
|
|
9
5
|
}
|
|
10
6
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AppRouteRecordRaw, ModuleDefinition } from "@oj-module/runtime";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
NodeExpandOutlined,
|
|
5
|
+
SisternodeOutlined,
|
|
6
|
+
SubnodeOutlined,
|
|
7
|
+
} from "@ant-design/icons";
|
|
8
|
+
import { createElement, lazy } from "react";
|
|
9
|
+
|
|
10
|
+
const Menu1And1 = lazy(() => import("./pages/menu1/menu1-1"));
|
|
11
|
+
const Menu1And2 = lazy(() => import("./pages/menu1/menu1-2"));
|
|
12
|
+
const Menu2 = lazy(() => import("./pages/menu2"));
|
|
13
|
+
|
|
14
|
+
const routes: AppRouteRecordRaw[] = [
|
|
15
|
+
{
|
|
16
|
+
path: "/route-nest",
|
|
17
|
+
handle: {
|
|
18
|
+
order: 20,
|
|
19
|
+
title: "route-nest:menu.nestMenus",
|
|
20
|
+
icon: createElement(NodeExpandOutlined),
|
|
21
|
+
layout: "container",
|
|
22
|
+
},
|
|
23
|
+
children: [
|
|
24
|
+
{
|
|
25
|
+
path: "/route-nest/menu1",
|
|
26
|
+
handle: {
|
|
27
|
+
title: "route-nest:menu.menu1",
|
|
28
|
+
icon: createElement(SisternodeOutlined),
|
|
29
|
+
layout: "parent",
|
|
30
|
+
},
|
|
31
|
+
children: [
|
|
32
|
+
{
|
|
33
|
+
path: "/route-nest/menu1/menu1-1",
|
|
34
|
+
Component: Menu1And1,
|
|
35
|
+
handle: {
|
|
36
|
+
title: "route-nest:menu.menu1-1",
|
|
37
|
+
icon: createElement(SubnodeOutlined),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
path: "/route-nest/menu1/menu1-2",
|
|
42
|
+
Component: Menu1And2,
|
|
43
|
+
handle: {
|
|
44
|
+
title: "route-nest:menu.menu1-2",
|
|
45
|
+
icon: createElement(SubnodeOutlined),
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
path: "/route-nest/menu2",
|
|
52
|
+
Component: Menu2,
|
|
53
|
+
handle: {
|
|
54
|
+
title: "route-nest:menu.menu2",
|
|
55
|
+
icon: createElement(SubnodeOutlined),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const mod: ModuleDefinition = {
|
|
63
|
+
name: "route-nest",
|
|
64
|
+
description: "嵌套路由模块",
|
|
65
|
+
version: "1.0.0",
|
|
66
|
+
routes,
|
|
67
|
+
i18n: {
|
|
68
|
+
"zh-CN": () => import("./locales/zh-CN.json"),
|
|
69
|
+
"en-US": () => import("./locales/en-US.json"),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default mod;
|