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.
- package/dist/create-workspace.d.ts +1 -0
- package/dist/create-workspace.d.ts.map +1 -1
- package/dist/create-workspace.js +1 -0
- package/dist/create-workspace.js.map +1 -1
- package/package.json +4 -4
- package/template/AGENTS.md +1 -1
- package/template/README.md +7 -7
- package/template/apps/server/package.json +1 -1
- package/template/apps/server/src/app.module.ts +1 -3
- package/template/apps/server/test/smoke.test.ts +6 -23
- package/template/apps/web/e2e/resources.spec.ts +20 -0
- package/template/apps/web/index.html +1 -1
- package/template/apps/web/package.json +1 -1
- package/template/apps/web/scripts/check.mjs +5 -2
- package/template/apps/web/src/AuthoritativeSelector.tsx +38 -29
- package/template/apps/web/src/Shell.tsx +39 -211
- package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +1 -1
- package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +306 -0
- package/template/apps/web/src/components/resource/StandardResourcePages.tsx +431 -0
- package/template/apps/web/src/components/resource/SurfaceFields.tsx +500 -0
- package/template/apps/web/src/data-provider.ts +36 -31
- package/template/apps/web/src/main.tsx +24 -54
- package/template/apps/web/src/platform-client.ts +131 -382
- package/template/apps/web/src/runtime-meta.ts +1 -1
- package/template/apps/web/src/styles.css +100 -3
- package/template/apps/web/test/contracts.test.ts +31 -693
- package/template/openxiangda.config.ts +14 -81
- package/template/package.json +3 -3
- package/template/packages/contracts/src/generated.ts +7 -130
- package/template/apps/server/src/instrument-context.controller.ts +0 -25
- package/template/apps/web/e2e/instruments.spec.ts +0 -1338
- package/template/apps/web/src/CollegePage.tsx +0 -181
- package/template/apps/web/src/InstrumentDetailPage.tsx +0 -134
- package/template/apps/web/src/InstrumentForm.tsx +0 -575
- package/template/apps/web/src/InstrumentFormPage.tsx +0 -117
- package/template/apps/web/src/InstrumentListPage.tsx +0 -385
- package/template/apps/web/src/fields.ts +0 -83
- package/template/apps/web/src/instrument.ts +0 -55
- package/template/platform/data/colleges.ts +0 -21
- 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: '
|
|
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
|
-
|
|
61
|
-
],
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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: [
|
|
26
|
+
data: { resources: [] },
|
|
27
|
+
events: { subscriptions: [], timers: [] },
|
|
28
|
+
workflows: { definitions: [], bindings: [], activations: [], providers: [], editableParameters: [] },
|
|
96
29
|
});
|
package/template/package.json
CHANGED
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"build": "pnpm --recursive build"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"openxiangda-cli": "2.0.0-alpha.
|
|
25
|
-
"openxiangda-contracts": "2.0.0-alpha.
|
|
26
|
-
"openxiangda-devkit-core": "2.0.0-alpha.
|
|
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 = "
|
|
4
|
-
export const resourceCodes = [
|
|
5
|
-
|
|
6
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
}
|