openxiangda-cli 2.0.0-alpha.66 → 2.0.0-alpha.67
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
|
@@ -247,15 +247,21 @@ function AuditEntry({ entry, surface }: { entry: DataAuditEntry; surface: DataRe
|
|
|
247
247
|
|
|
248
248
|
function useGeneratedList(definition: GeneratedDefinition) {
|
|
249
249
|
const { code, surface } = definition;
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
};
|
|
250
|
+
const defaultSortField = surface.list?.defaultSort?.field || Object.keys(surface.fields)[0] || 'id';
|
|
251
|
+
const defaultSortOrder = surface.list?.defaultSort?.order || 'asc';
|
|
252
|
+
const defaultPageSize = surface.list?.defaultPageSize || 20;
|
|
254
253
|
const [page, setPage] = useState(1);
|
|
255
|
-
const [pageSize, setPageSize] = useState(
|
|
254
|
+
const [pageSize, setPageSize] = useState(defaultPageSize);
|
|
256
255
|
const [draft, setDraft] = useState<Partial<GenericResourceQuery>>({});
|
|
257
256
|
const [query, setQuery] = useState<Partial<GenericResourceQuery>>({});
|
|
258
|
-
const [sort, setSort] = useState({ field:
|
|
257
|
+
const [sort, setSort] = useState({ field: defaultSortField, order: defaultSortOrder as 'asc' | 'desc' });
|
|
258
|
+
useEffect(() => {
|
|
259
|
+
setPage(1);
|
|
260
|
+
setPageSize(defaultPageSize);
|
|
261
|
+
setDraft({});
|
|
262
|
+
setQuery({});
|
|
263
|
+
setSort({ field: defaultSortField, order: defaultSortOrder as 'asc' | 'desc' });
|
|
264
|
+
}, [code, defaultPageSize, defaultSortField, defaultSortOrder]);
|
|
259
265
|
const list = useList<ResourceRecord>({
|
|
260
266
|
resource: code,
|
|
261
267
|
pagination: { currentPage: page, pageSize },
|
|
@@ -278,9 +284,10 @@ export function GeneratedResourcePage({
|
|
|
278
284
|
if (!definition || definition.surface.generated === false) {
|
|
279
285
|
return <Result status="404" title="未声明可生成的资源页面" />;
|
|
280
286
|
}
|
|
281
|
-
|
|
282
|
-
if (mode === '
|
|
283
|
-
return <
|
|
287
|
+
const pageKey = `${variant}:${mode}:${resourceCode}`;
|
|
288
|
+
if (mode === 'list') return <GeneratedResourceListPage key={pageKey} definition={definition} variant={variant} />;
|
|
289
|
+
if (mode === 'detail') return <GeneratedResourceDetailPage key={pageKey} definition={definition} variant={variant} />;
|
|
290
|
+
return <GeneratedResourceFormPage key={pageKey} definition={definition} mode={mode} variant={variant} />;
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
function GeneratedResourceListPage({ definition, variant }: { definition: GeneratedDefinition; variant: 'desktop' | 'mobile' }) {
|
|
@@ -201,7 +201,11 @@ export function createNativeResourceClient(code: string, surface: DataResourceSu
|
|
|
201
201
|
}
|
|
202
202
|
for (const [fieldCode, value] of Object.entries(query.filters || {})) {
|
|
203
203
|
if (value === undefined || value === null || value === '') continue;
|
|
204
|
-
|
|
204
|
+
// A list state can outlive a resource route during client-side navigation.
|
|
205
|
+
// Ignore filters from the previous resource instead of constructing an
|
|
206
|
+
// invalid Native Data query for the current resource.
|
|
207
|
+
if (!declaredFields.has(fieldCode)) continue;
|
|
208
|
+
const field = surface.fields[fieldCode];
|
|
205
209
|
if (Array.isArray(value) && value.length === 2 && ['date', 'datetime', 'number', 'money', 'percent'].includes(field?.widget || '')) {
|
|
206
210
|
if (value[0] !== undefined && value[0] !== null && value[0] !== '') filters.push({ field: fieldCode, operator: 'gte', value: value[0] });
|
|
207
211
|
if (value[1] !== undefined && value[1] !== null && value[1] !== '') filters.push({ field: fieldCode, operator: 'lte', value: value[1] });
|
|
@@ -215,8 +219,10 @@ export function createNativeResourceClient(code: string, surface: DataResourceSu
|
|
|
215
219
|
};
|
|
216
220
|
return {
|
|
217
221
|
async list(query: GenericResourceQuery) {
|
|
218
|
-
const
|
|
219
|
-
const
|
|
222
|
+
const fallbackSort = surface.list?.defaultSort || { field: Object.keys(surface.fields)[0] || 'id', order: 'asc' as const };
|
|
223
|
+
const requestedSort = query.sort || fallbackSort;
|
|
224
|
+
const sort = declaredFields.has(requestedSort.field) ? requestedSort : fallbackSort;
|
|
225
|
+
const body: DataQuery = { schemaVersion: SCHEMA_VERSIONS.dataQuery, filters: filtersFor(query), order: [{ field: sort.field, direction: sort.order || 'asc' }], limit: query.pageSize, offset: (query.page - 1) * query.pageSize };
|
|
220
226
|
const page = await request<DataPage<Record<string, unknown>>>(`${base}/query`, { method: 'POST', body: JSON.stringify({ ...body, environmentKey: currentEnvironmentKey() }) });
|
|
221
227
|
return { rows: page.items, total: page.total };
|
|
222
228
|
},
|
|
@@ -35,6 +35,11 @@ test('standard surfaces keep authoritative directory/resource selectors and mobi
|
|
|
35
35
|
assert.match(crud, /text\/csv;charset=utf-8/);
|
|
36
36
|
assert.match(crud, /数据读取失败/);
|
|
37
37
|
assert.match(crud, /state\.list\.query\.refetch/);
|
|
38
|
+
assert.match(crud, /key=\{pageKey\}/);
|
|
39
|
+
assert.match(crud, /setQuery\(\{\}\)/);
|
|
40
|
+
const client = readFileSync(new URL('../src/platform-client.ts', import.meta.url), 'utf8');
|
|
41
|
+
assert.match(client, /declaredFields\.has\(requestedSort\.field\)/);
|
|
42
|
+
assert.match(client, /if \(!declaredFields\.has\(fieldCode\)\) continue/);
|
|
38
43
|
});
|
|
39
44
|
|
|
40
45
|
test('runtime metadata stays mount-scoped', () => {
|
package/template/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build": "pnpm --recursive build"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"openxiangda-cli": "2.0.0-alpha.
|
|
24
|
+
"openxiangda-cli": "2.0.0-alpha.67",
|
|
25
25
|
"openxiangda-contracts": "2.0.0-alpha.31",
|
|
26
26
|
"openxiangda-devkit-core": "2.0.0-alpha.41",
|
|
27
27
|
"typescript": "5.9.3"
|