@oj-module/cli 0.2.66 → 0.2.68
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/bin/.oj-version +1 -0
- package/bin/oj +4 -0
- package/devkit/README.md +15 -7
- package/devkit/SKILL.md +38 -4
- package/devkit/framework-dev.md +10 -4
- package/devkit/manual.md +146 -24
- package/devkit/menu-rules.md +19 -4
- package/devkit/module-dev-and-cdn-playground.md +4 -0
- package/devkit/publish-walkthrough.md +132 -37
- package/devkit/wecom-internal-app.md +8 -3
- package/devkit/wecom-multi-corp-links.md +163 -0
- package/package.json +2 -2
- package/shell-dist/assets/{index.i0kqbxp050.js → index.6alqyx6ae0.js} +21 -1
- package/shell-dist/assets/{runtime.1xfsxcajj0.js → runtime.1xzahckt10.js} +4863 -4847
- package/shell-dist/index.html +4 -4
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/cli.test.ts +31 -0
- package/src/__tests__/new-scaffold.test.ts +13 -0
- package/src/__tests__/publish-keygen.test.ts +157 -0
- package/src/__tests__/templates-migration-schema-parity.test.ts +540 -0
- package/src/__tests__/templates-schema-columns.test.ts +15 -2
- package/src/__tests__/templates-tenant-scope.test.ts +6 -2
- package/src/build/module-def.ts +1 -0
- package/src/builtin.ts +3 -2
- package/src/bundle.ts +8 -3
- package/src/cli.ts +21 -5
- package/src/dev.ts +15 -10
- package/src/init.ts +47 -41
- package/src/install.ts +11 -4
- package/src/keygen.ts +54 -0
- package/src/lifecycle/__tests__/bundle.test.ts +21 -3
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +1 -1
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +2 -2
- package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +5 -2
- package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +1 -1
- package/src/lifecycle/__tests__/manifest-contract.test.ts +75 -3
- package/src/lifecycle/__tests__/smoke.test.ts +2 -2
- package/src/manifest-contract.ts +91 -8
- package/src/market/bootstrap.ts +26 -2
- package/src/market/command.ts +1 -0
- package/src/market/publish.ts +8 -1
- package/src/market/walkthrough.ts +24 -8
- package/src/new.ts +2 -0
- package/src/scaffold-guard.ts +227 -0
- package/src/site.ts +2 -0
- package/src/usage.ts +13 -9
- package/src/vendor.ts +5 -1
- package/templates/config.yaml +4 -2
- package/templates/init.include.yaml +10 -3
- package/templates/openapi.json +460 -1
- package/templates/src/README.md +37 -0
- package/templates/src/app/api/_platform/_lifecycle/compensate.ts +136 -0
- package/templates/src/app/api/_platform/_lifecycle/installer.ts +78 -25
- package/templates/src/app/api/_platform/_lifecycle/lock.ts +23 -0
- package/templates/src/app/api/_platform/_lifecycle/steps/deploy-web.ts +28 -0
- package/templates/src/app/api/_platform/_lifecycle/steps/preflight.ts +46 -0
- package/templates/src/app/api/_platform/_lifecycle/steps/reload.ts +100 -36
- package/templates/src/app/api/_platform/_lifecycle/steps/smoke.ts +7 -15
- package/templates/src/app/api/_platform/_lifecycle/text-edit.ts +71 -19
- package/templates/src/app/api/_platform/_lifecycle/types.ts +26 -2
- package/templates/src/app/api/_platform/_lifecycle/uninstall.ts +93 -14
- package/templates/src/app/api/_platform/_shared/service/domain/settings.ts +8 -4
- package/templates/src/app/api/_platform/_shared/service/domain/solution-perms.ts +25 -10
- package/templates/src/app/api/_platform/manifest.yaml +1 -0
- package/templates/src/app/api/_platform/market/api.ts +235 -10
- package/templates/src/app/api/_platform/migrations/0001__baseline.mysql.sql +178 -0
- package/templates/src/app/api/_platform/migrations/0001__baseline.pg.sql +173 -0
- package/templates/src/app/api/_platform/migrations/0001__baseline.sql +188 -0
- package/templates/src/app/api/_platform/migrations/0002__market_release.mysql.sql +17 -0
- package/templates/src/app/api/_platform/migrations/0002__market_release.pg.sql +16 -0
- package/templates/src/app/api/_platform/migrations/0002__market_release.sql +33 -0
- package/templates/src/app/api/_platform/schema.yaml +18 -0
- package/templates/src/app/api/_platform/seed.mysql.sql +10 -0
- package/templates/src/app/api/_platform/seed.pg.sql +10 -0
- package/templates/src/app/api/auth/_shared/wecom/client.ts +24 -4
- package/templates/src/app/api/home/migrations/0001__create_home_tables.mysql.sql +14 -0
- package/templates/src/app/api/home/migrations/0001__create_home_tables.pg.sql +14 -0
- package/templates/src/app/api/home/migrations/0002__tenant.pg.sql +4 -0
- package/templates/src/app/api/home/seed.mysql.sql +71 -0
- package/templates/src/app/api/home/seed.pg.sql +71 -0
- package/templates/src/app/api/notification/_shared/notify.ts +6 -6
- package/templates/src/app/api/notification/migrations/0001__create_notifications.mysql.sql +11 -0
- package/templates/src/app/api/notification/migrations/0001__create_notifications.pg.sql +11 -0
- package/templates/src/app/api/notification/migrations/0002__notifications_user.mysql.sql +8 -0
- package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.mysql.sql +21 -0
- package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.pg.sql +22 -0
- package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.mysql.sql +10 -0
- package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.pg.sql +11 -0
- package/templates/src/app/api/notification/migrations/0005__tenant.pg.sql +6 -0
- package/templates/src/app/api/notification/seed.mysql.sql +8 -0
- package/templates/src/app/api/notification/seed.pg.sql +11 -0
- package/templates/src/app/api/publish/_shared/identity.ts +69 -0
- package/templates/src/app/api/publish/api.ts +349 -0
- package/templates/src/app/api/publish/manifest.yaml +8 -0
- package/templates/src/app/api/publish/migrations/0001__publish_credential.mysql.sql +23 -0
- package/templates/src/app/api/publish/migrations/0001__publish_credential.pg.sql +23 -0
- package/templates/src/app/api/publish/migrations/0001__publish_credential.sql +39 -0
- package/templates/src/app/api/publish/schema.yaml +33 -0
- package/templates/src/app/api/system/login-methods/api.ts +2 -1
- package/templates/src/app/web/_platform/__client/api.schemas.ts +15 -0
- package/templates/src/app/web/_platform/__client/index.ts +25 -1
- package/templates/src/app/web/entry.ts +9 -5
- package/templates/src/app/web/home/routes.ts +5 -0
- package/templates/src/app/web/login/locales/en-US.json +7 -1
- package/templates/src/app/web/login/locales/zh-CN.json +7 -1
- package/templates/src/app/web/login/pages/login.tsx +79 -86
- package/templates/src/app/web/login/routes.ts +54 -1
- package/templates/src/app/web/personal-center/locales/en-US.json +1 -0
- package/templates/src/app/web/personal-center/locales/zh-CN.json +1 -0
- package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +5 -0
- package/templates/src/app/web/system/__client/api.schemas.ts +2 -1
- package/templates/src/app/web/system/locales/en-US.json +1 -8
- package/templates/src/app/web/system/locales/zh-CN.json +1 -8
- package/templates/src/app/web/system/pages/settings/index.tsx +17 -4
- package/templates/src/app/web/system/routes.ts +0 -6
- package/templates/src/oj-market/web/__tests__/CardGrid.test.tsx +33 -0
- package/templates/src/oj-market/web/__tests__/DetailDrawer.test.tsx +69 -0
- package/templates/src/oj-market/web/__tests__/marketClient.fake.ts +7 -1
- package/templates/src/oj-market/web/api/client.ts +3 -0
- package/templates/src/oj-market/web/api/defaultClient.ts +5 -0
- package/templates/src/oj-market/web/components/CardItem.tsx +44 -1
- package/templates/src/oj-market/web/components/DetailDrawer.tsx +17 -1
- package/templates/src/oj-market/web/entry.ts +31 -2
- package/templates/src/oj-market/web/locales/en-US.json +5 -1
- package/templates/src/oj-market/web/locales/zh-CN.json +5 -1
- package/templates/src/oj-market/web/publish/__client/api.schemas.ts +61 -0
- package/templates/src/oj-market/web/publish/__client/index.ts +164 -0
- package/templates/src/oj-market/web/publish/locales/en-US.json +80 -0
- package/templates/src/oj-market/web/publish/locales/zh-CN.json +80 -0
- package/templates/src/oj-market/web/publish/pages/history.tsx +112 -0
- package/templates/src/oj-market/web/publish/pages/index.tsx +196 -0
- package/templates/src/oj-market/web/publish/pages/model.ts +52 -0
- package/templates/src/oj-market/web/publish/pages/token-modal.tsx +82 -0
- package/templates/src/oj-market/web/publish/routes.ts +41 -0
- package/templates/src/oj-market/web/types.ts +30 -0
- package/templates/tests/lifecycle/compensate.spec.ts +207 -0
- package/templates/tests/lifecycle/deploy-smoke.spec.ts +38 -14
- package/templates/tests/lifecycle/installer.spec.ts +28 -9
- package/templates/tests/lifecycle/market-api.spec.ts +164 -12
- package/templates/tests/lifecycle/preflight.spec.ts +68 -0
- package/templates/tests/lifecycle/register.spec.ts +22 -0
- package/templates/tests/lifecycle/role-title-translate.spec.ts +4 -34
- package/templates/tests/lifecycle/text-edit.spec.ts +45 -27
- package/templates/tests/lifecycle/uninstall.spec.ts +36 -0
- package/templates/tests/publish-credential.spec.ts +354 -0
- package/templates/tests/publish-identity.spec.ts +44 -0
- package/templates/tests/rbac-solution-perms.spec.ts +48 -3
- package/templates/tests/wecom-client-timeout.spec.ts +33 -3
- package/templates/tests/wecom-landing.spec.ts +63 -1
- package/templates/tsconfig.paths.json +1 -0
- package/templates/web.config.ts +8 -4
- package/vendor/host-versions.json +3 -3
- package/templates/seed.mysql.sql +0 -6
- package/templates/seed.pg.sql +0 -6
- package/templates/src/app/api/_platform/migrations/0001__create_users.mysql.sql +0 -9
- package/templates/src/app/api/_platform/migrations/0001__create_users.pg.sql +0 -9
- package/templates/src/app/api/_platform/migrations/0001__create_users.sql +0 -7
- package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.sql +0 -2
- package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.mysql.sql +0 -5
- package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.sql +0 -5
- package/templates/src/app/api/_platform/migrations/0004__sys_rbac.mysql.sql +0 -70
- package/templates/src/app/api/_platform/migrations/0004__sys_rbac.pg.sql +0 -67
- package/templates/src/app/api/_platform/migrations/0004__sys_rbac.sql +0 -67
- package/templates/src/app/api/_platform/migrations/0005__users_must_change.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0005__users_must_change.sql +0 -2
- package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0007__users_email.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.mysql.sql +0 -10
- package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.pg.sql +0 -10
- package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.sql +0 -11
- package/templates/src/app/api/_platform/migrations/0009__sys_throttle.mysql.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0009__sys_throttle.pg.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0009__sys_throttle.sql +0 -13
- package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.mysql.sql +0 -17
- package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.pg.sql +0 -16
- package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.sql +0 -18
- package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.mysql.sql +0 -2
- package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.sql +0 -4
- package/templates/src/app/api/_platform/migrations/0012__market_history.mysql.sql +0 -13
- package/templates/src/app/api/_platform/migrations/0012__market_history.pg.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0012__market_history.sql +0 -14
- package/templates/src/app/api/_platform/migrations/0013__users_profile.sql +0 -4
- package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.mysql.sql +0 -9
- package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.pg.sql +0 -7
- package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.sql +0 -8
- package/templates/src/app/api/_platform/migrations/0015__tenant.mysql.sql +0 -12
- package/templates/src/app/api/_platform/migrations/0015__tenant.pg.sql +0 -11
- package/templates/src/app/api/_platform/migrations/0015__tenant.sql +0 -44
- package/templates/src/app/api/_platform/migrations/0016__org.mysql.sql +0 -41
- package/templates/src/app/api/_platform/migrations/0016__org.pg.sql +0 -40
- package/templates/src/app/api/_platform/migrations/0016__org.sql +0 -62
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +0 -7
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +0 -4
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +0 -8
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +0 -3
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +0 -8
- package/templates/src/app/web/system/pages/login-methods/index.tsx +0 -30
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
"roles": "Roles & Permissions",
|
|
7
7
|
"oplog": "Audit Log",
|
|
8
8
|
"settings": "Site Settings",
|
|
9
|
-
"loginMethods": "Login Methods",
|
|
10
9
|
"wecom": "WeCom Integration",
|
|
11
10
|
"departments": "Departments"
|
|
12
11
|
},
|
|
@@ -130,13 +129,6 @@
|
|
|
130
129
|
"secretHint": "Secret items cannot be edited online",
|
|
131
130
|
"saved": "Settings saved"
|
|
132
131
|
},
|
|
133
|
-
"loginMethodsPage": {
|
|
134
|
-
"title": "Enabled login methods",
|
|
135
|
-
"methodLocal": "Local password",
|
|
136
|
-
"methodLdap": "LDAP",
|
|
137
|
-
"methodSso": "SSO",
|
|
138
|
-
"methodWecom": "WeCom"
|
|
139
|
-
},
|
|
140
132
|
"wecom": {
|
|
141
133
|
"title": "Onboard a corporation",
|
|
142
134
|
"hint": "Click \"Generate install link\" and send the link or QR code to the corporation's admin to scan/open for approval. On success this system auto-registers the corporation via the create_auth callback (writes wecom_app_profile). The link is generated by WeCom get_customized_auth_url; its validity follows WeCom's response (up to 10 days). The QR code greys out when it expires, so regenerate it.",
|
|
@@ -276,6 +268,7 @@
|
|
|
276
268
|
"login": "Login Methods",
|
|
277
269
|
"ldap": "LDAP"
|
|
278
270
|
},
|
|
271
|
+
"loginMethods": "Login Methods",
|
|
279
272
|
"site_title": "Site Title",
|
|
280
273
|
"market_cdn_url": "Market CDN URL",
|
|
281
274
|
"ldap_enabled": "Enable LDAP login",
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
"roles": "角色权限",
|
|
7
7
|
"oplog": "操作日志",
|
|
8
8
|
"settings": "站点设置",
|
|
9
|
-
"loginMethods": "登录方式",
|
|
10
9
|
"wecom": "企微集成",
|
|
11
10
|
"departments": "组织架构"
|
|
12
11
|
},
|
|
@@ -130,13 +129,6 @@
|
|
|
130
129
|
"secretHint": "敏感项不可在线修改",
|
|
131
130
|
"saved": "设置已保存"
|
|
132
131
|
},
|
|
133
|
-
"loginMethodsPage": {
|
|
134
|
-
"title": "当前启用的登录方式",
|
|
135
|
-
"methodLocal": "本地口令",
|
|
136
|
-
"methodLdap": "LDAP",
|
|
137
|
-
"methodSso": "SSO 单点登录",
|
|
138
|
-
"methodWecom": "企业微信"
|
|
139
|
-
},
|
|
140
132
|
"wecom": {
|
|
141
133
|
"title": "开通企业",
|
|
142
134
|
"hint": "点「生成开通链接」把链接或二维码发给企业管理员,由其扫码/打开授权;授权成功后本系统经 create_auth 回调自动登记该企业(落库 wecom_app_profile)。链接由企微 get_customized_auth_url 生成,有效期以企微返回为准(可达 10 天),过期后二维码置灰,可重新生成。",
|
|
@@ -276,6 +268,7 @@
|
|
|
276
268
|
"login": "登录方式",
|
|
277
269
|
"ldap": "LDAP"
|
|
278
270
|
},
|
|
271
|
+
"loginMethods": "登录方式",
|
|
279
272
|
"site_title": "站点标题",
|
|
280
273
|
"market_cdn_url": "市场 CDN 地址",
|
|
281
274
|
"ldap_enabled": "启用 LDAP 登录",
|
|
@@ -3,18 +3,21 @@ import type { TFunction } from "i18next";
|
|
|
3
3
|
import type { SystemSettingsGetData } from "../../__client";
|
|
4
4
|
|
|
5
5
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { App, Button, Card, Input, Space, Switch, Tooltip } from "antd";
|
|
6
|
+
import { App, Button, Card, Input, Space, Switch, Tag, Tooltip } from "antd";
|
|
7
7
|
import { useState } from "react";
|
|
8
8
|
import { useTranslation } from "react-i18next";
|
|
9
9
|
|
|
10
|
-
import { systemSettingsGet, systemSettingsPut } from "../../__client";
|
|
10
|
+
import { systemLoginMethodsGet, systemSettingsGet, systemSettingsPut } from "../../__client";
|
|
11
11
|
import { explainError, isForbidden } from "../errors";
|
|
12
12
|
import { ForbiddenPanel } from "../forbidden";
|
|
13
13
|
|
|
14
14
|
type SettingItem = SystemSettingsGetData[number]["items"][number];
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* 只动框架键(规格 §3):按 module 字段过滤,业务自定义键(如 wiki 的 mw_config)与 market.*(security 组,super-only 写)不进入。
|
|
18
|
+
* 登录方式(ldap/sso/wecom)不再作为可编辑设置,收敛为下方只读卡片(与 /login 同源)。
|
|
19
|
+
*/
|
|
20
|
+
const FRAMEWORK_MODULES = new Set(["framework"]);
|
|
18
21
|
|
|
19
22
|
/** 单项行:bool → Switch("1"/"0");secret → 只读 ***;其余 Input 失焦/回车保存 */
|
|
20
23
|
function SettingRow({ item, t, onSave }: { item: SettingItem, t: TFunction, onSave: (key: string, value: string) => void }) {
|
|
@@ -73,6 +76,7 @@ export default function SettingsPage() {
|
|
|
73
76
|
const queryClient = useQueryClient();
|
|
74
77
|
|
|
75
78
|
const query = useQuery({ queryKey: ["system", "settings"], queryFn: systemSettingsGet });
|
|
79
|
+
const loginMethodsQuery = useQuery({ queryKey: ["system", "login-methods"], queryFn: systemLoginMethodsGet });
|
|
76
80
|
|
|
77
81
|
const putMut = useMutation({
|
|
78
82
|
mutationFn: (body: { key: string, value: string }) => systemSettingsPut(body),
|
|
@@ -90,8 +94,17 @@ export default function SettingsPage() {
|
|
|
90
94
|
.map(g => ({ ...g, items: g.items.filter(i => FRAMEWORK_MODULES.has(i.module)) }))
|
|
91
95
|
.filter(g => g.items.length > 0);
|
|
92
96
|
|
|
97
|
+
const loginMethods = loginMethodsQuery.data?.methods ?? ["local"];
|
|
98
|
+
|
|
93
99
|
return (
|
|
94
100
|
<Space direction="vertical" style={{ width: "100%", paddingTop: 16 }}>
|
|
101
|
+
<Card title={t("system:setting.loginMethods")}>
|
|
102
|
+
<Space wrap>
|
|
103
|
+
{loginMethods.map(m => (
|
|
104
|
+
<Tag key={m}>{t(`login:method.${m}`, { defaultValue: m })}</Tag>
|
|
105
|
+
))}
|
|
106
|
+
</Space>
|
|
107
|
+
</Card>
|
|
95
108
|
{groups.map(g => (
|
|
96
109
|
<Card key={g.group} title={t(`system:setting.group.${g.group}`, { defaultValue: g.group })}>
|
|
97
110
|
<Space direction="vertical" style={{ width: "100%" }}>
|
|
@@ -12,7 +12,6 @@ const Departments = lazy(() => import("./pages/departments"));
|
|
|
12
12
|
const Roles = lazy(() => import("./pages/roles"));
|
|
13
13
|
const Oplog = lazy(() => import("./pages/oplog"));
|
|
14
14
|
const Settings = lazy(() => import("./pages/settings"));
|
|
15
|
-
const LoginMethods = lazy(() => import("./pages/login-methods"));
|
|
16
15
|
const WecomAdmin = lazy(() => import("./pages/wecom"));
|
|
17
16
|
|
|
18
17
|
/**
|
|
@@ -76,11 +75,6 @@ export const routes: AppRouteRecordRaw[] = [
|
|
|
76
75
|
Component: Settings,
|
|
77
76
|
handle: { title: "system:menu.settings", roles: ["superadmin"] },
|
|
78
77
|
},
|
|
79
|
-
{
|
|
80
|
-
path: "/system/login-methods",
|
|
81
|
-
Component: LoginMethods,
|
|
82
|
-
handle: { title: "system:menu.loginMethods" },
|
|
83
|
-
},
|
|
84
78
|
{
|
|
85
79
|
// 企微代开发后台(服务商运营面):仅超管可见(路由级 roles + 页面内二次判定)
|
|
86
80
|
path: "/system/wecom",
|
|
@@ -73,6 +73,39 @@ describe("cardGrid 卡片网格(BDD)", () => {
|
|
|
73
73
|
expect(screen.queryByTestId("card-license-alpha")).toBeNull();
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it("given 索引带 summary/description When 渲染 Then 卡片显示简介与描述(描述全文进 title 供查看)", () => {
|
|
77
|
+
const description = "详细描述:提供示例 CRUD、菜单路由与安装/升级/回滚全链路。";
|
|
78
|
+
renderWithProviders(
|
|
79
|
+
<CardGrid rows={[{ ...installed, summary: "一句话说清方案做什么", description }]} {...handlers} />,
|
|
80
|
+
new InMemoryMarketClient(),
|
|
81
|
+
);
|
|
82
|
+
expect(screen.getByTestId("card-summary-alpha").textContent).toContain("一句话说清方案做什么");
|
|
83
|
+
const desc = screen.getByTestId("card-description-alpha");
|
|
84
|
+
expect(desc.textContent).toContain(description);
|
|
85
|
+
expect(desc.getAttribute("title")).toBe(description);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("given 索引未声明 summary/description When 渲染 Then 卡片不出现简介/描述块(不显示占位符)", () => {
|
|
89
|
+
renderWithProviders(<CardGrid rows={[installed]} {...handlers} />, new InMemoryMarketClient());
|
|
90
|
+
expect(screen.queryByTestId("card-summary-alpha")).toBeNull();
|
|
91
|
+
expect(screen.queryByTestId("card-description-alpha")).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("given 索引带 publisher_key When 渲染 Then 卡片显示发布者(签出的 key_id,全文进 title)", () => {
|
|
95
|
+
renderWithProviders(
|
|
96
|
+
<CardGrid rows={[{ ...installed, publisher_key: "demo-solution.wecom-everpan" }]} {...handlers} />,
|
|
97
|
+
new InMemoryMarketClient(),
|
|
98
|
+
);
|
|
99
|
+
const pub = screen.getByTestId("card-publisher-alpha");
|
|
100
|
+
expect(pub.textContent).toContain("demo-solution.wecom-everpan");
|
|
101
|
+
expect(pub.getAttribute("title")).toBe("demo-solution.wecom-everpan");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("given 索引未声明 publisher_key When 渲染 Then 卡片不出现发布者行(不显示占位符)", () => {
|
|
105
|
+
renderWithProviders(<CardGrid rows={[installed]} {...handlers} />, new InMemoryMarketClient());
|
|
106
|
+
expect(screen.queryByTestId("card-publisher-alpha")).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
|
|
76
109
|
it("given 未安装卡片 When 渲染 Then 安装按钮显示「安装」而非「升级」,且无回滚按钮", () => {
|
|
77
110
|
renderWithProviders(<CardGrid rows={[notInstalled]} {...handlers} />, new InMemoryMarketClient());
|
|
78
111
|
expect(screen.getByText("安装")).toBeTruthy();
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { IndexRow } from "../types";
|
|
2
|
+
import { screen } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { DetailDrawer } from "../components/DetailDrawer";
|
|
5
|
+
import { InMemoryMarketClient } from "./marketClient.fake";
|
|
6
|
+
import { renderWithProviders } from "./render";
|
|
7
|
+
|
|
8
|
+
const row: IndexRow = {
|
|
9
|
+
name: "alpha",
|
|
10
|
+
latest: "1.2.0",
|
|
11
|
+
installed: "1.1.0",
|
|
12
|
+
enabled: true,
|
|
13
|
+
upgradable: true,
|
|
14
|
+
summary: "一站式客户管理",
|
|
15
|
+
description: "第一行:客户档案\n第二行:跟进记录与报表",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe("detailDrawer 方案详情(BDD)", () => {
|
|
19
|
+
const handlers = {
|
|
20
|
+
onClose: vi.fn(),
|
|
21
|
+
onInstall: vi.fn(),
|
|
22
|
+
onHistory: vi.fn(),
|
|
23
|
+
onRollback: vi.fn(),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
it("given 带 summary/description When 打开 Then 展示完整简介与描述(描述保留换行,卡片限行的全文在此)", () => {
|
|
27
|
+
renderWithProviders(
|
|
28
|
+
<DetailDrawer row={row} open canManage {...handlers} />,
|
|
29
|
+
new InMemoryMarketClient(),
|
|
30
|
+
);
|
|
31
|
+
expect(screen.getByText("简介")).toBeTruthy();
|
|
32
|
+
expect(screen.getByText("详细介绍")).toBeTruthy();
|
|
33
|
+
expect(screen.getByTestId("detail-summary").textContent).toBe(row.summary);
|
|
34
|
+
const desc = screen.getByTestId("detail-description");
|
|
35
|
+
expect(desc.textContent).toBe(row.description);
|
|
36
|
+
expect(desc.style.whiteSpace).toBe("pre-wrap");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("given 未声明 summary/description When 打开 Then 不出现这两行(不显示占位符)", () => {
|
|
40
|
+
renderWithProviders(
|
|
41
|
+
<DetailDrawer row={{ ...row, summary: undefined, description: undefined }} open canManage {...handlers} />,
|
|
42
|
+
new InMemoryMarketClient(),
|
|
43
|
+
);
|
|
44
|
+
expect(screen.queryByTestId("detail-summary")).toBeNull();
|
|
45
|
+
expect(screen.queryByTestId("detail-description")).toBeNull();
|
|
46
|
+
expect(screen.queryByText("简介")).toBeNull();
|
|
47
|
+
expect(screen.queryByText("详细介绍")).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("given 带 publisher_key When 打开 Then 详情展示发布者(签出的 key_id,长串可折行)", () => {
|
|
51
|
+
renderWithProviders(
|
|
52
|
+
<DetailDrawer row={{ ...row, publisher_key: "demo-solution.wecom-everpan.macbook" }} open canManage {...handlers} />,
|
|
53
|
+
new InMemoryMarketClient(),
|
|
54
|
+
);
|
|
55
|
+
expect(screen.getByText("发布者")).toBeTruthy();
|
|
56
|
+
const pub = screen.getByTestId("detail-publisher");
|
|
57
|
+
expect(pub.textContent).toBe("demo-solution.wecom-everpan.macbook");
|
|
58
|
+
expect(pub.style.wordBreak).toBe("break-all");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("given 未声明 publisher_key When 打开 Then 不出现发布者行(不显示占位符)", () => {
|
|
62
|
+
renderWithProviders(
|
|
63
|
+
<DetailDrawer row={{ ...row, publisher_key: undefined }} open canManage {...handlers} />,
|
|
64
|
+
new InMemoryMarketClient(),
|
|
65
|
+
);
|
|
66
|
+
expect(screen.queryByTestId("detail-publisher")).toBeNull();
|
|
67
|
+
expect(screen.queryByText("发布者")).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { MarketClient } from "../api/client";
|
|
2
2
|
// 内存实现 MarketClient(BDD 测试注入用,无需真实后端)。
|
|
3
|
-
import type { EnableInput, IndexRow, InstallInput, MarketHistory, TaskRecord, UninstallImpact } from "../types";
|
|
3
|
+
import type { EnableInput, IndexRow, InstallInput, MarketHistory, ReleasePage, TaskRecord, UninstallImpact } from "../types";
|
|
4
4
|
|
|
5
5
|
export interface FakeState {
|
|
6
6
|
indexRows?: IndexRow[]
|
|
7
7
|
indexError?: Error
|
|
8
8
|
taskRecord?: TaskRecord
|
|
9
9
|
historyRows?: MarketHistory[]
|
|
10
|
+
releasePage?: ReleasePage
|
|
10
11
|
impact?: UninstallImpact
|
|
11
12
|
enableResult?: { ok: boolean, message: string }
|
|
12
13
|
uninstallResult?: { ok: boolean, message: string }
|
|
@@ -65,6 +66,11 @@ export class InMemoryMarketClient implements MarketClient {
|
|
|
65
66
|
return this.state.historyRows ?? [];
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
async releases(input: { page?: number, limit?: number } = {}) {
|
|
70
|
+
this.calls.push(`releases:${input.page ?? 1}:${input.limit ?? 20}`);
|
|
71
|
+
return this.state.releasePage ?? { list: [], total: 0, page: 1, size: 20, syncError: null };
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
async uninstallImpact(name: string) {
|
|
69
75
|
this.calls.push(`uninstallImpact:${name}`);
|
|
70
76
|
return this.state.impact ?? { name, affectedRoles: 0, affectedUsers: 0 };
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
IndexRow,
|
|
11
11
|
InstallInput,
|
|
12
12
|
MarketHistory,
|
|
13
|
+
ReleasePage,
|
|
13
14
|
TaskRecord,
|
|
14
15
|
UninstallImpact,
|
|
15
16
|
} from "../types";
|
|
@@ -33,6 +34,8 @@ export interface MarketClient {
|
|
|
33
34
|
enable: (input: EnableInput) => Promise<{ ok: boolean, message: string }>
|
|
34
35
|
/** 市场操作历史(_platform 只读端点 /_platform/market/history) */
|
|
35
36
|
history: () => Promise<MarketHistory[]>
|
|
37
|
+
/** 发布历史(登录即可读;服务端每次读先与签名索引对账) */
|
|
38
|
+
releases: (input?: { page?: number, limit?: number }) => Promise<ReleasePage>
|
|
36
39
|
/** 卸载影响面预检(P3 U1;服务端返回供二次确认,P1-15a 补齐后接通) */
|
|
37
40
|
uninstallImpact: (name: string) => Promise<UninstallImpact>
|
|
38
41
|
/** 卸载(P1-15a 补齐后接通) */
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
IndexRow,
|
|
13
13
|
InstallInput,
|
|
14
14
|
MarketHistory,
|
|
15
|
+
ReleasePage,
|
|
15
16
|
TaskRecord,
|
|
16
17
|
UninstallImpact,
|
|
17
18
|
} from "../types";
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
platformMarketHistoryGet,
|
|
25
26
|
platformMarketInstallPost,
|
|
26
27
|
platformMarketMetaGet,
|
|
28
|
+
platformMarketReleasesGet,
|
|
27
29
|
platformMarketTaskGet,
|
|
28
30
|
platformMarketTrustPost,
|
|
29
31
|
platformMarketUninstallImpactGet,
|
|
@@ -109,6 +111,9 @@ export const httpMarketClient: MarketClient = {
|
|
|
109
111
|
async history() {
|
|
110
112
|
return (await platformMarketHistoryGet()) as unknown as MarketHistory[];
|
|
111
113
|
},
|
|
114
|
+
async releases(input: { page?: number, limit?: number } = {}) {
|
|
115
|
+
return (await platformMarketReleasesGet(input as { page: number, limit: number })) as unknown as ReleasePage;
|
|
116
|
+
},
|
|
112
117
|
async uninstallImpact(name: string) {
|
|
113
118
|
return (await platformMarketUninstallImpactGet({ name })) as unknown as UninstallImpact;
|
|
114
119
|
},
|
|
@@ -17,7 +17,9 @@ export interface CardItemProps {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* 单张方案卡片:方案简介/详细描述 + 版本/状态标识(enabled/disabled/upgradable)+ 动作按钮。
|
|
21
|
+
* 卡片上先展示 summary(单行)与 description(最多 3 行,完整文案见详情抽屉),让人不必点
|
|
22
|
+
* 详情就能判断方案提供什么;索引未声明这两项就不占位(与 license 同口径)。
|
|
21
23
|
* 双版本展示(P1-15b):已装且可升级时并列「已装 installed → 最新 latest」(upgradable 对比),
|
|
22
24
|
* 否则单版本。已装方案提供回滚入口(RollbackDialog 选旧版降级安装)。
|
|
23
25
|
*/
|
|
@@ -44,6 +46,35 @@ export function CardItem({ row, busy, canManage = true, onInstall, onEnableToggl
|
|
|
44
46
|
</Space>
|
|
45
47
|
)}
|
|
46
48
|
>
|
|
49
|
+
{/* 方案「提供什么」:summary 单行、description 限 3 行;title 与详情抽屉给全文 */}
|
|
50
|
+
{typeof row.summary === "string" && row.summary.trim() !== "" && (
|
|
51
|
+
<div
|
|
52
|
+
data-testid={`card-summary-${row.name}`}
|
|
53
|
+
title={row.summary}
|
|
54
|
+
style={{ marginBottom: 8, fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
|
|
55
|
+
>
|
|
56
|
+
{row.summary}
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
{typeof row.description === "string" && row.description.trim() !== "" && (
|
|
60
|
+
<div
|
|
61
|
+
data-testid={`card-description-${row.name}`}
|
|
62
|
+
title={row.description}
|
|
63
|
+
style={{
|
|
64
|
+
marginBottom: 12,
|
|
65
|
+
color: "var(--oo-text-secondary, #888)",
|
|
66
|
+
fontSize: 12,
|
|
67
|
+
lineHeight: 1.6,
|
|
68
|
+
display: "-webkit-box",
|
|
69
|
+
WebkitLineClamp: 3,
|
|
70
|
+
WebkitBoxOrient: "vertical",
|
|
71
|
+
overflow: "hidden",
|
|
72
|
+
whiteSpace: "pre-wrap",
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
{row.description}
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
47
78
|
<div style={{ minHeight: 40, color: "var(--oo-text-secondary, #888)", marginBottom: 12 }} data-testid={`card-versions-${row.name}`}>
|
|
48
79
|
{dualVersion
|
|
49
80
|
? (
|
|
@@ -85,6 +116,18 @@ export function CardItem({ row, busy, canManage = true, onInstall, onEnableToggl
|
|
|
85
116
|
</Tag>
|
|
86
117
|
</div>
|
|
87
118
|
)}
|
|
119
|
+
{/* 发布者:展示签出的 key_id(离线可验的发布身份);无签名就不占位 */}
|
|
120
|
+
{typeof row.publisher_key === "string" && row.publisher_key.trim() !== "" && (
|
|
121
|
+
<div
|
|
122
|
+
data-testid={`card-publisher-${row.name}`}
|
|
123
|
+
title={row.publisher_key}
|
|
124
|
+
style={{ marginBottom: 12, color: "var(--oo-text-secondary, #888)", fontSize: 12, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
|
|
125
|
+
>
|
|
126
|
+
{t("oj-market:card:publisher")}
|
|
127
|
+
:
|
|
128
|
+
{row.publisher_key}
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
88
131
|
<Space wrap>
|
|
89
132
|
<Button type="primary" size="small" loading={busy} onClick={() => onInstall(row)} disabled={busy || !canManage} title={manageTip}>
|
|
90
133
|
{installed ? t("oj-market:card:upgrade") : t("oj-market:card:install")}
|
|
@@ -14,7 +14,7 @@ export interface DetailDrawerProps {
|
|
|
14
14
|
onRollback: (row: IndexRow) => void
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/** 方案详情抽屉:只读展示卡片元信息(含双版本对比)+ 安装/回滚/历史入口 */
|
|
17
|
+
/** 方案详情抽屉:只读展示卡片元信息(含双版本对比)+ 完整简介/描述 + 安装/回滚/历史入口 */
|
|
18
18
|
export function DetailDrawer({ row, open, onClose, canManage = true, onInstall, onHistory, onRollback }: DetailDrawerProps) {
|
|
19
19
|
const { t } = useTranslation();
|
|
20
20
|
// 非 superadmin:写操作禁用并解释原因,历史(只读)保持可用。
|
|
@@ -38,6 +38,22 @@ export function DetailDrawer({ row, open, onClose, canManage = true, onInstall,
|
|
|
38
38
|
<Descriptions.Item label={t("oj-market:card:upgradable")}>
|
|
39
39
|
{row.upgradable ? <Tag color="gold">{t("oj-market:card:upgradable")}</Tag> : "-"}
|
|
40
40
|
</Descriptions.Item>
|
|
41
|
+
{typeof row.publisher_key === "string" && row.publisher_key.trim() !== "" && (
|
|
42
|
+
<Descriptions.Item label={t("oj-market:card:publisher")}>
|
|
43
|
+
<span data-testid="detail-publisher" style={{ wordBreak: "break-all" }}>{row.publisher_key}</span>
|
|
44
|
+
</Descriptions.Item>
|
|
45
|
+
)}
|
|
46
|
+
{/* 卡片上的 description 被限行,抽屉给全文(保留换行,长串不撑破抽屉) */}
|
|
47
|
+
{typeof row.summary === "string" && row.summary.trim() !== "" && (
|
|
48
|
+
<Descriptions.Item label={t("oj-market:card:summary")}>
|
|
49
|
+
<span data-testid="detail-summary">{row.summary}</span>
|
|
50
|
+
</Descriptions.Item>
|
|
51
|
+
)}
|
|
52
|
+
{typeof row.description === "string" && row.description.trim() !== "" && (
|
|
53
|
+
<Descriptions.Item label={t("oj-market:card:description")}>
|
|
54
|
+
<div data-testid="detail-description" style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}>{row.description}</div>
|
|
55
|
+
</Descriptions.Item>
|
|
56
|
+
)}
|
|
41
57
|
</Descriptions>
|
|
42
58
|
<Space style={{ marginTop: 16 }}>
|
|
43
59
|
<Button type="primary" onClick={() => onInstall(row)} disabled={!canManage} title={manageTip}>
|
|
@@ -1,12 +1,30 @@
|
|
|
1
|
+
import type { ModuleContext, ModuleI18n } from "@oj-module/runtime";
|
|
2
|
+
|
|
3
|
+
import { AppstoreOutlined } from "@ant-design/icons";
|
|
1
4
|
import { defineModule, OutsidePageIcon } from "@oj-module/runtime";
|
|
2
5
|
import { createElement } from "react";
|
|
3
6
|
import MarketApp from "./pages/MarketApp";
|
|
7
|
+
import { onInit as publishOnInit, routes as publishRoutes } from "./publish/routes";
|
|
4
8
|
|
|
5
9
|
// 方案市场前端模块(第一方专用,R29:消费 /api/_platform/market/* 编排面,第三方方案不得仿照此调用面)。
|
|
6
10
|
// 菜单标题走 i18next 命名空间语法 "<moduleName>:menu.<key>"(i18n 资源在 locales/,安装时随包注册)。
|
|
11
|
+
//
|
|
12
|
+
// **单模单根**(2026-11-05):菜单只有一个「方案市场」根,下挂三个子页——
|
|
13
|
+
// 方案清单(index)/ 发布管理(publish)/ 发布历史(history)。
|
|
14
|
+
// 「发布管理」与「发布历史」都归市场:发布身份是市场的准入面,页面随市场模块同版本发布、
|
|
15
|
+
// 同生命周期下线;子页路径是相对父路由声明的,实际 URL 为 /oj-market、/oj-market/publish、
|
|
16
|
+
// /oj-market/history。
|
|
17
|
+
const i18nNamespaces: Record<string, ModuleI18n> = {
|
|
18
|
+
// 发布页沿用原命名空间:`t("publish:…")` / 菜单 `publish:menu.publish` 零改动
|
|
19
|
+
publish: {
|
|
20
|
+
"zh-CN": () => import("./publish/locales/zh-CN.json"),
|
|
21
|
+
"en-US": () => import("./publish/locales/en-US.json"),
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
7
25
|
export default defineModule({
|
|
8
26
|
name: "oj-market",
|
|
9
|
-
description: "oj
|
|
27
|
+
description: "oj 方案市场应用——方案清单 / 发布管理 / 发布历史(第一方专用,R29)",
|
|
10
28
|
version: "0.1.0",
|
|
11
29
|
routes: [
|
|
12
30
|
{
|
|
@@ -21,8 +39,12 @@ export default defineModule({
|
|
|
21
39
|
{
|
|
22
40
|
index: true,
|
|
23
41
|
Component: MarketApp,
|
|
24
|
-
handle: {
|
|
42
|
+
handle: {
|
|
43
|
+
title: "oj-market:menu.list",
|
|
44
|
+
icon: createElement(AppstoreOutlined),
|
|
45
|
+
},
|
|
25
46
|
},
|
|
47
|
+
...publishRoutes,
|
|
26
48
|
],
|
|
27
49
|
},
|
|
28
50
|
],
|
|
@@ -30,4 +52,11 @@ export default defineModule({
|
|
|
30
52
|
"zh-CN": () => import("./locales/zh-CN.json"),
|
|
31
53
|
"en-US": () => import("./locales/en-US.json"),
|
|
32
54
|
},
|
|
55
|
+
i18nNamespaces,
|
|
56
|
+
lifecycle: {
|
|
57
|
+
/** 发布页的契约前缀 /publish + scoped request 在这里接线(与市场自身的 client 互不影响) */
|
|
58
|
+
async onInit(ctx: ModuleContext) {
|
|
59
|
+
publishOnInit(ctx);
|
|
60
|
+
},
|
|
61
|
+
},
|
|
33
62
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"menu": {
|
|
3
|
-
"main": "Market"
|
|
3
|
+
"main": "Market",
|
|
4
|
+
"list": "Solutions"
|
|
4
5
|
},
|
|
5
6
|
"perm": {
|
|
6
7
|
"view": "View solution market"
|
|
@@ -25,6 +26,9 @@
|
|
|
25
26
|
"retry": "Retry",
|
|
26
27
|
"version": "Version",
|
|
27
28
|
"license": "License",
|
|
29
|
+
"publisher": "Publisher",
|
|
30
|
+
"summary": "Summary",
|
|
31
|
+
"description": "Description",
|
|
28
32
|
"latest": "Latest",
|
|
29
33
|
"installed": "Installed",
|
|
30
34
|
"notInstalled": "Not installed",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"menu": {
|
|
3
|
-
"main": "方案市场"
|
|
3
|
+
"main": "方案市场",
|
|
4
|
+
"list": "方案清单"
|
|
4
5
|
},
|
|
5
6
|
"perm": {
|
|
6
7
|
"view": "查看方案市场"
|
|
@@ -25,6 +26,9 @@
|
|
|
25
26
|
"retry": "重试",
|
|
26
27
|
"version": "版本",
|
|
27
28
|
"license": "许可",
|
|
29
|
+
"publisher": "发布者",
|
|
30
|
+
"summary": "简介",
|
|
31
|
+
"description": "详细介绍",
|
|
28
32
|
"latest": "最新",
|
|
29
33
|
"installed": "已装",
|
|
30
34
|
"notInstalled": "未安装",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// 生成物:ojm api 从契约生成,勿手改(改动请改契约文件后重跑 ojm api)
|
|
3
|
+
// AC-D15:仅供 DEV 校验动态 import,生产构建不进产物
|
|
4
|
+
import { z } from "@oj-module/runtime";
|
|
5
|
+
|
|
6
|
+
export const schemas = {
|
|
7
|
+
"publishCredentialGet": {
|
|
8
|
+
query: z.object({
|
|
9
|
+
"page": z.number().min(1).optional(),
|
|
10
|
+
"limit": z.number().min(1).max(200).optional(),
|
|
11
|
+
"tenant": z.string().optional()
|
|
12
|
+
}),
|
|
13
|
+
data: z.object({
|
|
14
|
+
"list": z.array(z.object({
|
|
15
|
+
"id": z.number(),
|
|
16
|
+
"product": z.string(),
|
|
17
|
+
"key_id": z.string(),
|
|
18
|
+
"username": z.string(),
|
|
19
|
+
"display_name": z.string().nullable().optional(),
|
|
20
|
+
"token_hint": z.string(),
|
|
21
|
+
"status": z.enum(["active", "used", "revoked", "expired"]),
|
|
22
|
+
"expires_at": z.number(),
|
|
23
|
+
"used_at": z.number().nullable().optional(),
|
|
24
|
+
"created_at": z.number(),
|
|
25
|
+
"owner_tenant": z.string().optional()
|
|
26
|
+
})),
|
|
27
|
+
"total": z.number()
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
"publishCredentialPost": {
|
|
31
|
+
body: z.object({
|
|
32
|
+
"product": z.string()
|
|
33
|
+
}),
|
|
34
|
+
data: z.object({
|
|
35
|
+
"token": z.string(),
|
|
36
|
+
"key_id": z.string(),
|
|
37
|
+
"product": z.string(),
|
|
38
|
+
"token_hint": z.string().optional(),
|
|
39
|
+
"expires_at": z.number()
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
"publishCredentialRevokePost": {
|
|
43
|
+
body: z.object({
|
|
44
|
+
"id": z.number()
|
|
45
|
+
}),
|
|
46
|
+
data: z.object({
|
|
47
|
+
"ok": z.boolean()
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
"publishCredentialExchangePost": {
|
|
51
|
+
body: z.object({
|
|
52
|
+
"token": z.string()
|
|
53
|
+
}),
|
|
54
|
+
data: z.object({
|
|
55
|
+
"key_id": z.string(),
|
|
56
|
+
"product": z.string(),
|
|
57
|
+
"username": z.string(),
|
|
58
|
+
"display_name": z.string().nullable().optional()
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
};
|