openxiangda-cli 2.0.0-alpha.183 → 2.0.0-alpha.185

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 (39) hide show
  1. package/dist/commands/admin.d.ts.map +1 -1
  2. package/dist/commands/admin.js +5 -3
  3. package/dist/commands/admin.js.map +1 -1
  4. package/dist/commands/spec.js +1 -1
  5. package/dist/commands/spec.js.map +1 -1
  6. package/package.json +5 -5
  7. package/template/AGENTS.md +2 -2
  8. package/template/apps/web/e2e/README.md +7 -0
  9. package/template/apps/web/package.json +2 -2
  10. package/template/apps/web/playwright.config.ts +3 -5
  11. package/template/apps/web/vite.config.ts +1 -9
  12. package/template/appspec/app.md +5 -1
  13. package/template/package.json +1 -1
  14. package/template/apps/web/data-api-live.e2e.html +0 -15
  15. package/template/apps/web/e2e/client-fixture.ts +0 -5
  16. package/template/apps/web/e2e/component-defaults-fixture.css +0 -15
  17. package/template/apps/web/e2e/data-api-live-fixture.tsx +0 -162
  18. package/template/apps/web/e2e/data-api-live.spec.ts +0 -144
  19. package/template/apps/web/e2e/field-protocol-fixture.tsx +0 -387
  20. package/template/apps/web/e2e/field-protocol.spec.ts +0 -285
  21. package/template/apps/web/e2e/mobile-files.spec.ts +0 -96
  22. package/template/apps/web/e2e/mobile-reference-fixture.tsx +0 -314
  23. package/template/apps/web/e2e/mobile-reference.spec.ts +0 -360
  24. package/template/apps/web/e2e/mobile-selection.spec.ts +0 -199
  25. package/template/apps/web/e2e/resource-experience-fixture.tsx +0 -491
  26. package/template/apps/web/e2e/resource-platform-mock.ts +0 -202
  27. package/template/apps/web/e2e/resources.spec.ts +0 -488
  28. package/template/apps/web/e2e/standard-admin.spec.ts +0 -511
  29. package/template/apps/web/e2e/workflow-entry-fixture.tsx +0 -107
  30. package/template/apps/web/e2e/workflow-entry.spec.ts +0 -556
  31. package/template/apps/web/e2e/workflow-experience-fixture.tsx +0 -338
  32. package/template/apps/web/e2e/workflow.spec.ts +0 -1265
  33. package/template/apps/web/field-protocol.e2e.html +0 -22
  34. package/template/apps/web/mobile-reference.e2e.html +0 -27
  35. package/template/apps/web/resource-experience.e2e.html +0 -16
  36. package/template/apps/web/scripts/check.mjs +0 -43
  37. package/template/apps/web/test/contracts.test.ts +0 -163
  38. package/template/apps/web/workflow-entry.e2e.html +0 -15
  39. package/template/apps/web/workflow-experience.e2e.html +0 -15
@@ -1,338 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom/client';
3
- import {
4
- defineApplicationContributions,
5
- OpenXiangdaApplication,
6
- type AdminNavigationInput,
7
- type AdminPagesInput,
8
- type StandardApplicationTodoCenterProps,
9
- type StandardUserPageFrameProps,
10
- type StandardUserSurfaceContributions,
11
- } from 'openxiangda/react';
12
- import { useParams, useSearchParams } from 'react-router-dom';
13
- import { appCode } from '../../../packages/contracts/src/generated.js';
14
- import 'openxiangda/react/styles.css';
15
-
16
- const fixtureParams = new URLSearchParams(window.location.search);
17
- const standardSurfaceMode = fixtureParams.get('surfaces');
18
-
19
- const workflowDefinitions = [
20
- {
21
- code: 'purchase-approval',
22
- title: '采购审批',
23
- launch: { mode: 'standalone' },
24
- subject: {
25
- resourceCode: 'purchase-orders',
26
- factProjection: { amount: 'amount' },
27
- summaryFields: ['amount'],
28
- },
29
- processOperationCode: 'openxiangda.workflow.purchase-approval.submit',
30
- },
31
- ] as const;
32
-
33
- const resourceDefinitions = {
34
- 'purchase-orders': {
35
- code: 'purchase-orders',
36
- name: '采购申请',
37
- capabilities: {
38
- read: `app:${appCode}:data:purchase-orders:read`,
39
- create: `app:${appCode}:data:purchase-orders:create`,
40
- update: `app:${appCode}:data:purchase-orders:update`,
41
- delete: `app:${appCode}:data:purchase-orders:delete`,
42
- },
43
- surface: {
44
- mutationOwner: 'native',
45
- generated: { list: true, detail: true, create: true, update: true, delete: true },
46
- fields: {
47
- amount: {
48
- label: '申请金额',
49
- type: 'number.decimal',
50
- widget: 'money',
51
- requiredHint: true,
52
- readCapabilities: [`app:${appCode}:data:purchase-orders:read`],
53
- createCapabilities: [`app:${appCode}:data:purchase-orders:create`],
54
- updateCapabilities: [`app:${appCode}:data:purchase-orders:update`],
55
- },
56
- },
57
- form: { layout: 'flat', fieldOrder: ['amount'] },
58
- mobile: { enabled: true },
59
- },
60
- },
61
- } as const;
62
-
63
- const detailRoutes = {
64
- desktop: {
65
- code: 'purchase-detail',
66
- path: '/admin/operations/purchases/:instanceId',
67
- label: '采购审批详情',
68
- surface: 'admin',
69
- tabPersistence: 'none',
70
- keepAlive: 'none',
71
- },
72
- mobile: {
73
- code: 'purchase-detail-mobile',
74
- path: '/m/purchases/:instanceId',
75
- label: '移动采购审批详情',
76
- surface: 'user',
77
- tabPersistence: 'none',
78
- keepAlive: 'none',
79
- },
80
- } as const;
81
-
82
- function CustomWorkflowDetail() {
83
- const { instanceId } = useParams();
84
- const [search] = useSearchParams();
85
- return (
86
- <div data-testid="custom-workflow-detail">
87
- 自定义流程详情 {instanceId} / {search.get('taskId') || 'instance'}
88
- </div>
89
- );
90
- }
91
-
92
- function StandardFrame({
93
- back,
94
- canGoBack,
95
- children,
96
- device,
97
- pageKind,
98
- route,
99
- }: StandardUserPageFrameProps) {
100
- return (
101
- <section
102
- data-can-go-back={String(canGoBack)}
103
- data-page-kind={pageKind}
104
- data-route-code={route.routeCode}
105
- data-route-params={JSON.stringify(route.params)}
106
- data-testid={`standard-frame-${device}`}
107
- >
108
- <button onClick={back} type="button">返回</button>
109
- {children}
110
- </section>
111
- );
112
- }
113
-
114
- function CustomTodo({
115
- device,
116
- error,
117
- hasMore,
118
- items,
119
- loadMore,
120
- loading,
121
- loadingMore,
122
- openItem,
123
- query,
124
- refresh,
125
- setQuery,
126
- }: StandardApplicationTodoCenterProps) {
127
- return (
128
- <main data-testid={`custom-todo-${device}`}>
129
- <h1>{device === 'mobile' ? '移动应用待办' : '桌面应用待办'}</h1>
130
- <output data-testid="custom-todo-query">
131
- {query.view}/{String(query.unread)}/{query.keyword || 'all'}
132
- </output>
133
- {error ? <div role="alert">{error}</div> : null}
134
- <button onClick={() => void refresh()} type="button">刷新待办</button>
135
- <button
136
- onClick={() => setQuery({ unread: !query.unread })}
137
- type="button"
138
- >
139
- 切换未读
140
- </button>
141
- <ul aria-busy={loading || loadingMore}>
142
- {items.map(item => (
143
- <li key={item.messageId}>
144
- <button onClick={() => void openItem(item)} type="button">
145
- {item.title}
146
- </button>
147
- </li>
148
- ))}
149
- </ul>
150
- <button
151
- disabled={!hasMore || loadingMore}
152
- onClick={() => void loadMore()}
153
- type="button"
154
- >
155
- 加载更多
156
- </button>
157
- </main>
158
- );
159
- }
160
-
161
- function BrokenTodo(_props: StandardApplicationTodoCenterProps) {
162
- throw new Error('fixture standard user renderer failure');
163
- }
164
-
165
- const standardUserSurfaces: StandardUserSurfaceContributions | undefined =
166
- standardSurfaceMode
167
- ? {
168
- frame: { desktop: StandardFrame, mobile: StandardFrame },
169
- applicationTodoCenter: {
170
- desktop:
171
- standardSurfaceMode === 'error' ? BrokenTodo : CustomTodo,
172
- mobile: standardSurfaceMode === 'error' ? BrokenTodo : CustomTodo,
173
- },
174
- }
175
- : undefined;
176
-
177
- const applicationContributions = defineApplicationContributions(detailRoutes, {
178
- pages: {
179
- desktop: CustomWorkflowDetail,
180
- mobile: CustomWorkflowDetail,
181
- },
182
- ...(standardUserSurfaces ? { standardUserSurfaces } : {}),
183
- });
184
-
185
- const adminPages = [] as const satisfies AdminPagesInput;
186
-
187
- const routeManifest = {
188
- schemaVersion: 'openxiangda.application-route-manifest/v3',
189
- appCode,
190
- devicePolicy: {
191
- kind: 'viewport-family',
192
- mobileMaxWidthPx: 900,
193
- desktopMinWidthPx: 901,
194
- },
195
- rootEntry: { code: 'application-root', desktop: '/', mobile: '/m/' },
196
- authentication: {
197
- desktop: { routeCode: 'application-login', path: '/login' },
198
- mobile: { routeCode: 'application-login-mobile', path: '/m/login' },
199
- },
200
- routes: [
201
- {
202
- code: 'application:todo-center',
203
- kind: 'application-todo-center',
204
- desktop: {
205
- routeCode: 'application.todo-center.desktop',
206
- path: '/todos',
207
- surface: 'user',
208
- pathParams: [],
209
- requiresAuthentication: true,
210
- },
211
- mobile: {
212
- routeCode: 'application.todo-center.mobile',
213
- path: '/m/todos',
214
- surface: 'user',
215
- pathParams: [],
216
- requiresAuthentication: true,
217
- },
218
- },
219
- {
220
- code: 'workflow:work-center',
221
- kind: 'workflow-work-center',
222
- desktop: {
223
- routeCode: 'workflow.work.center.desktop',
224
- path: '/work-center',
225
- surface: 'user',
226
- pathParams: [],
227
- requiresAuthentication: true,
228
- },
229
- mobile: {
230
- routeCode: 'workflow.work.center.mobile',
231
- path: '/m/work-center',
232
- surface: 'user',
233
- pathParams: [],
234
- requiresAuthentication: true,
235
- },
236
- },
237
- {
238
- code: 'workflow:task',
239
- kind: 'workflow-task',
240
- desktop: {
241
- routeCode: 'workflow.task.desktop',
242
- path: '/tasks/:taskId',
243
- surface: 'user',
244
- pathParams: ['taskId'],
245
- requiresAuthentication: true,
246
- },
247
- mobile: {
248
- routeCode: 'workflow.task.mobile',
249
- path: '/m/tasks/:taskId',
250
- surface: 'user',
251
- pathParams: ['taskId'],
252
- requiresAuthentication: true,
253
- },
254
- },
255
- {
256
- code: 'workflow:instance',
257
- kind: 'workflow-instance',
258
- desktop: {
259
- routeCode: 'workflow.instance.desktop',
260
- path: '/workflows/:instanceId',
261
- surface: 'user',
262
- pathParams: ['instanceId'],
263
- requiresAuthentication: true,
264
- },
265
- mobile: {
266
- routeCode: 'workflow.instance.mobile',
267
- path: '/m/workflows/:instanceId',
268
- surface: 'user',
269
- pathParams: ['instanceId'],
270
- requiresAuthentication: true,
271
- },
272
- },
273
- {
274
- code: 'workflow:purchase-approval:launch',
275
- kind: 'workflow-launch',
276
- workflowCode: 'purchase-approval',
277
- desktop: {
278
- routeCode: 'workflow.purchase-approval.launch.desktop',
279
- path: '/workflows/:workflowCode/start',
280
- surface: 'user',
281
- pathParams: ['workflowCode'],
282
- requiresAuthentication: true,
283
- },
284
- mobile: {
285
- routeCode: 'workflow.purchase-approval.launch.mobile',
286
- path: '/m/workflows/:workflowCode/start',
287
- surface: 'user',
288
- pathParams: ['workflowCode'],
289
- requiresAuthentication: true,
290
- },
291
- },
292
- ],
293
- digest: '34cc08a02cd187a07d9e2d2f99c1080b5b86f3a4512f9e0f43ff4cb05b7195fa',
294
- } as const;
295
-
296
- const adminNavigation = [] as const satisfies AdminNavigationInput;
297
-
298
- const initialPath = fixtureParams.get('initial') || '/work-center';
299
- const runtimeBase = fixtureParams.get('base')?.trim();
300
- if (runtimeBase) {
301
- for (const [name, content] of [
302
- ['openxiangda-runtime-base', runtimeBase],
303
- ['openxiangda-app-code', appCode],
304
- ['openxiangda-environment', 'preproduction'],
305
- ] as const) {
306
- const meta =
307
- document.querySelector<HTMLMetaElement>(`meta[name="${name}"]`) ||
308
- document.createElement('meta');
309
- meta.name = name;
310
- meta.content = content;
311
- if (!meta.parentElement) document.head.appendChild(meta);
312
- }
313
- }
314
- if (location.pathname.endsWith('/workflow-experience.e2e.html')) {
315
- const stateToken = fixtureParams.get('state');
316
- history.replaceState(
317
- stateToken
318
- ? { usr: { routeNegotiationState: stateToken }, key: 'fixture-state' }
319
- : {},
320
- '',
321
- initialPath,
322
- );
323
- }
324
-
325
- ReactDOM.createRoot(document.getElementById('root')!).render(
326
- <React.StrictMode>
327
- <OpenXiangdaApplication
328
- appCode={appCode}
329
- appName="流程体验验收"
330
- adminNavigation={adminNavigation}
331
- adminPages={adminPages}
332
- routeManifest={routeManifest}
333
- contributions={applicationContributions}
334
- resourceDefinitions={resourceDefinitions}
335
- workflows={workflowDefinitions}
336
- />
337
- </React.StrictMode>
338
- );