feat(form): x-references поля → SingleSelect с опциями из target словаря

Поля spacecraft.status, satellite_type_code и другие FK с x-references
теперь показывают dropdown с записями из целевого справочника вместо
свободного ввода. Label формируется как '<code> — <name.ru-RU>' если
target имеет localized name.

Fallback на TextInput когда target dict недоступен (scope-hide → 404)
или пуст — admin может ввести значение вручную, валидация серверная.

Кеш 5 минут (referenced data slow-moving) через TanStack Query.

UI tests +2 (75 total).
This commit is contained in:
Zimin A.N.
2026-05-06 19:29:01 +03:00
parent 5d5b03c421
commit c5d41da834
4 changed files with 287 additions and 2 deletions
+32
View File
@@ -42,6 +42,38 @@ export const recordsQuery = (dictionaryName: string, scopeCsv: string) =>
},
})
/**
* Fetch records from a target dictionary for use as FK reference options.
* Used by SchemaDrivenForm when a property has `x-references: dict.field`.
*
* Returns 404 → empty array (scope-hide: target dict not accessible).
* 5min staleTime — FK targets are typically slow-moving reference data.
*/
export const referencedRecordsQuery = (dictionaryName: string) =>
queryOptions({
queryKey: ['fk-options', dictionaryName] as const,
queryFn: async (): Promise<FlattenedRecord[]> => {
try {
const { data } = await apiClient.get<FlattenedRecord[]>(
`/${dictionaryName}/records`,
{ params: { as_scope: 'PUBLIC,INTERNAL,RESTRICTED' } },
)
return data
} catch (e: unknown) {
const status = (e as { response?: { status?: number } })?.response?.status
if (status === 404 || status === 403) return []
throw e
}
},
staleTime: 5 * 60_000,
})
export const useReferencedRecords = (dictionaryName: string | undefined) =>
useQuery({
...referencedRecordsQuery(dictionaryName ?? ''),
enabled: Boolean(dictionaryName),
})
export const recordHistoryQuery = (dictionaryName: string, businessKey: string) =>
queryOptions({
queryKey: ['record-history', dictionaryName, businessKey] as const,