openxiangda-cli 2.0.0-alpha.60 → 2.0.0-alpha.62

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.
Files changed (40) hide show
  1. package/dist/create-workspace.d.ts +1 -0
  2. package/dist/create-workspace.d.ts.map +1 -1
  3. package/dist/create-workspace.js +1 -0
  4. package/dist/create-workspace.js.map +1 -1
  5. package/package.json +4 -4
  6. package/template/AGENTS.md +1 -1
  7. package/template/README.md +7 -7
  8. package/template/apps/server/package.json +1 -1
  9. package/template/apps/server/src/app.module.ts +1 -3
  10. package/template/apps/server/test/smoke.test.ts +6 -23
  11. package/template/apps/web/e2e/resources.spec.ts +20 -0
  12. package/template/apps/web/index.html +1 -1
  13. package/template/apps/web/package.json +1 -1
  14. package/template/apps/web/scripts/check.mjs +5 -2
  15. package/template/apps/web/src/AuthoritativeSelector.tsx +38 -29
  16. package/template/apps/web/src/Shell.tsx +39 -211
  17. package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +1 -1
  18. package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +306 -0
  19. package/template/apps/web/src/components/resource/StandardResourcePages.tsx +431 -0
  20. package/template/apps/web/src/components/resource/SurfaceFields.tsx +500 -0
  21. package/template/apps/web/src/data-provider.ts +36 -31
  22. package/template/apps/web/src/main.tsx +24 -54
  23. package/template/apps/web/src/platform-client.ts +131 -382
  24. package/template/apps/web/src/runtime-meta.ts +1 -1
  25. package/template/apps/web/src/styles.css +100 -3
  26. package/template/apps/web/test/contracts.test.ts +31 -693
  27. package/template/openxiangda.config.ts +14 -81
  28. package/template/package.json +3 -3
  29. package/template/packages/contracts/src/generated.ts +7 -130
  30. package/template/apps/server/src/instrument-context.controller.ts +0 -25
  31. package/template/apps/web/e2e/instruments.spec.ts +0 -1338
  32. package/template/apps/web/src/CollegePage.tsx +0 -181
  33. package/template/apps/web/src/InstrumentDetailPage.tsx +0 -134
  34. package/template/apps/web/src/InstrumentForm.tsx +0 -575
  35. package/template/apps/web/src/InstrumentFormPage.tsx +0 -117
  36. package/template/apps/web/src/InstrumentListPage.tsx +0 -385
  37. package/template/apps/web/src/fields.ts +0 -83
  38. package/template/apps/web/src/instrument.ts +0 -55
  39. package/template/platform/data/colleges.ts +0 -21
  40. package/template/platform/data/instruments.ts +0 -81
@@ -1,96 +1,29 @@
1
1
  import { defineOpenXiangdaApp } from 'openxiangda-devkit-core';
2
- import {
3
- instruments,
4
- protectedFieldCapabilities,
5
- } from './platform/data/instruments.js';
6
- import { colleges } from './platform/data/colleges.js';
7
-
8
- const read = 'app:instrument-center:data:instruments:read';
9
- const create = 'app:instrument-center:data:instruments:create';
10
- const update = 'app:instrument-center:data:instruments:update';
11
- const remove = 'app:instrument-center:data:instruments:delete';
12
- const inspectContext = 'app:instrument-center:instrument:context:read';
13
- const directoryRead = 'app:instrument-center:directory:read';
14
- const collegeRead = 'app:instrument-center:data:colleges:read';
15
- const collegeCreate = 'app:instrument-center:data:colleges:create';
16
- const collegeUpdate = 'app:instrument-center:data:colleges:update';
17
- const allProtectedFieldCapabilities = Object.values(
18
- protectedFieldCapabilities
19
- ).flatMap(capabilities => [capabilities.create, capabilities.update]);
20
- const collegeCreateCapabilities = Object.values(
21
- protectedFieldCapabilities
22
- ).map(capabilities => capabilities.create);
23
- const collegeUpdateCapabilities = Object.entries(protectedFieldCapabilities)
24
- .filter(([field]) => field !== 'collegeId')
25
- .map(([, capabilities]) => capabilities.update);
26
2
 
3
+ /** Clean application scaffold: declare resources and fields, then generate CRUD. */
27
4
  export default defineOpenXiangdaApp({
28
5
  schemaVersion: 3,
29
- app: { code: 'instrument-center', name: '仪器资源管理' },
30
- frontend: {
31
- root: 'apps/web',
32
- routes: [
33
- { code: 'instruments', path: '/instruments', label: '仪器资源', surface: 'admin', navigation: 'menu', capability: read },
34
- { code: 'colleges', path: '/colleges', label: '学院字典', surface: 'admin', navigation: 'menu', capability: collegeRead },
35
- { code: 'instrument-create', path: '/instruments/new', label: '新增仪器', surface: 'admin', navigation: 'hidden', parentCode: 'instruments', capability: create },
36
- { code: 'instrument-edit', path: '/instruments/:id/edit', label: '编辑仪器', surface: 'admin', navigation: 'hidden', parentCode: 'instruments', capability: update },
37
- { code: 'instrument-detail', path: '/instruments/:id', label: '仪器详情', surface: 'admin', navigation: 'hidden', parentCode: 'instruments', capability: read },
38
- ],
39
- },
6
+ app: { code: 'openxiangda-application', name: 'OpenXiangda 应用' },
7
+ frontend: { root: 'apps/web', routes: [] },
40
8
  backend: {
41
9
  root: 'apps/server',
42
10
  runtime: 'node',
43
11
  framework: 'nestjs',
12
+ enabled: false,
44
13
  runMode: 'shared',
45
14
  secrets: [],
46
- operations: [
47
- {
48
- code: 'instrument-context.inspect',
49
- method: 'GET',
50
- path: '/api/instruments/context',
51
- capability: inspectContext,
52
- requestSchema: { type: 'object', additionalProperties: false },
53
- responseSchema: { type: 'object' },
54
- },
55
- ],
15
+ operations: [],
56
16
  },
57
17
  platform: { root: 'platform' },
58
18
  authz: {
59
- capabilities: [
60
- { code: inspectContext, kind: 'backend', name: '查看当前应用身份摘要' },
61
- ],
62
- roles: [
63
- { code: 'school_admin', name: '学校管理员', capabilities: [read, create, update, remove, collegeRead, collegeCreate, collegeUpdate, directoryRead, ...allProtectedFieldCapabilities, inspectContext] },
64
- { code: 'college_admin', name: '学院管理员', capabilities: [read, create, update, remove, directoryRead, ...collegeCreateCapabilities, ...collegeUpdateCapabilities, inspectContext] },
65
- { code: 'instrument_admin', name: '仪器管理员', capabilities: [read, update, directoryRead, inspectContext] },
66
- ],
67
- scopeDimensions: [
68
- {
69
- code: 'college',
70
- name: '学院',
71
- valueType: 'uuid',
72
- hierarchyMode: 'flat',
73
- valueSource: {
74
- kind: 'native_resource',
75
- resourceCode: 'colleges',
76
- labelField: 'name',
77
- enabledField: 'enabled',
78
- },
79
- },
80
- ],
81
- dataPolicies: [
82
- {
83
- code: 'instrument-access',
84
- name: '仪器数据范围',
85
- resourceCode: 'instruments',
86
- unrestrictedRoleCodes: ['school_admin'],
87
- matchMode: 'OR',
88
- rules: [
89
- { dimensionCode: 'college', field: 'collegeId', roleCodes: ['college_admin'] },
90
- { subject: 'current_user', field: 'instrumentAdminIds', roleCodes: ['instrument_admin'] },
91
- ],
92
- },
93
- ],
19
+ capabilities: [],
20
+ roles: [],
21
+ scopeDimensions: [],
22
+ scopeSources: [],
23
+ dataPolicies: [],
24
+ authorizationTransitions: [],
94
25
  },
95
- data: { resources: [colleges, instruments] },
26
+ data: { resources: [] },
27
+ events: { subscriptions: [], timers: [] },
28
+ workflows: { definitions: [], bindings: [], activations: [], providers: [], editableParameters: [] },
96
29
  });
@@ -21,9 +21,9 @@
21
21
  "build": "pnpm --recursive build"
22
22
  },
23
23
  "devDependencies": {
24
- "openxiangda-cli": "2.0.0-alpha.60",
25
- "openxiangda-contracts": "2.0.0-alpha.28",
26
- "openxiangda-devkit-core": "2.0.0-alpha.36",
24
+ "openxiangda-cli": "2.0.0-alpha.62",
25
+ "openxiangda-contracts": "2.0.0-alpha.30",
26
+ "openxiangda-devkit-core": "2.0.0-alpha.38",
27
27
  "typescript": "5.9.3"
28
28
  }
29
29
  }
@@ -1,31 +1,11 @@
1
1
  // Generated by OpenXiangda 2.0 Native compiler. Do not edit by hand.
2
2
  export const compilerContractVersion = "native-2" as const;
3
- export const appCode = "instrument-center" as const;
4
- export const resourceCodes = [
5
- "colleges",
6
- "instruments"
7
- ] as const;
3
+ export const appCode = "openxiangda-application" as const;
4
+ export const resourceCodes = [] as const;
5
+ export const resourceSurfaces = {} as const;
6
+ export const resourceDefinitions = {} as const;
8
7
  export const capabilities = [
9
- "app:instrument-center:data:colleges:create",
10
- "app:instrument-center:data:colleges:delete",
11
- "app:instrument-center:data:colleges:read",
12
- "app:instrument-center:data:colleges:update",
13
- "app:instrument-center:data:instruments:create",
14
- "app:instrument-center:data:instruments:delete",
15
- "app:instrument-center:data:instruments:read",
16
- "app:instrument-center:data:instruments:update",
17
- "app:instrument-center:directory:read",
18
- "app:instrument-center:instrument:context:read",
19
- "app:instrument-center:instrument:field:asset-code:create",
20
- "app:instrument-center:instrument:field:asset-code:update",
21
- "app:instrument-center:instrument:field:asset-value:create",
22
- "app:instrument-center:instrument:field:asset-value:update",
23
- "app:instrument-center:instrument:field:college-id:create",
24
- "app:instrument-center:instrument:field:college-id:update",
25
- "app:instrument-center:instrument:field:instrument-admin-ids:create",
26
- "app:instrument-center:instrument:field:instrument-admin-ids:update",
27
- "app:instrument-center:instrument:field:instrument-code:create",
28
- "app:instrument-center:instrument:field:instrument-code:update",
8
+ "app:openxiangda-application:directory:read",
29
9
  "app:role:assign",
30
10
  "app:role:define",
31
11
  "app:role:grant-capability",
@@ -33,71 +13,8 @@ export const capabilities = [
33
13
  "app:scope-grant:manage",
34
14
  "app:super-admin:manage"
35
15
  ] as const;
36
- export const appOperations = {
37
- instrumentContextInspect: {
38
- "code": "instrument-context.inspect",
39
- "method": "GET",
40
- "path": "/api/instruments/context",
41
- "requiredCapability": "app:instrument-center:instrument:context:read",
42
- "requestSchemaDigest": "cd1a463c46d6264134447db17a8c3c7abe5b9a2488c6d759fea66da1f96b133e",
43
- "responseSchemaDigest": "a2c799262a3ce3c19ef5cdd983bf3d12b43ab3c426227091b909dcb7054738c0"
44
- }
45
- } as const;
46
- export const appRoutes = {
47
- colleges: {
48
- "code": "colleges",
49
- "path": "/colleges",
50
- "label": "学院字典",
51
- "surface": "admin",
52
- "navigation": "menu",
53
- "capability": "app:instrument-center:data:colleges:read",
54
- "tabPersistence": "session",
55
- "keepAlive": "none"
56
- },
57
- instrumentCreate: {
58
- "code": "instrument-create",
59
- "path": "/instruments/new",
60
- "label": "新增仪器",
61
- "surface": "admin",
62
- "navigation": "hidden",
63
- "parentCode": "instruments",
64
- "capability": "app:instrument-center:data:instruments:create",
65
- "tabPersistence": "session",
66
- "keepAlive": "none"
67
- },
68
- instrumentDetail: {
69
- "code": "instrument-detail",
70
- "path": "/instruments/:id",
71
- "label": "仪器详情",
72
- "surface": "admin",
73
- "navigation": "hidden",
74
- "parentCode": "instruments",
75
- "capability": "app:instrument-center:data:instruments:read",
76
- "tabPersistence": "none",
77
- "keepAlive": "none"
78
- },
79
- instrumentEdit: {
80
- "code": "instrument-edit",
81
- "path": "/instruments/:id/edit",
82
- "label": "编辑仪器",
83
- "surface": "admin",
84
- "navigation": "hidden",
85
- "parentCode": "instruments",
86
- "capability": "app:instrument-center:data:instruments:update",
87
- "tabPersistence": "none",
88
- "keepAlive": "none"
89
- },
90
- instruments: {
91
- "code": "instruments",
92
- "path": "/instruments",
93
- "label": "仪器资源",
94
- "surface": "admin",
95
- "navigation": "menu",
96
- "capability": "app:instrument-center:data:instruments:read",
97
- "tabPersistence": "session",
98
- "keepAlive": "none"
99
- }
100
- } as const;
16
+ export const appOperations = {} as const;
17
+ export const appRoutes = {} as const;
101
18
  export const eventTypes = [] as const;
102
19
  export const eventSubscriptionCodes = [] as const;
103
20
  export const workflowCodes = [] as const;
@@ -109,43 +26,3 @@ export type AppRoute = (typeof appRoutes)[keyof typeof appRoutes];
109
26
  export type EventType = (typeof eventTypes)[number];
110
27
  export type EventSubscriptionCode = (typeof eventSubscriptionCodes)[number];
111
28
  export type WorkflowCode = (typeof workflowCodes)[number];
112
-
113
- export interface CollegesRecord {
114
- id: string;
115
- revision: number;
116
- name: string;
117
- enabled: boolean;
118
- }
119
-
120
- export interface InstrumentsRecord {
121
- id: string;
122
- revision: number;
123
- instrumentCode: string;
124
- chineseName: string;
125
- englishName?: string | null;
126
- aliasName?: string | null;
127
- image?: string | null;
128
- specModel: string;
129
- categoryId: string;
130
- instrumentSource?: string | null;
131
- manufacturer?: string | null;
132
- assetCode: string;
133
- assetValue?: number | null;
134
- enabledDate: string;
135
- usageStatus: string;
136
- instrumentStatus: string;
137
- openToOutside: boolean;
138
- subjectAreas?: unknown | null;
139
- platformProperty?: string | null;
140
- collegeId: string;
141
- manageDepartmentId: string;
142
- useDepartmentId: string;
143
- instrumentAdminIds: unknown;
144
- contactUserIds: unknown;
145
- contactPhone: string;
146
- contactEmail?: string | null;
147
- locationId?: string | null;
148
- address?: string | null;
149
- serviceContent?: string | null;
150
- attachments?: string | null;
151
- }
@@ -1,25 +0,0 @@
1
- import { Controller, Get, UseGuards } from '@nestjs/common';
2
- import { appOperations } from '@app/contracts';
3
- import {
4
- CurrentUser,
5
- OpenXiangdaAuthzGuard,
6
- OpenXiangdaOperation,
7
- type OpenXiangdaCurrentUser,
8
- } from 'openxiangda-nest';
9
-
10
- @Controller('api/instruments')
11
- @UseGuards(OpenXiangdaAuthzGuard)
12
- export class InstrumentContextController {
13
- @Get('context')
14
- @OpenXiangdaOperation(appOperations.instrumentContextInspect)
15
- inspect(@CurrentUser() user: OpenXiangdaCurrentUser) {
16
- // Intentionally read-only: this demonstrates local Nest business actions
17
- // without wrapping Data API CRUD.
18
- return {
19
- userId: user.userId,
20
- roleCodes: user.roleCodes,
21
- capabilityCodes: user.capabilityCodes,
22
- environmentKey: user.environmentKey,
23
- };
24
- }
25
- }