cabloy 5.1.147 → 5.1.149
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/.cabloy-version +1 -1
- package/.claude/skills/cabloy-workflow/evals/evals.json +1 -1
- package/.claude/skills/cabloy-worktree-environment/SKILL.md +2 -5
- package/.claude/skills/cabloy-worktree-environment/evals/evals.json +1 -1
- package/CHANGELOG.md +17 -0
- package/package.json +1 -1
- package/repo-docs/.vitepress/config.mjs +4 -0
- package/repo-docs/backend/markdown-guide.md +1 -0
- package/repo-docs/backend/relations-guide.md +1 -0
- package/repo-docs/frontend/form-layout-guide.md +15 -1
- package/repo-docs/frontend/markdown-guide.md +1 -0
- package/repo-docs/frontend/scripts.md +11 -11
- package/repo-docs/fullstack/edition-collaboration-differences.md +1 -0
- package/repo-docs/fullstack/one-to-one-companion-resource-guide.md +447 -0
- package/repo-docs/fullstack/parallel-worktree-environment.md +4 -4
- package/repo-docs/fullstack/quickstart.md +4 -4
- package/repo-docs/reference/repo-scripts.md +12 -14
- package/repo-e2e/specs/cabloy-basic.spec.ts +176 -1
- package/vona/src/suite/a-training/modules/training-student/package.json +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +177 -103
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.index.ts +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/bean/meta.version.ts +19 -1
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/en-us.ts +3 -0
- package/vona/src/suite/a-training/modules/training-student/src/config/locale/zh-cn.ts +3 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +21 -2
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +7 -1
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +21 -2
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +21 -2
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +0 -3
- package/vona/src/suite/a-training/modules/training-student/src/entity/studentContent.tsx +36 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +6 -0
- package/vona/src/suite/a-training/modules/training-student/src/model/studentContent.ts +22 -0
- package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +63 -6
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +117 -7
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/pnpm-lock.yaml +19 -15
- package/zova/src/suite/a-training/modules/training-student/package.json +3 -1
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +40 -40
- package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +358 -337
- package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +18 -7
- package/zova/src/suite-vendor/a-zova/modules/a-form/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-form/src/lib/formLayout.ts +13 -5
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { IDecoratorEntityOptions } from 'vona-module-a-orm';
|
|
3
|
+
|
|
4
|
+
import { $makeMetadata, Api, v } from 'vona-module-a-openapiutils';
|
|
5
|
+
import { Entity, EntityBase } from 'vona-module-a-orm';
|
|
6
|
+
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
7
|
+
|
|
8
|
+
import { $locale } from '../.metadata/locales.ts';
|
|
9
|
+
|
|
10
|
+
export interface IEntityOptionsStudentContent extends IDecoratorEntityOptions {}
|
|
11
|
+
|
|
12
|
+
@Entity<IEntityOptionsStudentContent>('trainingStudentContent', {
|
|
13
|
+
openapi: { title: $locale('StudentContent') },
|
|
14
|
+
fields: {
|
|
15
|
+
id: $makeMetadata(ZovaRender.visible(false)),
|
|
16
|
+
iid: $makeMetadata(ZovaRender.visible(false)),
|
|
17
|
+
deleted: $makeMetadata(ZovaRender.visible(false)),
|
|
18
|
+
createdAt: $makeMetadata(ZovaRender.visible(false)),
|
|
19
|
+
updatedAt: $makeMetadata(ZovaRender.visible(false)),
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
export class EntityStudentContent extends EntityBase {
|
|
23
|
+
@Api.field(v.tableIdentity(), ZovaRender.visible(false))
|
|
24
|
+
studentId: TableIdentity;
|
|
25
|
+
|
|
26
|
+
@Api.field(
|
|
27
|
+
v.title($locale('DescriptionMarkdown')),
|
|
28
|
+
v.optional(),
|
|
29
|
+
ZovaRender.order(1),
|
|
30
|
+
ZovaRender.field('basic-markdown:formFieldMarkdown'),
|
|
31
|
+
)
|
|
32
|
+
descriptionMarkdown?: string;
|
|
33
|
+
|
|
34
|
+
@Api.field(v.title($locale('DescriptionHtml')), v.optional(), ZovaRender.visible(false))
|
|
35
|
+
descriptionHtml?: string;
|
|
36
|
+
}
|
|
@@ -22,6 +22,12 @@ export interface IModelOptionsStudent extends IDecoratorModelOptions<EntityStude
|
|
|
22
22
|
'description',
|
|
23
23
|
],
|
|
24
24
|
}),
|
|
25
|
+
studentContent: $relation.hasOne('training-student:studentContent', 'studentId', {
|
|
26
|
+
columns: ['id', 'studentId', 'descriptionMarkdown', 'descriptionHtml'],
|
|
27
|
+
}),
|
|
28
|
+
studentContentForm: $relation.hasOne('training-student:studentContent', 'studentId', {
|
|
29
|
+
columns: ['id', 'studentId', 'descriptionMarkdown'],
|
|
30
|
+
}),
|
|
25
31
|
},
|
|
26
32
|
})
|
|
27
33
|
export class ModelStudent extends BeanModelBase<EntityStudent> {}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IDecoratorModelOptions } from 'vona-module-a-orm';
|
|
2
|
+
|
|
3
|
+
import { $relation, BeanModelBase, Model } from 'vona-module-a-orm';
|
|
4
|
+
|
|
5
|
+
import { EntityStudentContent } from '../entity/studentContent.tsx';
|
|
6
|
+
|
|
7
|
+
export interface IModelOptionsStudentContent extends IDecoratorModelOptions<EntityStudentContent> {}
|
|
8
|
+
|
|
9
|
+
@Model<IModelOptionsStudentContent>({
|
|
10
|
+
entity: EntityStudentContent,
|
|
11
|
+
relations: {
|
|
12
|
+
student: $relation.belongsTo(
|
|
13
|
+
'training-student:studentContent',
|
|
14
|
+
'training-student:student',
|
|
15
|
+
'studentId',
|
|
16
|
+
),
|
|
17
|
+
},
|
|
18
|
+
cache: {
|
|
19
|
+
modelsClear: 'training-student:student',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
export class ModelStudentContent extends BeanModelBase<EntityStudentContent> {}
|
|
@@ -18,12 +18,27 @@ function getStudentRecordSubjectsInclude(): {
|
|
|
18
18
|
return { trainingRecords: { include: { trainingRecordSubjects: true } } };
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function getStudentContentFormInclude() {
|
|
22
|
+
return { studentContentForm: true };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getStudentContentInclude() {
|
|
26
|
+
return { studentContent: true };
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
@Service()
|
|
22
30
|
export class ServiceStudent extends BeanBase {
|
|
23
31
|
async create(student: DtoStudentCreate): Promise<EntityStudent> {
|
|
24
|
-
|
|
32
|
+
const { studentContentForm, ...studentFields } = student as DtoStudentCreate & {
|
|
33
|
+
studentContentForm?: { descriptionMarkdown?: string };
|
|
34
|
+
};
|
|
35
|
+
const created = await this.scope.model.student.insert(studentFields, {
|
|
25
36
|
include: getStudentRecordSubjectsInclude(),
|
|
26
37
|
});
|
|
38
|
+
if (studentContentForm !== undefined) {
|
|
39
|
+
await this._updateStudentContent(created.id, studentContentForm.descriptionMarkdown);
|
|
40
|
+
}
|
|
41
|
+
return created;
|
|
27
42
|
}
|
|
28
43
|
|
|
29
44
|
async select(params?: IQueryParams<ModelStudent>): Promise<DtoStudentSelectRes> {
|
|
@@ -32,20 +47,34 @@ export class ServiceStudent extends BeanBase {
|
|
|
32
47
|
|
|
33
48
|
async view(id: TableIdentity): Promise<DtoStudentView | undefined> {
|
|
34
49
|
return await this.scope.model.student.getById(id, {
|
|
35
|
-
include:
|
|
50
|
+
include: {
|
|
51
|
+
...getStudentRecordSubjectsInclude(),
|
|
52
|
+
...getStudentContentFormInclude(),
|
|
53
|
+
},
|
|
36
54
|
});
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
async update(id: TableIdentity, student: DtoStudentUpdate) {
|
|
40
|
-
|
|
58
|
+
const { studentContentForm, ...studentFields } = student as DtoStudentUpdate & {
|
|
59
|
+
studentContentForm?: { descriptionMarkdown?: string };
|
|
60
|
+
};
|
|
61
|
+
const updateResult = await this.scope.model.student.updateById(id, studentFields, {
|
|
41
62
|
include: getStudentRecordSubjectsInclude(),
|
|
42
63
|
});
|
|
64
|
+
if (studentContentForm !== undefined) {
|
|
65
|
+
await this._updateStudentContent(id, studentContentForm.descriptionMarkdown);
|
|
66
|
+
}
|
|
67
|
+
return updateResult;
|
|
43
68
|
}
|
|
44
69
|
|
|
45
70
|
async summary(id: TableIdentity): Promise<DtoStudentSummary | undefined> {
|
|
46
|
-
const student = await this.scope.model.student.getById(id
|
|
71
|
+
const student = await this.scope.model.student.getById(id, {
|
|
72
|
+
include: getStudentContentInclude(),
|
|
73
|
+
});
|
|
47
74
|
if (!student) return undefined;
|
|
48
|
-
const
|
|
75
|
+
const description = student.studentContent?.descriptionMarkdown;
|
|
76
|
+
const descriptionHtml = student.studentContent?.descriptionHtml;
|
|
77
|
+
const descriptionLength = description?.length ?? 0;
|
|
49
78
|
const levelTitle = String(student.level);
|
|
50
79
|
return {
|
|
51
80
|
id: student.id,
|
|
@@ -53,22 +82,50 @@ export class ServiceStudent extends BeanBase {
|
|
|
53
82
|
mobile: student.mobile,
|
|
54
83
|
level: student.level,
|
|
55
84
|
levelTitle,
|
|
56
|
-
description
|
|
85
|
+
description,
|
|
86
|
+
descriptionHtml,
|
|
57
87
|
descriptionLength,
|
|
58
88
|
summaryText: `${student.name} is in level ${student.level}. Description length: ${descriptionLength}.`,
|
|
59
89
|
};
|
|
60
90
|
}
|
|
61
91
|
|
|
62
92
|
async delete(id: TableIdentity) {
|
|
93
|
+
await this.scope.model.studentContent.delete({ studentId: id });
|
|
63
94
|
return await this.scope.model.student.deleteById(id, {
|
|
64
95
|
include: getStudentRecordSubjectsInclude(),
|
|
65
96
|
});
|
|
66
97
|
}
|
|
67
98
|
|
|
68
99
|
async deleteForce(id: TableIdentity) {
|
|
100
|
+
await this.scope.model.studentContent.delete({ studentId: id }, { disableDeleted: true });
|
|
69
101
|
return await this.scope.model.student.deleteById(id, {
|
|
70
102
|
disableDeleted: true,
|
|
71
103
|
include: getStudentRecordSubjectsInclude(),
|
|
72
104
|
});
|
|
73
105
|
}
|
|
106
|
+
|
|
107
|
+
private async _updateStudentContent(
|
|
108
|
+
studentId: TableIdentity,
|
|
109
|
+
descriptionMarkdown?: string,
|
|
110
|
+
): Promise<void> {
|
|
111
|
+
const markdown = descriptionMarkdown?.trim();
|
|
112
|
+
const studentContent = await this.scope.model.studentContent.get({ studentId });
|
|
113
|
+
if (!markdown) {
|
|
114
|
+
if (studentContent) await this.scope.model.studentContent.deleteById(studentContent.id);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const descriptionHtml = this.bean.markdown.renderHtml(markdown);
|
|
118
|
+
if (studentContent) {
|
|
119
|
+
await this.scope.model.studentContent.updateById(studentContent.id, {
|
|
120
|
+
descriptionMarkdown: markdown,
|
|
121
|
+
descriptionHtml,
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
await this.scope.model.studentContent.insert({
|
|
125
|
+
studentId,
|
|
126
|
+
descriptionMarkdown: markdown,
|
|
127
|
+
descriptionHtml,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
74
131
|
}
|
|
@@ -25,17 +25,36 @@ describe('student.test.ts', () => {
|
|
|
25
25
|
const formLayout =
|
|
26
26
|
blocks?.[0]?.options?.blocks?.[0]?.options?.blocks?.[0]?.options?.formLayout;
|
|
27
27
|
const tabs = formLayout?.children[0];
|
|
28
|
-
const
|
|
28
|
+
const groups = tabs?.children[0]?.children;
|
|
29
|
+
const profileSection = groups?.[0]?.children[0];
|
|
30
|
+
const studentContentSection = groups?.[1]?.children[0];
|
|
29
31
|
const trainingRecordsSection = tabs?.children[1]?.children[1];
|
|
30
32
|
assert.equal(tabs?.type, 'tabs');
|
|
31
33
|
assert.equal(tabs?.id, undefined);
|
|
32
34
|
assert.equal(tabs?.children[1]?.type, 'tab');
|
|
33
35
|
assert.equal(tabs?.children[1]?.id, undefined);
|
|
36
|
+
assert.equal(groups?.length, 2);
|
|
37
|
+
assert.deepEqual(
|
|
38
|
+
groups?.map(item => item.type),
|
|
39
|
+
['group', 'group'],
|
|
40
|
+
);
|
|
34
41
|
assert.deepEqual(profileSection?.columns, { default: 1, md: 2 });
|
|
35
42
|
assert.deepEqual(
|
|
36
43
|
profileSection?.children.map(item => item.name),
|
|
37
44
|
['name', 'mobile', 'imageId'],
|
|
38
45
|
);
|
|
46
|
+
assert.deepEqual(
|
|
47
|
+
studentContentSection?.children.map(item => item.name),
|
|
48
|
+
['studentContentForm'],
|
|
49
|
+
);
|
|
50
|
+
assert.equal(
|
|
51
|
+
component.properties.studentContentForm.rest.fieldSource,
|
|
52
|
+
'studentContentForm.descriptionMarkdown',
|
|
53
|
+
);
|
|
54
|
+
assert.equal(
|
|
55
|
+
component.properties.studentContentForm.rest.form.render,
|
|
56
|
+
'basic-markdown:formFieldMarkdown',
|
|
57
|
+
);
|
|
39
58
|
assert.equal(tabs?.children[1]?.children[0]?.name, 'level');
|
|
40
59
|
assert.deepEqual(
|
|
41
60
|
trainingRecordsSection?.children.map(item => item.name),
|
|
@@ -93,6 +112,7 @@ describe('student.test.ts', () => {
|
|
|
93
112
|
'mobile',
|
|
94
113
|
'level',
|
|
95
114
|
'description',
|
|
115
|
+
'descriptionHtml',
|
|
96
116
|
'levelTitle',
|
|
97
117
|
'descriptionLength',
|
|
98
118
|
'summaryText',
|
|
@@ -118,9 +138,13 @@ describe('student.test.ts', () => {
|
|
|
118
138
|
const maskedMobileUpdate = '139****4321';
|
|
119
139
|
const trainingTime = new Date('2026-03-10T08:00:00.000Z');
|
|
120
140
|
const trainingTimeUpdate = new Date('2026-04-18T13:20:00.000Z');
|
|
141
|
+
const description =
|
|
142
|
+
`# Student profile\n\n${'This is a long Markdown description. '.repeat(10)}`.trim();
|
|
143
|
+
const descriptionUpdate =
|
|
144
|
+
`## Updated profile\n\n${'This is updated Markdown content. '.repeat(10)}`.trim();
|
|
121
145
|
const data = {
|
|
122
146
|
name: '__Tom__',
|
|
123
|
-
|
|
147
|
+
studentContentForm: { descriptionMarkdown: description },
|
|
124
148
|
mobile,
|
|
125
149
|
level: 1,
|
|
126
150
|
trainingRecords: [
|
|
@@ -157,6 +181,7 @@ describe('student.test.ts', () => {
|
|
|
157
181
|
assert.equal(!!studentItem, true);
|
|
158
182
|
assert.equal(studentItem!.level, data.level);
|
|
159
183
|
assert.equal(studentItem!.mobile, maskedMobile);
|
|
184
|
+
assert.equal((studentItem as any).description, undefined);
|
|
160
185
|
// findMany: level filter
|
|
161
186
|
const selectResByLevel: DtoStudentSelectRes = await app.bean.executor.performAction(
|
|
162
187
|
'get',
|
|
@@ -182,6 +207,7 @@ describe('student.test.ts', () => {
|
|
|
182
207
|
const record = student.trainingRecords?.[0];
|
|
183
208
|
const recordSubject = record?.trainingRecordSubjects?.[0];
|
|
184
209
|
assert.equal(student.trainingRecords?.length, 1);
|
|
210
|
+
assert.equal(student.studentContentForm?.descriptionMarkdown, description);
|
|
185
211
|
assert.equal(record?.name, '__Record__');
|
|
186
212
|
assert.equal(record?.subjectCount, 1);
|
|
187
213
|
assert.equal(record?.totalScore, 88);
|
|
@@ -193,7 +219,7 @@ describe('student.test.ts', () => {
|
|
|
193
219
|
// update
|
|
194
220
|
const dataUpdate = {
|
|
195
221
|
name: '__TomNew__',
|
|
196
|
-
|
|
222
|
+
studentContentForm: { descriptionMarkdown: descriptionUpdate },
|
|
197
223
|
mobile: mobileUpdate,
|
|
198
224
|
level: 2,
|
|
199
225
|
trainingRecords: [
|
|
@@ -236,6 +262,7 @@ describe('student.test.ts', () => {
|
|
|
236
262
|
assert.equal(student.name, dataUpdate.name);
|
|
237
263
|
assert.equal(student.level, dataUpdate.level);
|
|
238
264
|
assert.equal(student.mobile, maskedMobileUpdate);
|
|
265
|
+
assert.equal(student.studentContentForm?.descriptionMarkdown, descriptionUpdate);
|
|
239
266
|
assert.equal(student.trainingRecords?.length, 1);
|
|
240
267
|
assert.equal(updatedRecord?.name, '__RecordNew__');
|
|
241
268
|
assert.equal(updatedRecord?.subjectCount, 2);
|
|
@@ -254,6 +281,15 @@ describe('student.test.ts', () => {
|
|
|
254
281
|
disableDeleted: true,
|
|
255
282
|
});
|
|
256
283
|
assert.equal(studentRaw!.mobile, mobileUpdate);
|
|
284
|
+
assert.equal((studentRaw as any).description, undefined);
|
|
285
|
+
const studentContent = await app
|
|
286
|
+
.scope('training-student')
|
|
287
|
+
.model.studentContent.get({ studentId });
|
|
288
|
+
assert.equal(studentContent?.descriptionMarkdown, descriptionUpdate);
|
|
289
|
+
assert.equal(
|
|
290
|
+
studentContent?.descriptionHtml,
|
|
291
|
+
app.bean.markdown.renderHtml(descriptionUpdate),
|
|
292
|
+
);
|
|
257
293
|
// summary
|
|
258
294
|
const summary: DtoStudentSummary = await app.bean.executor.performAction(
|
|
259
295
|
'get',
|
|
@@ -263,7 +299,9 @@ describe('student.test.ts', () => {
|
|
|
263
299
|
assert.equal(summary.name, dataUpdate.name);
|
|
264
300
|
assert.equal(summary.mobile, maskedMobileUpdate);
|
|
265
301
|
assert.equal(summary.level, dataUpdate.level);
|
|
266
|
-
assert.equal(summary.
|
|
302
|
+
assert.equal(summary.description, descriptionUpdate);
|
|
303
|
+
assert.equal(summary.descriptionHtml, app.bean.markdown.renderHtml(descriptionUpdate));
|
|
304
|
+
assert.equal(summary.descriptionLength, descriptionUpdate.length);
|
|
267
305
|
assert.equal(typeof summary.levelTitle, 'string');
|
|
268
306
|
assert.equal(typeof summary.summaryText, 'string');
|
|
269
307
|
// delete
|
|
@@ -294,11 +332,83 @@ describe('student.test.ts', () => {
|
|
|
294
332
|
disableDeleted: true,
|
|
295
333
|
});
|
|
296
334
|
assert.equal(studentForce, undefined);
|
|
335
|
+
assert.equal(
|
|
336
|
+
await app
|
|
337
|
+
.scope('training-student')
|
|
338
|
+
.model.studentContent.get({ studentId: studentIdForce }, { disableDeleted: true }),
|
|
339
|
+
undefined,
|
|
340
|
+
);
|
|
297
341
|
// logout
|
|
298
342
|
await app.bean.passport.signout();
|
|
299
343
|
});
|
|
300
344
|
});
|
|
301
345
|
|
|
346
|
+
it('action:student:contentPersistence', async () => {
|
|
347
|
+
await app.bean.executor.mockCtx(async () => {
|
|
348
|
+
await app.bean.passport.signinMock();
|
|
349
|
+
let studentId: string | undefined;
|
|
350
|
+
try {
|
|
351
|
+
studentId = await app.bean.executor.performAction('post', '/training/student', {
|
|
352
|
+
body: {
|
|
353
|
+
name: '__ContentStudent__',
|
|
354
|
+
mobile: '13812345678',
|
|
355
|
+
level: 1,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
assert.equal(
|
|
359
|
+
await app.scope('training-student').model.studentContent.get({ studentId }),
|
|
360
|
+
undefined,
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
await app.bean.executor.performAction('patch', '/training/student/:id', {
|
|
364
|
+
params: { id: studentId },
|
|
365
|
+
body: {
|
|
366
|
+
name: '__ContentStudent__',
|
|
367
|
+
mobile: '13812345678',
|
|
368
|
+
level: 1,
|
|
369
|
+
studentContentForm: {
|
|
370
|
+
descriptionMarkdown: ' ## Created later ',
|
|
371
|
+
descriptionHtml: '<p>Forged HTML</p>',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
const studentContent = await app
|
|
376
|
+
.scope('training-student')
|
|
377
|
+
.model.studentContent.get({ studentId });
|
|
378
|
+
assert.equal(studentContent?.descriptionMarkdown, '## Created later');
|
|
379
|
+
assert.equal(
|
|
380
|
+
studentContent?.descriptionHtml,
|
|
381
|
+
app.bean.markdown.renderHtml('## Created later'),
|
|
382
|
+
);
|
|
383
|
+
assert.notEqual(studentContent?.descriptionHtml, '<p>Forged HTML</p>');
|
|
384
|
+
|
|
385
|
+
await app.bean.executor.performAction('patch', '/training/student/:id', {
|
|
386
|
+
params: { id: studentId },
|
|
387
|
+
body: {
|
|
388
|
+
name: '__ContentStudent__',
|
|
389
|
+
mobile: '13812345678',
|
|
390
|
+
level: 1,
|
|
391
|
+
studentContentForm: { descriptionMarkdown: ' \n\t ' },
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
assert.equal(
|
|
395
|
+
await app.scope('training-student').model.studentContent.get({ studentId }),
|
|
396
|
+
undefined,
|
|
397
|
+
);
|
|
398
|
+
} finally {
|
|
399
|
+
if (studentId) {
|
|
400
|
+
await app
|
|
401
|
+
.scope('training-student')
|
|
402
|
+
.model.studentContent.delete({ studentId }, { disableDeleted: true });
|
|
403
|
+
await app
|
|
404
|
+
.scope('training-student')
|
|
405
|
+
.model.student.deleteById(studentId, { disableDeleted: true });
|
|
406
|
+
}
|
|
407
|
+
await app.bean.passport.signout();
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
302
412
|
it('action:student:systemAdmin', async () => {
|
|
303
413
|
await app.bean.executor.mockCtx(async () => {
|
|
304
414
|
await app.bean.passport.signinMock();
|
|
@@ -327,7 +437,7 @@ describe('student.test.ts', () => {
|
|
|
327
437
|
await app.bean.executor.performAction('post', '/training/student', {
|
|
328
438
|
body: {
|
|
329
439
|
name: '__Tom__',
|
|
330
|
-
|
|
440
|
+
studentContentForm: { descriptionMarkdown: 'This is a test' },
|
|
331
441
|
mobile: '13812345678',
|
|
332
442
|
level: 4,
|
|
333
443
|
},
|
|
@@ -344,7 +454,7 @@ describe('student.test.ts', () => {
|
|
|
344
454
|
await app.bean.executor.performAction('post', '/training/student', {
|
|
345
455
|
body: {
|
|
346
456
|
name: '__Tom__',
|
|
347
|
-
|
|
457
|
+
studentContentForm: { descriptionMarkdown: 'This is a test' },
|
|
348
458
|
level: 1,
|
|
349
459
|
},
|
|
350
460
|
});
|
|
@@ -360,7 +470,7 @@ describe('student.test.ts', () => {
|
|
|
360
470
|
await app.bean.executor.performAction('post', '/training/student', {
|
|
361
471
|
body: {
|
|
362
472
|
name: '__Tom__',
|
|
363
|
-
|
|
473
|
+
studentContentForm: { descriptionMarkdown: 'This is a test' },
|
|
364
474
|
mobile: '1381234567',
|
|
365
475
|
level: 1,
|
|
366
476
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zova",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.154",
|
|
4
4
|
"gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
|
|
5
5
|
"description": "A vue3 framework with ioc",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"zova-core": "^5.1.88",
|
|
49
|
-
"zova-suite-a-zova": "^5.1.
|
|
49
|
+
"zova-suite-a-zova": "^5.1.153"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"clean-package": "^2.2.0",
|
package/zova/pnpm-lock.yaml
CHANGED
|
@@ -77,7 +77,7 @@ importers:
|
|
|
77
77
|
version: 10.5.2(postcss@8.5.26)
|
|
78
78
|
axios:
|
|
79
79
|
specifier: ^1.18.1
|
|
80
|
-
version: 1.18.1
|
|
80
|
+
version: 1.18.1(supports-color@10.2.2)
|
|
81
81
|
compression:
|
|
82
82
|
specifier: ^1.8.1
|
|
83
83
|
version: 1.8.1
|
|
@@ -363,7 +363,7 @@ importers:
|
|
|
363
363
|
devDependencies:
|
|
364
364
|
'@cabloy/cli':
|
|
365
365
|
specifier: ^3.1.29
|
|
366
|
-
version: 3.1.29(vue@3.5.38(typescript@5.9.3))
|
|
366
|
+
version: 3.1.29(supports-color@10.2.2)(vue@3.5.38(typescript@5.9.3))
|
|
367
367
|
'@cabloy/lint':
|
|
368
368
|
specifier: ^5.1.32
|
|
369
369
|
version: 5.1.32(@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/rule-tester@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.62.1(typescript@5.9.3))(@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(oxfmt@0.62.0)(oxlint@1.77.0)(supports-color@10.2.2)(typescript@5.9.3)(vue-eslint-parser@10.4.1(eslint@10.6.0(jiti@2.7.0)))
|
|
@@ -438,7 +438,7 @@ importers:
|
|
|
438
438
|
dependencies:
|
|
439
439
|
'@cabloy/cli':
|
|
440
440
|
specifier: ^3.1.29
|
|
441
|
-
version: 3.1.29(vue@3.5.38(typescript@5.9.3))
|
|
441
|
+
version: 3.1.29(supports-color@10.2.2)(vue@3.5.38(typescript@5.9.3))
|
|
442
442
|
'@cabloy/process-helper':
|
|
443
443
|
specifier: ^3.1.8
|
|
444
444
|
version: 3.1.8
|
|
@@ -449,7 +449,7 @@ importers:
|
|
|
449
449
|
specifier: ^7.6.2
|
|
450
450
|
version: 7.8.5
|
|
451
451
|
zova-cli-set-front:
|
|
452
|
-
specifier: ^1.2.
|
|
452
|
+
specifier: ^1.2.102
|
|
453
453
|
version: link:../cli-set-front
|
|
454
454
|
devDependencies:
|
|
455
455
|
clean-package:
|
|
@@ -472,7 +472,7 @@ importers:
|
|
|
472
472
|
version: 7.29.7(@babel/core@7.29.7)
|
|
473
473
|
'@cabloy/cli':
|
|
474
474
|
specifier: ^3.1.29
|
|
475
|
-
version: 3.1.29(vue@3.5.38(typescript@5.9.3))
|
|
475
|
+
version: 3.1.29(supports-color@10.2.2)(vue@3.5.38(typescript@5.9.3))
|
|
476
476
|
'@cabloy/extend':
|
|
477
477
|
specifier: ^3.2.8
|
|
478
478
|
version: 3.2.8
|
|
@@ -1198,7 +1198,7 @@ importers:
|
|
|
1198
1198
|
dependencies:
|
|
1199
1199
|
axios:
|
|
1200
1200
|
specifier: ^1.18.1
|
|
1201
|
-
version: 1.18.1
|
|
1201
|
+
version: 1.18.1(supports-color@10.2.2)
|
|
1202
1202
|
devDependencies:
|
|
1203
1203
|
clean-package:
|
|
1204
1204
|
specifier: ^2.2.0
|
|
@@ -1471,7 +1471,7 @@ importers:
|
|
|
1471
1471
|
devDependencies:
|
|
1472
1472
|
'@cabloy/cli':
|
|
1473
1473
|
specifier: ^3.1.29
|
|
1474
|
-
version: 3.1.29(vue@3.5.38(typescript@5.9.3))
|
|
1474
|
+
version: 3.1.29(supports-color@10.2.2)(vue@3.5.38(typescript@5.9.3))
|
|
1475
1475
|
'@types/luxon':
|
|
1476
1476
|
specifier: ^3.7.1
|
|
1477
1477
|
version: 3.7.2
|
|
@@ -1804,6 +1804,10 @@ importers:
|
|
|
1804
1804
|
version: link:modules/training-student
|
|
1805
1805
|
|
|
1806
1806
|
src/suite/a-training/modules/training-student:
|
|
1807
|
+
dependencies:
|
|
1808
|
+
zova-module-basic-markdown:
|
|
1809
|
+
specifier: ^5.0.0
|
|
1810
|
+
version: link:../../../cabloy-basic/modules/basic-markdown
|
|
1807
1811
|
devDependencies:
|
|
1808
1812
|
clean-package:
|
|
1809
1813
|
specifier: ^2.2.0
|
|
@@ -8798,7 +8802,7 @@ snapshots:
|
|
|
8798
8802
|
|
|
8799
8803
|
'@bufbuild/protobuf@2.12.1': {}
|
|
8800
8804
|
|
|
8801
|
-
'@cabloy/cli@3.1.29(vue@3.5.38(typescript@5.9.3))':
|
|
8805
|
+
'@cabloy/cli@3.1.29(supports-color@10.2.2)(vue@3.5.38(typescript@5.9.3))':
|
|
8802
8806
|
dependencies:
|
|
8803
8807
|
'@babel/parser': 7.29.7
|
|
8804
8808
|
'@cabloy/module-glob': 5.3.18
|
|
@@ -8807,7 +8811,7 @@ snapshots:
|
|
|
8807
8811
|
'@cabloy/utils': 2.1.27
|
|
8808
8812
|
'@cabloy/word-utils': link:packages-utils/word-utils
|
|
8809
8813
|
'@npmcli/config': 10.11.0
|
|
8810
|
-
'@zhennann/common-bin': 4.0.1
|
|
8814
|
+
'@zhennann/common-bin': 4.0.1(supports-color@10.2.2)
|
|
8811
8815
|
'@zhennann/ejs': 3.0.1
|
|
8812
8816
|
boxen: 4.2.0
|
|
8813
8817
|
chalk: 3.0.0
|
|
@@ -11041,7 +11045,7 @@ snapshots:
|
|
|
11041
11045
|
|
|
11042
11046
|
'@vue/shared@3.5.13': {}
|
|
11043
11047
|
|
|
11044
|
-
'@zhennann/common-bin@4.0.1':
|
|
11048
|
+
'@zhennann/common-bin@4.0.1(supports-color@10.2.2)':
|
|
11045
11049
|
dependencies:
|
|
11046
11050
|
chalk: 4.1.2
|
|
11047
11051
|
change-case: 4.1.2
|
|
@@ -11075,7 +11079,7 @@ snapshots:
|
|
|
11075
11079
|
|
|
11076
11080
|
acorn@8.17.0: {}
|
|
11077
11081
|
|
|
11078
|
-
agent-base@6.0.2:
|
|
11082
|
+
agent-base@6.0.2(supports-color@10.2.2):
|
|
11079
11083
|
dependencies:
|
|
11080
11084
|
debug: 4.4.3(supports-color@10.2.2)
|
|
11081
11085
|
transitivePeerDependencies:
|
|
@@ -11187,11 +11191,11 @@ snapshots:
|
|
|
11187
11191
|
dependencies:
|
|
11188
11192
|
possible-typed-array-names: 1.1.0
|
|
11189
11193
|
|
|
11190
|
-
axios@1.18.1:
|
|
11194
|
+
axios@1.18.1(supports-color@10.2.2):
|
|
11191
11195
|
dependencies:
|
|
11192
11196
|
follow-redirects: 1.16.0
|
|
11193
11197
|
form-data: 4.0.6
|
|
11194
|
-
https-proxy-agent: 5.0.1
|
|
11198
|
+
https-proxy-agent: 5.0.1(supports-color@10.2.2)
|
|
11195
11199
|
proxy-from-env: 2.1.0
|
|
11196
11200
|
transitivePeerDependencies:
|
|
11197
11201
|
- debug
|
|
@@ -12604,9 +12608,9 @@ snapshots:
|
|
|
12604
12608
|
statuses: 2.0.2
|
|
12605
12609
|
toidentifier: 1.0.1
|
|
12606
12610
|
|
|
12607
|
-
https-proxy-agent@5.0.1:
|
|
12611
|
+
https-proxy-agent@5.0.1(supports-color@10.2.2):
|
|
12608
12612
|
dependencies:
|
|
12609
|
-
agent-base: 6.0.2
|
|
12613
|
+
agent-base: 6.0.2(supports-color@10.2.2)
|
|
12610
12614
|
debug: 4.4.3(supports-color@10.2.2)
|
|
12611
12615
|
transitivePeerDependencies:
|
|
12612
12616
|
- supports-color
|