openxiangda-cli 2.0.0-alpha.120 → 2.0.0-alpha.122
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda-cli",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.122",
|
|
4
4
|
"description": "Thin application-level CLI for OpenXiangda 2.0.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"openxiangda-contracts": "2.0.0-alpha.58",
|
|
25
25
|
"openxiangda-devkit-core": "2.0.0-alpha.76",
|
|
26
26
|
"openxiangda-mcp": "2.0.0-alpha.76",
|
|
27
|
-
"openxiangda-skill-kit": "2.0.0-alpha.
|
|
27
|
+
"openxiangda-skill-kit": "2.0.0-alpha.97"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"tsx": "4.23.12",
|
|
@@ -24,6 +24,36 @@ const field = (
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
const fields: DataResourceSurface['fields'] = {
|
|
27
|
+
departmentMultiple: field('构成部门', 'department.multiple', 'directory-department', {
|
|
28
|
+
list: true,
|
|
29
|
+
section: '组织信息',
|
|
30
|
+
}),
|
|
31
|
+
departmentSingle: field('牵头部门', 'department.single', 'directory-department', {
|
|
32
|
+
list: true,
|
|
33
|
+
section: '组织信息',
|
|
34
|
+
}),
|
|
35
|
+
userMultiple: field('小组成员', 'user.multiple', 'directory-user', {
|
|
36
|
+
list: true,
|
|
37
|
+
section: '组织信息',
|
|
38
|
+
}),
|
|
39
|
+
resourceMultiple: field('关联资源', 'resource-ref.multiple', 'resource', {
|
|
40
|
+
list: true,
|
|
41
|
+
section: '组织信息',
|
|
42
|
+
source: {
|
|
43
|
+
kind: 'resource',
|
|
44
|
+
resourceCode: 'resource-01',
|
|
45
|
+
labelField: 'name',
|
|
46
|
+
searchFields: ['name'],
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
enabled: field('启用状态', 'boolean', 'switch', {
|
|
50
|
+
list: true,
|
|
51
|
+
section: '组织信息',
|
|
52
|
+
}),
|
|
53
|
+
displayOrder: field('显示顺序', 'number.integer', 'number', {
|
|
54
|
+
list: true,
|
|
55
|
+
section: '组织信息',
|
|
56
|
+
}),
|
|
27
57
|
description: field('栏目说明', 'text.long', 'textarea', {
|
|
28
58
|
section: '栏目设置',
|
|
29
59
|
}),
|
|
@@ -107,6 +137,11 @@ const surface: DataResourceSurface = {
|
|
|
107
137
|
mobile: { enabled: true },
|
|
108
138
|
};
|
|
109
139
|
|
|
140
|
+
const { enabled, displayOrder, ...remainingFields } = fields;
|
|
141
|
+
const acceptanceSurface = new URLSearchParams(location.search).get('primary') === 'falsy'
|
|
142
|
+
? { ...surface, fields: { enabled, displayOrder, ...remainingFields } }
|
|
143
|
+
: surface;
|
|
144
|
+
|
|
110
145
|
const names = [
|
|
111
146
|
'内容栏目',
|
|
112
147
|
'内容文章',
|
|
@@ -135,7 +170,7 @@ const resourceDefinitions = Object.fromEntries(
|
|
|
135
170
|
update: `app:openxiangda-application:data:${code}:update`,
|
|
136
171
|
delete: `app:openxiangda-application:data:${code}:delete`,
|
|
137
172
|
},
|
|
138
|
-
surface,
|
|
173
|
+
surface: acceptanceSurface,
|
|
139
174
|
},
|
|
140
175
|
];
|
|
141
176
|
})
|
|
@@ -21,6 +21,27 @@ const definitions = resourceDefinitions as Record<string, DeclaredResource>;
|
|
|
21
21
|
const allCapabilities = [...capabilities] as string[];
|
|
22
22
|
const runtimeBase = `/view/${appCode}`;
|
|
23
23
|
|
|
24
|
+
const semanticResourceItem = {
|
|
25
|
+
id: 'group-1',
|
|
26
|
+
revision: 1,
|
|
27
|
+
updated_at: '2026-08-28T01:00:00.000Z',
|
|
28
|
+
departmentMultiple: [
|
|
29
|
+
{ label: '信息技术部', value: 'department-it' },
|
|
30
|
+
{ label: '人文艺术部', value: 'department-humanities' },
|
|
31
|
+
],
|
|
32
|
+
departmentSingle: { label: '校工会', value: 'department-union' },
|
|
33
|
+
userMultiple: [
|
|
34
|
+
{ label: '周明远', value: 'user-zhou', employeeNo: 'T1001' },
|
|
35
|
+
{ label: '沈书雅', value: 'user-shen', employeeNo: 'T1002' },
|
|
36
|
+
],
|
|
37
|
+
resourceMultiple: [
|
|
38
|
+
{ label: '教职工之家', value: 'resource-home', resourceCode: 'resource-01' },
|
|
39
|
+
{ label: '文体活动室', value: 'resource-activity', resourceCode: 'resource-01' },
|
|
40
|
+
],
|
|
41
|
+
enabled: false,
|
|
42
|
+
displayOrder: 0,
|
|
43
|
+
};
|
|
44
|
+
|
|
24
45
|
function runtimeAuthorization(authorized: boolean, superAdmin = false) {
|
|
25
46
|
return {
|
|
26
47
|
schemaVersion: 'openxiangda.runtime-authorization/v2',
|
|
@@ -62,6 +83,7 @@ async function mockPlatform(
|
|
|
62
83
|
authorized = true,
|
|
63
84
|
targetRuntimeBase = runtimeBase,
|
|
64
85
|
superAdmin = false,
|
|
86
|
+
queryItemsByResource: Record<string, Array<Record<string, unknown>>> = {},
|
|
65
87
|
) {
|
|
66
88
|
let contextReads = 0;
|
|
67
89
|
let avatarCompletes = 0;
|
|
@@ -162,6 +184,8 @@ async function mockPlatform(
|
|
|
162
184
|
}
|
|
163
185
|
const query = url.pathname.match(/\/native\/data\/([^/]+)\/query$/);
|
|
164
186
|
if (query) {
|
|
187
|
+
const resourceCode = decodeURIComponent(query[1]);
|
|
188
|
+
const items = queryItemsByResource[resourceCode] || [];
|
|
165
189
|
observed.push({ path: url.pathname, perspectiveCode });
|
|
166
190
|
return route.fulfill({
|
|
167
191
|
contentType: 'application/json',
|
|
@@ -169,11 +193,11 @@ async function mockPlatform(
|
|
|
169
193
|
code: 200,
|
|
170
194
|
data: {
|
|
171
195
|
schemaVersion: 'openxiangda.native-data-page/v2',
|
|
172
|
-
resourceCode
|
|
196
|
+
resourceCode,
|
|
173
197
|
appVersionId: 'app-version-1',
|
|
174
198
|
environmentHeadRevision: 1,
|
|
175
|
-
items
|
|
176
|
-
total:
|
|
199
|
+
items,
|
|
200
|
+
total: items.length,
|
|
177
201
|
limit: 500,
|
|
178
202
|
offset: 0,
|
|
179
203
|
},
|
|
@@ -379,6 +403,82 @@ test('keeps the user portal and namespaced generated admin resource in one route
|
|
|
379
403
|
await expect(page.locator('.oxa-sider')).toHaveCount(1);
|
|
380
404
|
});
|
|
381
405
|
|
|
406
|
+
test('renders canonical semantic labels in the real generated resource list', async ({ page }) => {
|
|
407
|
+
const resourceCode = 'resource-01';
|
|
408
|
+
await mockPlatform(page, true, runtimeBase, true, {
|
|
409
|
+
[resourceCode]: [semanticResourceItem],
|
|
410
|
+
});
|
|
411
|
+
await page.goto('/resource-experience.e2e.html');
|
|
412
|
+
await expect(page).toHaveURL(`/admin/resources/${resourceCode}`);
|
|
413
|
+
const row = page.getByRole('row').filter({ hasText: '信息技术部' });
|
|
414
|
+
await expect(row).toHaveCount(1);
|
|
415
|
+
for (const label of [
|
|
416
|
+
'信息技术部',
|
|
417
|
+
'人文艺术部',
|
|
418
|
+
'校工会',
|
|
419
|
+
'周明远',
|
|
420
|
+
'沈书雅',
|
|
421
|
+
'教职工之家',
|
|
422
|
+
'文体活动室',
|
|
423
|
+
]) {
|
|
424
|
+
await expect(row).toContainText(label);
|
|
425
|
+
}
|
|
426
|
+
await expect(row).not.toContainText('[object Object]');
|
|
427
|
+
await expect(row.getByRole('cell').nth(5)).toHaveText('否');
|
|
428
|
+
await expect(row.getByRole('cell').nth(6)).toHaveText('0');
|
|
429
|
+
await page.screenshot({
|
|
430
|
+
fullPage: true,
|
|
431
|
+
path: 'test-results/generated-resource-semantic-values-desktop.png',
|
|
432
|
+
});
|
|
433
|
+
await row.getByText('信息技术部', { exact: true }).click();
|
|
434
|
+
await expect(page).toHaveURL(`/admin/resources/${resourceCode}/group-1`);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test('renders the canonical first field on the mobile generated list', async ({ page }) => {
|
|
438
|
+
const resourceCode = 'resource-01';
|
|
439
|
+
await mockPlatform(page, true, runtimeBase, true, {
|
|
440
|
+
[resourceCode]: [semanticResourceItem],
|
|
441
|
+
});
|
|
442
|
+
await page.setViewportSize({ width: 390, height: 844 });
|
|
443
|
+
await page.goto('/resource-experience.e2e.html');
|
|
444
|
+
await page.evaluate(resource => {
|
|
445
|
+
history.pushState({}, '', `/m/admin/resources/${resource}`);
|
|
446
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
447
|
+
}, resourceCode);
|
|
448
|
+
const card = page.locator('.oxa-mobile-record-card').filter({ hasText: '信息技术部' });
|
|
449
|
+
await expect(card).toHaveCount(1);
|
|
450
|
+
await expect(card).toContainText('人文艺术部');
|
|
451
|
+
await expect(card).toContainText('校工会');
|
|
452
|
+
await expect(card).toContainText('周明远');
|
|
453
|
+
await expect(card).toContainText('教职工之家');
|
|
454
|
+
await expect(card).not.toContainText('[object Object]');
|
|
455
|
+
await page.screenshot({
|
|
456
|
+
fullPage: true,
|
|
457
|
+
path: 'test-results/generated-resource-semantic-values-mobile.png',
|
|
458
|
+
});
|
|
459
|
+
await card.getByText('信息技术部', { exact: true }).click();
|
|
460
|
+
await expect(page).toHaveURL(`/m/admin/resources/${resourceCode}/group-1`);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test('preserves false and zero when they lead the mobile generated list', async ({ page }) => {
|
|
464
|
+
const resourceCode = 'resource-01';
|
|
465
|
+
await mockPlatform(page, true, runtimeBase, true, {
|
|
466
|
+
[resourceCode]: [semanticResourceItem],
|
|
467
|
+
});
|
|
468
|
+
await page.setViewportSize({ width: 390, height: 844 });
|
|
469
|
+
await page.goto('/resource-experience.e2e.html?primary=falsy');
|
|
470
|
+
await page.evaluate(resource => {
|
|
471
|
+
history.pushState({}, '', `/m/admin/resources/${resource}`);
|
|
472
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
473
|
+
}, resourceCode);
|
|
474
|
+
const card = page.locator('.oxa-mobile-record-card');
|
|
475
|
+
await expect(card).toHaveCount(1);
|
|
476
|
+
await expect(card.locator('.oxa-mobile-record-heading')).toHaveText('否');
|
|
477
|
+
await expect(card.locator('.oxa-mobile-record-fields > div').filter({ hasText: '显示顺序' })).toContainText('0');
|
|
478
|
+
await card.locator('.oxa-mobile-record-heading').getByText('否', { exact: true }).click();
|
|
479
|
+
await expect(page).toHaveURL(`/m/admin/resources/${resourceCode}/group-1`);
|
|
480
|
+
});
|
|
481
|
+
|
|
382
482
|
test('fails closed on a direct operation route without its capability', async ({ page }) => {
|
|
383
483
|
await mockPlatform(page, false, runtimeBase, false);
|
|
384
484
|
await page.goto('/resource-experience.e2e.html');
|