Files
mdm-ordinis/ordinis-admin-ui/src/components/lineage/DictionaryDependentsPanel.tsx
T
2026-05-10 22:17:06 +00:00

82 lines
3.1 KiB
TypeScript

import { useTranslation } from 'react-i18next'
import { Link } from '@tanstack/react-router'
import { Badge, Panel } from '@/ui'
import { ArrowRightIcon } from '@phosphor-icons/react'
import { useDictionaryDependents } from '@/api/queries'
import type { OnCloseAction } from '@/api/client'
type Props = {
dictionaryName: string
}
const onCloseVariant = (a: OnCloseAction): 'neutral' | 'warning' | 'error' => {
if (a === 'CASCADE') return 'error'
if (a === 'WARN') return 'warning'
return 'neutral'
}
/**
* Schema-level reverse FK card — "На этот словарь ссылаются:".
*
* <p>Показывает chip per (sourceDict.field → targetField, count, onClose mode).
* Скрывает себя если 0 dependents (не loading и не error) — большинство
* справочников не имеют incoming FK, не нужно занимать место.
*
* <p>Phase 1 (read-only). Phase 3 добавит preview cascade chain в close
* confirmation dialog.
*/
export const DictionaryDependentsPanel = ({ dictionaryName }: Props) => {
const { t } = useTranslation()
const { data, isLoading, error } = useDictionaryDependents(dictionaryName)
// Hide entirely в loading / error / empty — это "secondary" info card,
// не должен конкурировать с records table за внимание.
if (isLoading || error) return null
if (!data || data.length === 0) return null
return (
<Panel>
<div className="flex items-center justify-between mb-3">
<h3 className="text-sm font-primary text-carbon">
{t('lineage.usedBy.title')}
</h3>
<span className="text-2xs text-carbon/60">
{t('lineage.usedBy.count', { count: data.length })}
</span>
</div>
<ul className="flex flex-wrap gap-2">
{data.map((d) => (
<li
key={`${d.sourceDict}.${d.sourceField}`}
className="flex items-center gap-2 px-2.5 py-1.5 rounded-sm border border-regolith bg-white text-2xs"
>
<Link
to="/dictionaries/$name"
params={{ name: d.sourceDict }}
className="text-ultramarain hover:underline font-mono"
aria-label={t('lineage.usedBy.openSourceDict', {
dict: d.sourceDisplayName ?? d.sourceDict,
})}
>
{d.sourceDisplayName ?? d.sourceDict}
</Link>
<span className="font-mono text-carbon/70">.{d.sourceField}</span>
<ArrowRightIcon weight="bold" size={12} className="text-carbon/40" />
<span className="font-mono text-carbon/70">{d.targetField}</span>
{d.activeRecordsInSourceDict > 0 && (
<Badge variant="neutral">
{t('lineage.usedBy.activeCount', {
count: d.activeRecordsInSourceDict,
})}
</Badge>
)}
<Badge variant={onCloseVariant(d.onClose)}>
{t(`lineage.onClose.${d.onClose}`)}
</Badge>
</li>
))}
</ul>
</Panel>
)
}