fix: resolve platform relation identities
This commit is contained in:
@@ -1195,6 +1195,8 @@ const contracts = [
|
||||
}
|
||||
];
|
||||
const source = fs.readFileSync('src/api/resources.ts', 'utf8');
|
||||
const backendContractSource = fs.readFileSync('../../backend/api/internal/logic/platform/resource.go', 'utf8');
|
||||
const backendRouterSource = fs.readFileSync('../../backend/api/internal/routers/platform.go', 'utf8');
|
||||
const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 } }).outputText;
|
||||
const resourceModule = { exports: {} };
|
||||
vm.runInNewContext(compiled, { module: resourceModule, exports: resourceModule.exports });
|
||||
@@ -1208,6 +1210,8 @@ function checkContracts() {
|
||||
const definition = resources.find((resource) => resource.name === contract.name);
|
||||
const label = `${contract.domain}/${contract.name}`;
|
||||
if (!definition || definition.resource !== contract.resource || definition.mode !== contract.mode || definition.pageKind !== contract.pageKind || !sameFields(definition.fields, contract.fields)) failures.push(`${label}: mismatched contract or allowlist`);
|
||||
if (!backendContractSource.includes(`Domain: "${contract.domain}"`) || !backendContractSource.includes(`Name: "${contract.name}"`)) failures.push(`${label}: absent from backend ExpectedResources`);
|
||||
if (contract.name !== 'saf_event_disposal' && !backendRouterSource.includes(contract.resource)) failures.push(`${label}: absent from backend router`);
|
||||
const requiredIdentity = contract.fields.filter((field) => field.required && field.key.endsWith('_identity')).map((field) => field.key);
|
||||
if (definition && JSON.stringify(definition.requiredIdentities ?? []) !== JSON.stringify(requiredIdentity)) failures.push(`${label}: required identity fields do not match allowlist`);
|
||||
if (contract.name === 'saf_event_disposal') continue;
|
||||
@@ -1224,7 +1228,7 @@ function checkContracts() {
|
||||
const readonlyPage = fs.readFileSync('src/views/shared/ReadOnlyListPage.vue', 'utf8');
|
||||
if (/(CrudListPage|resourceApi\\.(create|update|archive|updateStatus))/.test(readonlyPage)) failures.push('readonly shared page: contains write surface');
|
||||
const treePage = fs.readFileSync('src/views/shared/TreePage.vue', 'utf8');
|
||||
if (!treePage.includes('<a-tree') || !/parent_identity|parent_id/.test(treePage) || treePage.includes('CrudListPage')) failures.push('tree shared page: missing tree semantics');
|
||||
if (!treePage.includes('<a-tree') || !treePage.includes('parent_identity') || /\bparent_id\b|\bid\b/.test(treePage) || treePage.includes('CrudListPage')) failures.push('tree shared page: must be identity-first');
|
||||
for (const name of ['ec_category', 'platform_menu']) { const view = path.join('src/views', name === 'ec_category' ? 'ec' : 'platform', name, 'TreePage.vue'); if (!fs.existsSync(view)) failures.push(`${name}: must use TreePage`); }
|
||||
const safetyEvent = resources.find((resource) => resource.name === 'saf_event');
|
||||
if (!safetyEvent?.detailActions?.some((item) => item.name === 'saf_event_disposal' && item.resource === '/safety/saf_event/:identity/disposals')) failures.push('safety event: missing disposal detail action');
|
||||
|
||||
@@ -4,10 +4,10 @@ import { Message } from '@arco-design/web-vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { resourceApi } from '@/api/resource';
|
||||
import type { ResourceUiDefinition } from '@/api/resources';
|
||||
type Node = Record<string, unknown> & { identity: string; parent_identity?: string; id?: number; parent_id?: number; children: Node[] };
|
||||
type Node = Record<string, unknown> & { identity: string; parent_identity?: string; children: Node[] };
|
||||
const props = defineProps<{ definition: ResourceUiDefinition }>();
|
||||
const loading = ref(false); const list = ref<Node[]>([]);
|
||||
const tree = computed(() => { const byIdentity = new Map<string, Node>(); const byInternalId = new Map<number, Node>(); const roots: Node[] = []; list.value.forEach((item) => { const node = { ...item, children: [] }; byIdentity.set(node.identity, node); if (typeof node.id === 'number') byInternalId.set(node.id, node); }); byIdentity.forEach((item) => { const parent = item.parent_identity ? byIdentity.get(item.parent_identity) : typeof item.parent_id === 'number' ? byInternalId.get(item.parent_id) : undefined; if (parent) parent.children.push(item); else roots.push(item); }); return roots; });
|
||||
const tree = computed(() => { const byIdentity = new Map<string, Node>(); const roots: Node[] = []; list.value.forEach((item) => byIdentity.set(item.identity, { ...item, children: [] })); byIdentity.forEach((item) => { const parent = item.parent_identity ? byIdentity.get(item.parent_identity) : undefined; if (parent) parent.children.push(item); else roots.push(item); }); return roots; });
|
||||
async function load() { loading.value = true; try { list.value = (await resourceApi.list<Node>(props.definition.resource, 1, 500)).list; } catch (error) { Message.error((error as Error).message); } finally { loading.value = false; } }
|
||||
onMounted(load);
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user