setEdit({ kind: 'closed' })}
@@ -1302,3 +1329,133 @@ const serverErrorMessage = (err: unknown): string | null => {
}
return err instanceof Error ? err.message : 'Unknown error'
}
+
+// ===== Editor Tabs (Stage 3.4) =====
+
+type EditorTab = 'records' | 'relations' | 'fields' | 'json' | 'events' | 'history'
+
+function EditorTabBar({
+ active,
+ onChange,
+}: {
+ active: EditorTab
+ onChange: (tab: EditorTab) => void
+}) {
+ const { t } = useTranslation()
+ const tabs: { id: EditorTab; label: string }[] = [
+ { id: 'records', label: t('editor.tab.records', { defaultValue: 'Записи' }) },
+ { id: 'relations', label: t('editor.tab.relations', { defaultValue: 'Связи' }) },
+ { id: 'fields', label: t('editor.tab.fields', { defaultValue: 'Поля' }) },
+ { id: 'json', label: t('editor.tab.json', { defaultValue: 'JSON' }) },
+ { id: 'events', label: t('editor.tab.events', { defaultValue: 'События' }) },
+ { id: 'history', label: t('editor.tab.history', { defaultValue: 'История' }) },
+ ]
+ return (
+
+ {tabs.map((tab) => {
+ const isActive = active === tab.id
+ return (
+
+ )
+ })}
+
+ )
+}
+
+/** Fields tab — schema properties summary. */
+function FieldsTabContent({ detail }: { detail: { schemaJson: import('@/api/client').JsonSchema } }) {
+ const props = detail.schemaJson.properties ?? {}
+ const required = new Set(detail.schemaJson.required ?? [])
+ const entries = Object.entries(props)
+ if (entries.length === 0) {
+ return (
+
+ Schema без properties.
+
+ )
+ }
+ return (
+
+
+
+
+ | name |
+ type |
+ required |
+ unique |
+ i18n |
+ → FK |
+ description |
+
+
+
+ {entries.map(([key, prop]) => (
+
+ | {key} |
+ {prop.type ?? '—'} |
+ {required.has(key) ? '✓' : ''} |
+ {prop['x-unique'] ? '✓' : ''} |
+ {prop['x-localized'] ? '✓' : ''} |
+
+ {prop['x-references'] ?? ''}
+ |
+
+ {prop.description ?? ''}
+ |
+
+ ))}
+
+
+
+ )
+}
+
+/** JSON tab — raw schema JSON, pretty-printed read-only. */
+function JsonTabContent({ detail }: { detail: { schemaJson: import('@/api/client').JsonSchema } }) {
+ const json = JSON.stringify(detail.schemaJson, null, 2)
+ return (
+
+ {json}
+
+ )
+}
+
+/** Events tab — pointer to audit log scoped to this dict. */
+function EventsTabContent({ dictName }: { dictName: string }) {
+ return (
+
+
+ События для справочника {dictName} — в общем аудит-логе.
+
+
+ Открыть /audit с фильтром →
+
+
+ )
+}
+
+/** History tab — placeholder (Stage 3.x followup, требует backend changelog endpoint). */
+function HistoryTabContent() {
+ return (
+
+ Timeline изменений справочника — скоро. Требует backend endpoint для schema versions.
+
+ )
+}