cabloy 5.1.157 → 5.1.159
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-contract-loop/SKILL.md +24 -7
- package/.claude/skills/cabloy-contract-loop/evals/evals.json +12 -0
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +28 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +19 -2
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +18 -0
- package/.claude/skills/cabloy-zova-source-reading/SKILL.md +14 -0
- package/.claude/skills/cabloy-zova-source-reading/references/core-reading-paths.md +10 -0
- package/.github/workflows/docs-pages.yml +18 -2
- package/CHANGELOG.md +26 -0
- package/CONTRIBUTING.md +84 -0
- package/LICENSES.md +5 -0
- package/package.json +2 -1
- package/repo-docs/.vitepress/config.mjs +34 -4
- package/repo-docs/.vitepress/theme/components/GitHubRepositoriesNav.vue +255 -0
- package/repo-docs/.vitepress/theme/custom.css +21 -0
- package/repo-docs/.vitepress/theme/index.js +7 -1
- package/repo-docs/backend/resource-field-update.md +48 -1
- package/repo-docs/blogs/index.md +2 -0
- package/repo-docs/frontend/form-layout-guide.md +6 -6
- package/repo-docs/frontend/page-guide.md +12 -0
- package/repo-docs/frontend/page-meta-guide.md +27 -0
- package/repo-docs/frontend/ssr-architecture-overview.md +4 -0
- package/repo-docs/frontend/ssr-build-deploy-guide.md +1 -1
- package/repo-docs/frontend/zova-form-source-reading-map.md +2 -2
- package/repo-docs/frontend/zova-form-under-the-hood.md +1 -1
- package/repo-docs/frontend/zova-reactivity-under-the-hood.md +65 -9
- package/repo-docs/fullstack/contract-loop-playbook.md +2 -0
- package/repo-docs/fullstack/ssr-site-and-flavor-setup.md +198 -0
- package/repo-docs/fullstack/vona-zova-integration.md +2 -0
- package/repo-e2e/docs/playwright.config.ts +37 -0
- package/repo-e2e/docs/specs/blogs-index.spec.ts +180 -0
- package/repo-e2e/docs/specs/github-repositories-nav.spec.ts +69 -0
- package/repo-e2e/docs/test-results/.last-run.json +4 -0
- package/repo-e2e/specs/cabloy-basic.spec.ts +136 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/entity/{{resourceName}}.tsx_ +1 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/entity/{{resourceName}}.tsx_ +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +21 -80
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/en-us.ts +3 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/config/locale/zh-cn.ts +3 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productCreate.tsx +2 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productUpdate.tsx +2 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productView.tsx +2 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordCreate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordSelectReq.tsx +3 -7
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordUpdate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/dto/recordView.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-record/src/entity/record.tsx +8 -0
- package/vona/src/suite/a-training/modules/training-record/test/record.test.ts +51 -0
- 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 +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentSelectResItem.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +1 -0
- package/vona/src/suite/a-training/modules/training-student/src/entity/student.tsx +10 -1
- package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +99 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/src/bean/pipe.filter.ts +85 -57
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/cli/templates/rest/render.ts +2 -0
- package/zova/packages-cli/cli-set-front/cli/templates/rest/rest.ts +13 -3
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-zova/zova/package.json +2 -2
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockPage/controller.tsx +31 -11
- package/zova/src/suite/cabloy-basic/modules/basic-page/src/component/blockTable/controller.tsx +3 -0
- package/zova/src/suite/cabloy-basic/modules/basic-pageentry/src/component/blockPageEntry/controller.tsx +1 -1
- package/zova/src/suite/cabloy-basic/modules/basic-table/src/component/table/render.tsx +68 -8
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +4 -0
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- 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 +0 -6
- package/zova/src/suite-vendor/a-zova/modules/a-form/test/lib/formLayout.test.ts +16 -9
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +4 -0
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +13 -2
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/schema.ts +1 -0
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +50 -0
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/render.tsx +60 -7
- package/zova/src/suite-vendor/a-zova/modules/a-table/src/types/table.ts +6 -4
- package/zova/src/suite-vendor/a-zova/package.json +4 -4
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { AriaAttributes, CSSProperties } from 'vue';
|
|
2
|
+
|
|
1
3
|
import { FlexRender } from '@tanstack/vue-table';
|
|
2
4
|
import { BeanRenderBase } from 'zova';
|
|
3
5
|
import { Render } from 'zova-module-a-bean';
|
|
@@ -8,7 +10,14 @@ export class RenderTable<TData extends {} = {}> extends BeanRenderBase {
|
|
|
8
10
|
public render() {
|
|
9
11
|
return (
|
|
10
12
|
<ZTable
|
|
11
|
-
{
|
|
13
|
+
data={this.$props.data}
|
|
14
|
+
schema={this.$props.schema}
|
|
15
|
+
schemaOrder={this.$props.schemaOrder}
|
|
16
|
+
sorting={this.$props.sorting}
|
|
17
|
+
onSortingChange={this.$props.onSortingChange}
|
|
18
|
+
tableScope={this.$props.tableScope}
|
|
19
|
+
getColumns={this.$props.getColumns}
|
|
20
|
+
getRowId={this.$props.getRowId}
|
|
12
21
|
controllerRef={ref => {
|
|
13
22
|
this.$props?.tableRef?.(ref);
|
|
14
23
|
}}
|
|
@@ -19,6 +28,21 @@ export class RenderTable<TData extends {} = {}> extends BeanRenderBase {
|
|
|
19
28
|
);
|
|
20
29
|
}
|
|
21
30
|
|
|
31
|
+
private _getColumnStyle(column: any): CSSProperties {
|
|
32
|
+
const rest = (column.columnDef.meta as any)?.rest;
|
|
33
|
+
const fixed = column.getIsPinned();
|
|
34
|
+
const width = rest?.width ? `${rest.width}px` : undefined;
|
|
35
|
+
return {
|
|
36
|
+
width,
|
|
37
|
+
minWidth: width,
|
|
38
|
+
textAlign: rest?.align,
|
|
39
|
+
position: fixed ? ('sticky' as const) : undefined,
|
|
40
|
+
left: fixed === 'left' ? `${column.getStart('left')}px` : undefined,
|
|
41
|
+
right: fixed === 'right' ? `${column.getAfter('right')}px` : undefined,
|
|
42
|
+
zIndex: fixed ? 1 : undefined,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
22
46
|
public _renderTable($$table: ControllerTable<TData>) {
|
|
23
47
|
const table = $$table.table;
|
|
24
48
|
return (
|
|
@@ -26,12 +50,43 @@ export class RenderTable<TData extends {} = {}> extends BeanRenderBase {
|
|
|
26
50
|
<thead>
|
|
27
51
|
<tr>
|
|
28
52
|
{table.getFlatHeaders().map(header => {
|
|
53
|
+
const column = header.column;
|
|
54
|
+
const canSort = column.getCanSort();
|
|
55
|
+
const sorted = column.getIsSorted();
|
|
56
|
+
const fixed = column.getIsPinned();
|
|
57
|
+
const headerDefinition = column.columnDef.header;
|
|
58
|
+
const headerContent = (
|
|
59
|
+
<FlexRender render={headerDefinition} props={header.getContext()}></FlexRender>
|
|
60
|
+
);
|
|
61
|
+
let sortAria: AriaAttributes['aria-sort'] = 'none';
|
|
62
|
+
let sortIcon: '▲' | '▼' | '↕' = '↕';
|
|
63
|
+
if (sorted === 'asc') {
|
|
64
|
+
sortAria = 'ascending';
|
|
65
|
+
sortIcon = '▲';
|
|
66
|
+
} else if (sorted === 'desc') {
|
|
67
|
+
sortAria = 'descending';
|
|
68
|
+
sortIcon = '▼';
|
|
69
|
+
}
|
|
29
70
|
return (
|
|
30
|
-
<th
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
71
|
+
<th
|
|
72
|
+
key={header.id}
|
|
73
|
+
class={fixed ? 'bg-base-100' : undefined}
|
|
74
|
+
style={this._getColumnStyle(column)}
|
|
75
|
+
aria-sort={sortAria}
|
|
76
|
+
>
|
|
77
|
+
{canSort ? (
|
|
78
|
+
<button
|
|
79
|
+
type="button"
|
|
80
|
+
class="inline-flex w-full items-center gap-1"
|
|
81
|
+
onClick={column.getToggleSortingHandler()}
|
|
82
|
+
aria-label={`Sort by ${column.id}`}
|
|
83
|
+
>
|
|
84
|
+
{headerContent}
|
|
85
|
+
<span aria-hidden="true">{sortIcon}</span>
|
|
86
|
+
</button>
|
|
87
|
+
) : (
|
|
88
|
+
headerContent
|
|
89
|
+
)}
|
|
35
90
|
</th>
|
|
36
91
|
);
|
|
37
92
|
})}
|
|
@@ -42,10 +97,15 @@ export class RenderTable<TData extends {} = {}> extends BeanRenderBase {
|
|
|
42
97
|
return (
|
|
43
98
|
<tr key={row.id}>
|
|
44
99
|
{row.getVisibleCells().map(cell => {
|
|
100
|
+
const column = cell.column;
|
|
45
101
|
return (
|
|
46
|
-
<td
|
|
102
|
+
<td
|
|
103
|
+
key={cell.id}
|
|
104
|
+
class={column.getIsPinned() ? 'bg-base-100' : undefined}
|
|
105
|
+
style={this._getColumnStyle(column)}
|
|
106
|
+
>
|
|
47
107
|
<FlexRender
|
|
48
|
-
render={
|
|
108
|
+
render={column.columnDef.cell}
|
|
49
109
|
props={cell.getContext()}
|
|
50
110
|
></FlexRender>
|
|
51
111
|
</td>
|
|
@@ -57,6 +57,7 @@ export class ModelResource<
|
|
|
57
57
|
public schemaCreate?: ISchemaObjectExtensionField;
|
|
58
58
|
public schemaUpdate?: ISchemaObjectExtensionField;
|
|
59
59
|
public schemaFilter?: ISchemaObjectExtensionField;
|
|
60
|
+
public schemaOrder?: ISchemaObjectExtensionField;
|
|
60
61
|
public schemaRow?: ISchemaObjectExtensionField;
|
|
61
62
|
public schemaPages?: ISchemaObjectExtensionField;
|
|
62
63
|
|
|
@@ -87,6 +88,9 @@ export class ModelResource<
|
|
|
87
88
|
this.schemaFilter = this.$computed(() => {
|
|
88
89
|
return this.apiSchemasSelect.filter;
|
|
89
90
|
});
|
|
91
|
+
this.schemaOrder = this.$computed(() => {
|
|
92
|
+
return this.apiSchemasSelect.order;
|
|
93
|
+
});
|
|
90
94
|
this.schemaRow = this.$computed(() => {
|
|
91
95
|
return this.apiSchemasSelect.row;
|
|
92
96
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zova-suite-a-cabloy",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.51",
|
|
4
4
|
"gitHead": "4dece229b6d3f4735930e833afcb4b95ec51bf86",
|
|
5
5
|
"description": "",
|
|
6
6
|
"author": "",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "module",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"zova-module-a-rbac": "^5.0.1",
|
|
11
|
-
"zova-module-rest-resource": "^5.1.
|
|
11
|
+
"zova-module-rest-resource": "^5.1.50"
|
|
12
12
|
},
|
|
13
13
|
"title": "a-cabloy"
|
|
14
14
|
}
|
|
@@ -58,12 +58,6 @@ export function resolveFormLayout(
|
|
|
58
58
|
),
|
|
59
59
|
)
|
|
60
60
|
.filter(Boolean) as IResolvedFormLayoutNode[];
|
|
61
|
-
for (const property of properties ?? []) {
|
|
62
|
-
const name = property.key;
|
|
63
|
-
if (!name || !propertyNames.has(name) || fieldNames.has(name)) continue;
|
|
64
|
-
fieldNames.add(name);
|
|
65
|
-
children.push({ type: 'field', name });
|
|
66
|
-
}
|
|
67
61
|
return { children, fieldTabPaths, diagnostics };
|
|
68
62
|
}
|
|
69
63
|
|
|
@@ -76,6 +76,19 @@ test('Form Layout accepts every preserved alias for the same canonical source',
|
|
|
76
76
|
assert.deepEqual(resolved.diagnostics, []);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
test('Form Layout renders only explicitly declared visible fields', () => {
|
|
80
|
+
const resolved = resolveFormLayout(
|
|
81
|
+
createTabsLayout('name'),
|
|
82
|
+
createProperties({ key: 'name', type: 'string' }, { key: 'level', type: 'string' }),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
assert.deepEqual(getTabFieldNames(resolved), ['name']);
|
|
86
|
+
assert.deepEqual(resolved.fieldTabPaths, {
|
|
87
|
+
name: [{ tabsId: 'tabs-0', tabId: 'tab-0-0' }],
|
|
88
|
+
});
|
|
89
|
+
assert.deepEqual(resolved.diagnostics, []);
|
|
90
|
+
});
|
|
91
|
+
|
|
79
92
|
test('Form Layout prefers an exact canonical field over a colliding alias', () => {
|
|
80
93
|
const resolved = resolveFormLayout(
|
|
81
94
|
{ children: [{ type: 'field', name: 'content' }] },
|
|
@@ -89,10 +102,7 @@ test('Form Layout prefers an exact canonical field over a colliding alias', () =
|
|
|
89
102
|
),
|
|
90
103
|
);
|
|
91
104
|
|
|
92
|
-
assert.deepEqual(resolved.children, [
|
|
93
|
-
{ type: 'field', name: 'content' },
|
|
94
|
-
{ type: 'field', name: 'content.descriptionMarkdown' },
|
|
95
|
-
]);
|
|
105
|
+
assert.deepEqual(resolved.children, [{ type: 'field', name: 'content' }]);
|
|
96
106
|
assert.deepEqual(resolved.diagnostics, []);
|
|
97
107
|
});
|
|
98
108
|
|
|
@@ -131,17 +141,14 @@ test('Form Layout keeps ambiguous aliases and relation prefixes unknown', () =>
|
|
|
131
141
|
),
|
|
132
142
|
);
|
|
133
143
|
|
|
134
|
-
assert.deepEqual(resolved.children, [
|
|
135
|
-
{ type: 'field', name: 'content.descriptionMarkdown' },
|
|
136
|
-
{ type: 'field', name: 'content.descriptionHtml' },
|
|
137
|
-
]);
|
|
144
|
+
assert.deepEqual(resolved.children, []);
|
|
138
145
|
assert.deepEqual(resolved.diagnostics, [
|
|
139
146
|
{ type: 'unknownField', value: '_content' },
|
|
140
147
|
{ type: 'unknownField', value: 'content' },
|
|
141
148
|
]);
|
|
142
149
|
});
|
|
143
150
|
|
|
144
|
-
test('Form Layout does not resolve
|
|
151
|
+
test('Form Layout does not resolve invisible aliases', () => {
|
|
145
152
|
const resolved = resolveFormLayout(
|
|
146
153
|
{ children: [{ type: 'field', name: '_descriptionMarkdown' }] },
|
|
147
154
|
createProperties({
|
|
@@ -183,6 +183,10 @@ export class ModelSdk extends BeanModelBase {
|
|
|
183
183
|
const operationObject = sdk.data?.operationObject;
|
|
184
184
|
return getSchemaOfRequestQueryFilter(operationObject, { where: true });
|
|
185
185
|
},
|
|
186
|
+
get order() {
|
|
187
|
+
const operationObject = sdk.data?.operationObject;
|
|
188
|
+
return getSchemaOfRequestQueryFilter(operationObject, { order: true });
|
|
189
|
+
},
|
|
186
190
|
get requestBody() {
|
|
187
191
|
const operationObject = sdk.data?.operationObject;
|
|
188
192
|
const schemaBody = getSchemaOfRequestBody(operationObject);
|
|
@@ -15,13 +15,24 @@ export type TypeFormFieldOnEffect = (value: any) => void;
|
|
|
15
15
|
|
|
16
16
|
export interface ISchemaRenderComponentPresetRecord extends IResourceFormFieldRecord {}
|
|
17
17
|
|
|
18
|
-
export
|
|
18
|
+
export type TypeTableColumnAlign = 'left' | 'center' | 'right';
|
|
19
|
+
export type TypeTableColumnFixed = 'left' | 'right';
|
|
20
|
+
|
|
21
|
+
export interface ITableColumnOptions {
|
|
22
|
+
order?: number;
|
|
23
|
+
align?: TypeTableColumnAlign;
|
|
24
|
+
width?: number;
|
|
25
|
+
fixed?: TypeTableColumnFixed;
|
|
26
|
+
enableSorting?: boolean;
|
|
27
|
+
sortDescFirst?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ISchemaObjectExtensionFieldRest extends ITableColumnOptions {
|
|
19
31
|
'blocks'?: IResourceRenderBlockOptionsBlock[];
|
|
20
32
|
'schemaScene'?: TypeSchemaScene;
|
|
21
33
|
//
|
|
22
34
|
'fieldSource'?: string;
|
|
23
35
|
'visible'?: boolean;
|
|
24
|
-
'order'?: number;
|
|
25
36
|
'disableNotifyChanged'?: boolean;
|
|
26
37
|
'readonly'?: boolean;
|
|
27
38
|
'onEffect'?: TypeFormFieldOnEffect;
|
|
@@ -10,8 +10,11 @@ import { celEnvBase, isNilOrEmptyString } from '@cabloy/utils';
|
|
|
10
10
|
import {
|
|
11
11
|
CellContext,
|
|
12
12
|
createColumnHelper,
|
|
13
|
+
functionalUpdate,
|
|
13
14
|
getCoreRowModel,
|
|
15
|
+
OnChangeFn,
|
|
14
16
|
Row,
|
|
17
|
+
SortingState,
|
|
15
18
|
TableOptionsWithReactiveData,
|
|
16
19
|
} from '@tanstack/vue-table';
|
|
17
20
|
import { SchemaObject } from 'openapi3-ts/oas31';
|
|
@@ -48,6 +51,9 @@ import { ITableCellRenderColumnOptions } from '../../types/tableColumn.js';
|
|
|
48
51
|
export interface ControllerTableProps<TData extends {} = {}> {
|
|
49
52
|
data?: TData[];
|
|
50
53
|
schema?: SchemaObject;
|
|
54
|
+
schemaOrder?: SchemaObject;
|
|
55
|
+
sorting?: SortingState;
|
|
56
|
+
onSortingChange?: OnChangeFn<SortingState>;
|
|
51
57
|
tableScope?: ITableScope;
|
|
52
58
|
getColumns?: TypeTableGetColumns<TData>;
|
|
53
59
|
slotDefault?: (table: ControllerTable<TData>) => VNode;
|
|
@@ -95,9 +101,14 @@ export class ControllerTable<TData extends {} = {}> extends BeanControllerTableB
|
|
|
95
101
|
return this.$props.data;
|
|
96
102
|
}
|
|
97
103
|
|
|
104
|
+
public get sorting() {
|
|
105
|
+
return this.$props.sorting ?? [];
|
|
106
|
+
}
|
|
107
|
+
|
|
98
108
|
public async refreshMeta() {
|
|
99
109
|
this.tableMeta = await this._createTableMeta();
|
|
100
110
|
this.columns = await this._createColumns();
|
|
111
|
+
this.table?.setColumnPinning(this._getColumnPinning());
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
private _createTable() {
|
|
@@ -108,6 +119,22 @@ export class ControllerTable<TData extends {} = {}> extends BeanControllerTableB
|
|
|
108
119
|
getCoreRowModel: getCoreRowModel(),
|
|
109
120
|
renderFallbackValue: this.scope.config.renderFallbackValue,
|
|
110
121
|
manualPagination: true,
|
|
122
|
+
manualSorting: true,
|
|
123
|
+
enableMultiSort: false,
|
|
124
|
+
enableSortingRemoval: false,
|
|
125
|
+
state: {
|
|
126
|
+
get sorting() {
|
|
127
|
+
return self.sorting;
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
onSortingChange: updater => {
|
|
131
|
+
const sorting = functionalUpdate(updater, self.sorting).slice(0, 1);
|
|
132
|
+
self.$props.onSortingChange?.(sorting);
|
|
133
|
+
},
|
|
134
|
+
get initialState() {
|
|
135
|
+
const columnPinning = self._getColumnPinning();
|
|
136
|
+
return { columnPinning };
|
|
137
|
+
},
|
|
111
138
|
get data() {
|
|
112
139
|
return self.data || [];
|
|
113
140
|
},
|
|
@@ -116,6 +143,7 @@ export class ControllerTable<TData extends {} = {}> extends BeanControllerTableB
|
|
|
116
143
|
},
|
|
117
144
|
};
|
|
118
145
|
this.table = this.$useTable(tableOptions);
|
|
146
|
+
this.table.setColumnPinning(this._getColumnPinning());
|
|
119
147
|
}
|
|
120
148
|
|
|
121
149
|
private async _createColumns() {
|
|
@@ -162,12 +190,34 @@ export class ControllerTable<TData extends {} = {}> extends BeanControllerTableB
|
|
|
162
190
|
return property?.title || key;
|
|
163
191
|
},
|
|
164
192
|
cell: props => tableMeta.renders[key](props),
|
|
193
|
+
size: property.rest?.width,
|
|
194
|
+
enableSorting: property.rest?.enableSorting === true && this._isOrderable(property),
|
|
195
|
+
sortDescFirst: property.rest?.sortDescFirst === true,
|
|
196
|
+
meta: { rest: property.rest },
|
|
165
197
|
}),
|
|
166
198
|
);
|
|
167
199
|
}
|
|
168
200
|
return columns;
|
|
169
201
|
}
|
|
170
202
|
|
|
203
|
+
private _getColumnPinning() {
|
|
204
|
+
const left: string[] = [];
|
|
205
|
+
const right: string[] = [];
|
|
206
|
+
for (const property of this.tableMeta?.properties ?? []) {
|
|
207
|
+
const fixed = property.rest?.fixed;
|
|
208
|
+
if (fixed === 'left') left.push(property.key!);
|
|
209
|
+
if (fixed === 'right') right.push(property.key!);
|
|
210
|
+
}
|
|
211
|
+
return { left, right };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private _isOrderable(property: ISchemaObjectExtensionField) {
|
|
215
|
+
const properties = this.$props.schemaOrder?.properties;
|
|
216
|
+
if (!properties) return false;
|
|
217
|
+
const keys = [property.key, property.schemaKey, ...(property.schemaKeys ?? [])];
|
|
218
|
+
return keys.some(key => key && Object.prototype.hasOwnProperty.call(properties, key));
|
|
219
|
+
}
|
|
220
|
+
|
|
171
221
|
private _createProperties() {
|
|
172
222
|
this.properties = this.$computed(() => {
|
|
173
223
|
return this.$sdk.loadSchemaProperties(this.schema, 'table');
|
|
@@ -1,9 +1,26 @@
|
|
|
1
|
+
import type { AriaAttributes, CSSProperties } from 'vue';
|
|
2
|
+
|
|
1
3
|
import { FlexRender } from '@tanstack/vue-table';
|
|
2
4
|
import { BeanRenderBase } from 'zova';
|
|
3
5
|
import { Render } from 'zova-module-a-bean';
|
|
4
6
|
|
|
5
7
|
@Render()
|
|
6
8
|
export class RenderTable extends BeanRenderBase {
|
|
9
|
+
private _getColumnStyle(column: any): CSSProperties {
|
|
10
|
+
const rest = (column.columnDef.meta as any)?.rest;
|
|
11
|
+
const fixed = column.getIsPinned();
|
|
12
|
+
const width = rest?.width ? `${rest.width}px` : undefined;
|
|
13
|
+
return {
|
|
14
|
+
width,
|
|
15
|
+
minWidth: width,
|
|
16
|
+
textAlign: rest?.align,
|
|
17
|
+
position: fixed ? ('sticky' as const) : undefined,
|
|
18
|
+
left: fixed === 'left' ? `${column.getStart('left')}px` : undefined,
|
|
19
|
+
right: fixed === 'right' ? `${column.getAfter('right')}px` : undefined,
|
|
20
|
+
zIndex: fixed ? 1 : undefined,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
private _renderTableDefault() {
|
|
8
25
|
const table = this.table;
|
|
9
26
|
return (
|
|
@@ -11,12 +28,43 @@ export class RenderTable extends BeanRenderBase {
|
|
|
11
28
|
<thead>
|
|
12
29
|
<tr>
|
|
13
30
|
{table.getFlatHeaders().map(header => {
|
|
31
|
+
const column = header.column;
|
|
32
|
+
const canSort = column.getCanSort();
|
|
33
|
+
const sorted = column.getIsSorted();
|
|
34
|
+
const fixed = column.getIsPinned();
|
|
35
|
+
const headerDefinition = column.columnDef.header;
|
|
36
|
+
const headerContent = (
|
|
37
|
+
<FlexRender render={headerDefinition} props={header.getContext()}></FlexRender>
|
|
38
|
+
);
|
|
39
|
+
let sortAria: AriaAttributes['aria-sort'] = 'none';
|
|
40
|
+
let sortIcon: '▲' | '▼' | '↕' = '↕';
|
|
41
|
+
if (sorted === 'asc') {
|
|
42
|
+
sortAria = 'ascending';
|
|
43
|
+
sortIcon = '▲';
|
|
44
|
+
} else if (sorted === 'desc') {
|
|
45
|
+
sortAria = 'descending';
|
|
46
|
+
sortIcon = '▼';
|
|
47
|
+
}
|
|
14
48
|
return (
|
|
15
|
-
<th
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
<th
|
|
50
|
+
key={header.id}
|
|
51
|
+
class={fixed ? 'bg-base-100' : undefined}
|
|
52
|
+
style={this._getColumnStyle(column)}
|
|
53
|
+
aria-sort={sortAria}
|
|
54
|
+
>
|
|
55
|
+
{canSort ? (
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
class="inline-flex w-full items-center gap-1"
|
|
59
|
+
onClick={column.getToggleSortingHandler()}
|
|
60
|
+
aria-label={`Sort by ${column.id}`}
|
|
61
|
+
>
|
|
62
|
+
{headerContent}
|
|
63
|
+
<span aria-hidden="true">{sortIcon}</span>
|
|
64
|
+
</button>
|
|
65
|
+
) : (
|
|
66
|
+
headerContent
|
|
67
|
+
)}
|
|
20
68
|
</th>
|
|
21
69
|
);
|
|
22
70
|
})}
|
|
@@ -27,10 +75,15 @@ export class RenderTable extends BeanRenderBase {
|
|
|
27
75
|
return (
|
|
28
76
|
<tr key={row.id}>
|
|
29
77
|
{row.getVisibleCells().map(cell => {
|
|
78
|
+
const column = cell.column;
|
|
30
79
|
return (
|
|
31
|
-
<td
|
|
80
|
+
<td
|
|
81
|
+
key={cell.id}
|
|
82
|
+
class={column.getIsPinned() ? 'bg-base-100' : undefined}
|
|
83
|
+
style={this._getColumnStyle(column)}
|
|
84
|
+
>
|
|
32
85
|
<FlexRender
|
|
33
|
-
render={
|
|
86
|
+
render={column.columnDef.cell}
|
|
34
87
|
props={cell.getContext()}
|
|
35
88
|
></FlexRender>
|
|
36
89
|
</td>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ColumnDef, useVueTable } from '@tanstack/vue-table';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
ISchemaObjectExtensionField,
|
|
4
|
+
TypeTableCellRenderComponent,
|
|
5
|
+
} from 'zova-module-a-openapi';
|
|
4
6
|
|
|
5
7
|
import type { ControllerTable } from '../component/table/controller.jsx';
|
|
6
8
|
import type { TypeTableCellRender } from './tableColumn.js';
|
|
@@ -10,12 +12,12 @@ export type TypeTable<TData extends {} = {}> = ReturnType<typeof useVueTable<TDa
|
|
|
10
12
|
export type TypeColumn<TData extends {} = {}> = ColumnDef<TData, any>;
|
|
11
13
|
|
|
12
14
|
export interface ITableMeta<TData extends {} = {}> {
|
|
13
|
-
properties:
|
|
15
|
+
properties: ISchemaObjectExtensionField[];
|
|
14
16
|
renders: Record<string, TypeTableCellRender<TData>>;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export type TypeTableGetColumnsNext<TData extends {} = {}> = (
|
|
18
|
-
properties?:
|
|
20
|
+
properties?: ISchemaObjectExtensionField[],
|
|
19
21
|
) => Promise<TypeColumn<TData>[]>;
|
|
20
22
|
|
|
21
23
|
export type TypeTableCreateColumnRender<TData extends {} = {}> = (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zova-suite-a-zova",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.155",
|
|
4
4
|
"gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
|
|
5
5
|
"description": "zova",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
"zova-module-a-boundary": "^5.1.22",
|
|
17
17
|
"zova-module-a-command": "^5.1.34",
|
|
18
18
|
"zova-module-a-fetch": "^5.1.25",
|
|
19
|
-
"zova-module-a-form": "^5.1.
|
|
19
|
+
"zova-module-a-form": "^5.1.51",
|
|
20
20
|
"zova-module-a-icon": "^5.1.27",
|
|
21
21
|
"zova-module-a-interceptor": "^5.1.31",
|
|
22
22
|
"zova-module-a-logger": "^5.1.28",
|
|
23
23
|
"zova-module-a-meta": "^5.1.22",
|
|
24
24
|
"zova-module-a-model": "^5.1.36",
|
|
25
|
-
"zova-module-a-openapi": "^5.1.
|
|
25
|
+
"zova-module-a-openapi": "^5.1.52",
|
|
26
26
|
"zova-module-a-router": "^5.1.34",
|
|
27
27
|
"zova-module-a-routerstack": "^5.1.27",
|
|
28
28
|
"zova-module-a-routertabs": "^5.1.34",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"zova-module-a-ssrhmr": "^5.1.23",
|
|
31
31
|
"zova-module-a-ssrserver": "^5.1.26",
|
|
32
32
|
"zova-module-a-style": "^5.1.35",
|
|
33
|
-
"zova-module-a-table": "^5.1.
|
|
33
|
+
"zova-module-a-table": "^5.1.39",
|
|
34
34
|
"zova-module-a-zod": "^5.1.37",
|
|
35
35
|
"zova-module-a-zova": "^5.1.103"
|
|
36
36
|
},
|