fix hyper-links
This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
import { Show, SimpleShowLayout, TextField } from 'react-admin';
|
import { Show, SimpleShowLayout, TextField, NumberField } from 'react-admin';
|
||||||
|
|
||||||
export const EquipmentTypeShow = () => (
|
export const EquipmentTypeShow = () => (
|
||||||
<Show>
|
<Show>
|
||||||
<SimpleShowLayout>
|
<SimpleShowLayout>
|
||||||
<TextField source="code" label="code" />
|
<TextField source="code" label="Код вида оборудования" />
|
||||||
<TextField source="name" label="name" />
|
<TextField source="name" label="Наименование вида" />
|
||||||
<TextField source="manufacturer" label="manufacturer" />
|
<TextField source="manufacturer" label="Производитель" />
|
||||||
<TextField source="maintenanceIntervalHours" label="maintenanceIntervalHours" />
|
<NumberField source="maintenanceIntervalHours" label="Периодичность ТО, моточасов" />
|
||||||
<TextField source="overhaulIntervalHours" label="overhaulIntervalHours" />
|
<NumberField source="overhaulIntervalHours" label="Периодичность КР, моточасов" />
|
||||||
</SimpleShowLayout>
|
</SimpleShowLayout>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
import { Show, SimpleShowLayout, TextField } from 'react-admin';
|
import { Show, SimpleShowLayout, TextField, NumberField, DateField, SelectField, ReferenceField } from 'react-admin';
|
||||||
|
|
||||||
|
const statusChoices = [
|
||||||
|
{ id: 'Active', name: 'В эксплуатации' },
|
||||||
|
{ id: 'Repair', name: 'В ремонте' },
|
||||||
|
{ id: 'Reserve', name: 'В резерве' },
|
||||||
|
{ id: 'WriteOff', name: 'Списано' },
|
||||||
|
];
|
||||||
export const EquipmentShow = () => (
|
export const EquipmentShow = () => (
|
||||||
<Show>
|
<Show>
|
||||||
<SimpleShowLayout>
|
<SimpleShowLayout>
|
||||||
<TextField source="id" label="id" />
|
<TextField source="id" label="id" />
|
||||||
<TextField source="inventoryNumber" label="inventoryNumber" />
|
<TextField source="inventoryNumber" label="Инвентарный номер" />
|
||||||
<TextField source="serialNumber" label="serialNumber" />
|
<TextField source="serialNumber" label="Заводской (серийный) номер" />
|
||||||
<TextField source="name" label="name" />
|
<TextField source="name" label="Наименование единицы оборудования" />
|
||||||
<TextField source="equipmentTypeCode" label="equipmentTypeCode" />
|
<ReferenceField source="equipmentTypeCode" reference="equipment-types" label="Вид оборудования" link="show">
|
||||||
<TextField source="status" label="status" />
|
<TextField source="code" />
|
||||||
<TextField source="location" label="location" />
|
</ReferenceField>
|
||||||
<TextField source="commissionedAt" label="commissionedAt" />
|
<SelectField source="status" label="Текущий статус" choices={statusChoices} />
|
||||||
<TextField source="totalEngineHours" label="totalEngineHours" />
|
<TextField source="location" label="Место эксплуатации / скважина / куст" />
|
||||||
<TextField source="engineHoursSinceLastRepair" label="engineHoursSinceLastRepair" />
|
<DateField source="commissionedAt" label="Дата ввода в эксплуатацию" />
|
||||||
<TextField source="lastRepairAt" label="lastRepairAt" />
|
<NumberField source="totalEngineHours" label="Общая наработка, моточасов" />
|
||||||
<TextField source="notes" label="notes" />
|
<NumberField source="engineHoursSinceLastRepair" label="Наработка с последнего ремонта, моточасов" />
|
||||||
|
<DateField source="lastRepairAt" label="Дата последнего ремонта" />
|
||||||
|
<TextField source="notes" label="Примечания" />
|
||||||
</SimpleShowLayout>
|
</SimpleShowLayout>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,20 +1,38 @@
|
|||||||
import { Show, SimpleShowLayout, TextField } from 'react-admin';
|
import { Show, SimpleShowLayout, TextField, NumberField, DateField, SelectField, ReferenceField } from 'react-admin';
|
||||||
|
|
||||||
|
const repairKindChoices = [
|
||||||
|
{ id: 'TO', name: 'Техническое обслуживание' },
|
||||||
|
{ id: 'TR', name: 'Текущий ремонт' },
|
||||||
|
{ id: 'TRE', name: 'Текущий расширенный ремонт' },
|
||||||
|
{ id: 'KR', name: 'Капитальный ремонт' },
|
||||||
|
{ id: 'AR', name: 'Аварийный ремонт' },
|
||||||
|
{ id: 'MP', name: 'Метрологическая поверка' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const statusChoices = [
|
||||||
|
{ id: 'Draft', name: 'Черновик' },
|
||||||
|
{ id: 'Approved', name: 'Утверждена' },
|
||||||
|
{ id: 'InWork', name: 'В работе' },
|
||||||
|
{ id: 'Done', name: 'Выполнена' },
|
||||||
|
{ id: 'Cancelled', name: 'Отменена' },
|
||||||
|
];
|
||||||
export const RepairOrderShow = () => (
|
export const RepairOrderShow = () => (
|
||||||
<Show>
|
<Show>
|
||||||
<SimpleShowLayout>
|
<SimpleShowLayout>
|
||||||
<TextField source="id" label="id" />
|
<TextField source="id" label="id" />
|
||||||
<TextField source="number" label="number" />
|
<TextField source="number" label="Номер заявки" />
|
||||||
<TextField source="equipmentId" label="equipmentId" />
|
<ReferenceField source="equipmentId" reference="equipment" label="Оборудование" link="show">
|
||||||
<TextField source="repairKind" label="repairKind" />
|
<TextField source="inventoryNumber" />
|
||||||
<TextField source="status" label="status" />
|
</ReferenceField>
|
||||||
<TextField source="plannedAt" label="plannedAt" />
|
<SelectField source="repairKind" label="Вид ремонта" choices={repairKindChoices} />
|
||||||
<TextField source="startedAt" label="startedAt" />
|
<SelectField source="status" label="Статус" choices={statusChoices} />
|
||||||
<TextField source="completedAt" label="completedAt" />
|
<DateField source="plannedAt" label="Плановая дата начала" />
|
||||||
<TextField source="contractor" label="contractor" />
|
<DateField source="startedAt" label="Фактическая дата начала" />
|
||||||
<TextField source="engineHoursAtRepair" label="engineHoursAtRepair" />
|
<DateField source="completedAt" label="Фактическая дата завершения" />
|
||||||
<TextField source="description" label="description" />
|
<TextField source="contractor" label="Подрядная организация (если внешний ремонт)" />
|
||||||
<TextField source="notes" label="notes" />
|
<NumberField source="engineHoursAtRepair" label="Наработка на момент ремонта, моточасов" />
|
||||||
|
<TextField source="description" label="Описание работ / дефекта" />
|
||||||
|
<TextField source="notes" label="Примечания" />
|
||||||
</SimpleShowLayout>
|
</SimpleShowLayout>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -550,7 +550,42 @@ function renderFrontendResource(entityName, entity, resourceName, pk, enums, all
|
|||||||
const editImports = ['Edit', ...Array.from(formImportSet)].join(', ');
|
const editImports = ['Edit', ...Array.from(formImportSet)].join(', ');
|
||||||
const edit = `import { ${editImports} } from 'react-admin';\n\n${choiceConsts.join('\n')}\nexport const ${className}Edit = () => (\n <Edit>\n <SimpleForm>\n ${entity.attributes.map((a) => formField(a, 'edit')).filter(Boolean).join('\n ')}\n </SimpleForm>\n </Edit>\n);\n`;
|
const edit = `import { ${editImports} } from 'react-admin';\n\n${choiceConsts.join('\n')}\nexport const ${className}Edit = () => (\n <Edit>\n <SimpleForm>\n ${entity.attributes.map((a) => formField(a, 'edit')).filter(Boolean).join('\n ')}\n </SimpleForm>\n </Edit>\n);\n`;
|
||||||
|
|
||||||
const show = `import { Show, SimpleShowLayout, TextField } from 'react-admin';\n\nexport const ${className}Show = () => (\n <Show>\n <SimpleShowLayout>\n ${entity.attributes.map((a) => `<TextField source="${a.name}" label="${a.name}" />`).join('\n ')}\n </SimpleShowLayout>\n </Show>\n);\n`;
|
const showImportSet = new Set(['Show', 'SimpleShowLayout', 'TextField']);
|
||||||
|
if (hasNumber) showImportSet.add('NumberField');
|
||||||
|
if (hasDate) showImportSet.add('DateField');
|
||||||
|
if (enumAttrs.length) showImportSet.add('SelectField');
|
||||||
|
if (hasFK) showImportSet.add('ReferenceField');
|
||||||
|
|
||||||
|
const showFields = [];
|
||||||
|
for (const a of entity.attributes) {
|
||||||
|
const label = getAttributeLabel(a, allEntities);
|
||||||
|
if (a.foreign) {
|
||||||
|
const referenceEntity = allEntities[a.foreign.entity];
|
||||||
|
const referenceAttrs = getEntityAttrNames(referenceEntity);
|
||||||
|
const fieldSource = referenceAttrs.has('inventoryNumber')
|
||||||
|
? 'inventoryNumber'
|
||||||
|
: referenceAttrs.has('code')
|
||||||
|
? 'code'
|
||||||
|
: referenceAttrs.has('number')
|
||||||
|
? 'number'
|
||||||
|
: 'name';
|
||||||
|
showFields.push(
|
||||||
|
`<ReferenceField source="${a.name}" reference="${pluralize(toKebab(a.foreign.entity))}" label="${label}" link="show">\n <TextField source="${fieldSource}" />\n </ReferenceField>`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (a.type === 'date') {
|
||||||
|
showFields.push(`<DateField source="${a.name}" label="${label}" />`);
|
||||||
|
} else if (['integer', 'decimal'].includes(a.type)) {
|
||||||
|
showFields.push(`<NumberField source="${a.name}" label="${label}" />`);
|
||||||
|
} else if (!['string', 'text', 'uuid', 'integer', 'decimal', 'date'].includes(a.type)) {
|
||||||
|
showFields.push(`<SelectField source="${a.name}" label="${label}" choices={${a.name === 'status' ? 'statusChoices' : `${a.name}Choices`}} />`);
|
||||||
|
} else {
|
||||||
|
showFields.push(`<TextField source="${a.name}" label="${label}" />`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const show = `import { ${Array.from(showImportSet).join(', ')} } from 'react-admin';\n\n${choiceConsts.join('\n')}export const ${className}Show = () => (\n <Show>\n <SimpleShowLayout>\n ${showFields.join('\n ')}\n </SimpleShowLayout>\n </Show>\n);\n`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
files: {
|
files: {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ The frontend stays a React Admin SPA generated from `domain/*.dsl` and anchored
|
|||||||
- Each entity becomes a React Admin resource with list/create/edit/show views.
|
- Each entity becomes a React Admin resource with list/create/edit/show views.
|
||||||
- Resource names must stay aligned with backend path segments.
|
- Resource names must stay aligned with backend path segments.
|
||||||
- Foreign keys must use `ReferenceInput` / `ReferenceField`.
|
- Foreign keys must use `ReferenceInput` / `ReferenceField`.
|
||||||
|
- Foreign keys shown in list/show views must stay clickable via `ReferenceField link="show"` to open full details of the related resource.
|
||||||
- Lists must expose filters through `List` `filters` and an actions toolbar with `FilterButton`.
|
- Lists must expose filters through `List` `filters` and an actions toolbar with `FilterButton`.
|
||||||
- For enum fields where multi-select is required (for example `status`), use `SelectArrayInput` in list filters.
|
- For enum fields where multi-select is required (for example `status`), use `SelectArrayInput` in list filters.
|
||||||
- For foreign key filters and form selection use `ReferenceInput` + `AutocompleteInput` with `filterToQuery={(searchText) => ({ q: searchText })}`.
|
- For foreign key filters and form selection use `ReferenceInput` + `AutocompleteInput` with `filterToQuery={(searchText) => ({ q: searchText })}`.
|
||||||
@@ -50,6 +51,7 @@ The frontend stays a React Admin SPA generated from `domain/*.dsl` and anchored
|
|||||||
- Natural-key resources must preserve route, update, and sort compatibility with React Admin contracts.
|
- Natural-key resources must preserve route, update, and sort compatibility with React Admin contracts.
|
||||||
- Frontend requests must continue to work when the real primary key is not named `id`.
|
- Frontend requests must continue to work when the real primary key is not named `id`.
|
||||||
- `dataProvider` query serialization must preserve repeated query params for array filters (for example enum multi-select).
|
- `dataProvider` query serialization must preserve repeated query params for array filters (for example enum multi-select).
|
||||||
|
- `Resource` wiring in `App.tsx` must keep `show={...}` registration for all generated resources.
|
||||||
|
|
||||||
## Reproducibility invariants
|
## Reproducibility invariants
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ Validation is now a lightweight automated gate instead of a prose-only checklist
|
|||||||
- typed form mapping is preserved:
|
- typed form mapping is preserved:
|
||||||
- `integer` / `decimal` -> `NumberInput`
|
- `integer` / `decimal` -> `NumberInput`
|
||||||
- `date` -> `DateInput`
|
- `date` -> `DateInput`
|
||||||
|
- reference fields intended for navigation keep `ReferenceField link="show"`
|
||||||
|
- resources keep `show={...}` registration in `App.tsx`
|
||||||
|
|
||||||
### Natural-key checks
|
### Natural-key checks
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user