Page Design: Dữ liệu Định vị (Anchored Data — Tree Table)¶
Follows MASTER.md — uses Domain-Specific Pattern "Tree Table". Applies to:
SCR-ANCHOR-10Route:/[locale]/anchored-dataUsers: Manager (full CRUD), Approver (read-only via SCR-ANCHOR-20)
Layout¶
+-----------------------------------------------------------+
| "Thiết lập dữ liệu định vị (Anchored Data)" |
| "Khai báo cấu trúc dữ liệu tiêu chuẩn theo Phụ lục A" |
| [+ Thêm Domain] |
+-----------------------------------------------------------+
| Search bar [Filter: status ▼] |
+-----------------------------------------------------------+
| Tree Table |
| ┌─────────────────────────────┬──────────┬────────┐ |
| │ Cấu trúc Dữ liệu │ Mã ID │ Thao tác│ |
| ├─────────────────────────────┼──────────┼────────┤ |
| │ ▼ Con người │ [DM1] │ Sửa │ |
| │ ├ Định danh (italic) │ [DM1.1] │ │ |
| │ │ • Số CCCD │ DE001... │ │ |
| │ │ • Họ và tên │ DE002... │ │ |
| │ └ Y tế & Sức khỏe │ [DM1.2] │ │ |
| │ ▶ Tổ chức │ [DM2] │ │ |
| │ ▶ Đất đai │ [DM3] │ │ |
| └─────────────────────────────┴──────────┴────────┘ |
+-----------------------------------------------------------+
| Showing X domains, Y sub-domains, Z data elements |
+-----------------------------------------------------------+
max-w-6xl mx-auto,space-y-6- Tree table is a single flat
<table>with visual indentation (not nested tables) - All domains collapsed by default → expand on click
Components¶
Page Header¶
flex justify-between items-end
div
h1.text-2xl.font-bold.text-foreground /* title */
p.text-sm.text-muted-foreground.font-medium /* subtitle */
/* Add Domain button — Primary */
bg-primary text-primary-foreground px-6 py-2.5 rounded-2xl
font-bold shadow-lg hover:bg-blue-700 transition-all
flex items-center gap-2
Plus.h-[18px].w-[18px].stroke-[2.5]
Search & Filter Bar¶
flex items-center gap-4
/* Search input */
flex-1 relative
Search.absolute.left-4.top-1/2.-translate-y-1/2.h-4.w-4.text-muted-foreground
input.w-full.pl-10.pr-4.py-2.5.rounded-2xl.border.border-input
.text-sm.font-medium.placeholder:text-muted-foreground
.focus:ring-2.focus:ring-ring
placeholder="Tìm kiếm Domain, Sub Domain, Data Element..."
/* Status filter — shadcn Select */
w-48
Tree Table¶
/* Container */
bg-card rounded-3xl border border-border overflow-hidden shadow-sm
/* Table */
w-full text-sm text-left
/* Header row */
bg-muted border-b border-border
th.px-8.py-5.font-bold.text-muted-foreground.uppercase.tracking-widest.text-[11px]
/* Columns: Cấu trúc Dữ liệu | Mã ID | Thao tác (right-aligned) */
/* Body */
divide-y divide-border/50
Domain Row (Level 1)¶
bg-muted/50 cursor-pointer hover:bg-muted transition-colors
td.px-8.py-4.font-black.text-foreground.flex.items-center.gap-2
/* Expand icon */
ChevronDown.h-4.w-4.text-primary /* expanded */
ChevronRight.h-4.w-4.text-muted-foreground /* collapsed */
/* Domain name */
span
td.px-8.py-4.font-mono.text-xs.text-muted-foreground.font-bold
/* Code: [DM1] */
td.px-8.py-4.text-right
button.text-primary.font-bold.text-xs.hover:underline "Sửa"
Interaction: Click row → toggle expand/collapse children. Click "Sửa" → open SCR-ANCHOR-11 popup.
Sub Domain Row (Level 2)¶
bg-card
td.pl-14.py-3.font-bold.text-muted-foreground.italic
/* Sub Domain name */
td.px-8.py-3.font-mono.text-xs.text-muted-foreground.font-bold
/* Code: [DM1.1] */
td.px-8.py-3.text-right
button.text-primary.font-bold.text-xs.hover:underline "Sửa"
Interaction: Click "Sửa" → open SCR-ANCHOR-12 popup.
Data Element Row (Level 3)¶
hover:bg-accent/50 transition-colors
td.pl-20.py-2.text-muted-foreground.font-medium
/* "• " + DE name */
span.mr-2 "•"
span "Số CCCD"
td.px-8.py-2.font-mono.text-[10px].text-muted-foreground/60
/* Code: [DE001-DM1.1] */
td.px-8.py-2.text-right
/* No action button at this level — click row to see detail */
Interaction: Click row → navigate to SCR-ANCHOR-20 (detail page).
Context Menu (Right-click or "..." button on Domain/Sub Domain)¶
/* shadcn DropdownMenu */
/* Items: Thêm Sub Domain, Thêm Data Element, Sửa, Xóa */
/* Xóa only visible if no children */
Summary Footer¶
px-8 py-4 bg-muted/30 border-t border-border
text-sm text-muted-foreground font-medium
"Hiển thị X domains, Y sub-domains, Z data elements"
Empty State¶
/* When no domains exist yet (fresh system) */
flex flex-col items-center justify-center py-16 text-center
Database.h-12.w-12.text-muted-foreground/30
p.text-lg.font-bold.text-muted-foreground.mt-4 "Chưa có dữ liệu định vị"
p.text-sm.text-muted-foreground.mt-2 "Bắt đầu bằng cách import Master Data hoặc thêm Domain đầu tiên."
div.flex.gap-3.mt-4
Button(variant="outline") "Import Master Data"
Button(variant="default") "Thêm Domain"
Loading State¶
/* Table skeleton */
bg-card rounded-3xl border border-border overflow-hidden shadow-sm
/* Header skeleton */
bg-muted px-8 py-5 flex gap-8
Skeleton.h-3.w-40 Skeleton.h-3.w-16 Skeleton.h-3.w-12
/* 5 row skeletons */
divide-y divide-border/50
px-8 py-4 flex gap-8
Skeleton.h-4.w-48 Skeleton.h-3.w-12 Skeleton.h-3.w-8
Data & Business Rules¶
| Rule | Detail |
|---|---|
| Default state | All domains collapsed |
| Sort | Domains by code ASC (DM1, DM2...). Sub Domains by code ASC within domain. DEs by code ASC within sub domain |
| Search | Filter across all levels — if a DE matches, show its parent Domain + Sub Domain expanded |
| Codes | Auto-generated, read-only: DM{N}, DM{N}.{M}, DE{NNN}-DM{N}.{M} |
| Delete guard | Cannot delete Domain with Sub Domains. Cannot delete Sub Domain with Data Elements. Show AlertDialog |
| Status filter | Filter by Data Element status (DRAFT, IN_REVIEW, APPROVED, PUBLISHED) |
Behaviors¶
| State | Trigger | Display |
|---|---|---|
| Loading | Page init | Skeleton table |
| Empty | No domains | Empty state with dual CTA |
| Default | Data loaded | All domains collapsed, row counts in footer |
| Expanded | Click domain row | Show Sub Domains + DEs underneath, icon → ChevronDown |
| Collapsed | Click expanded domain | Hide children, icon → ChevronRight |
| Search active | Type in search | Live filter, matching rows highlighted, parents auto-expanded |
| Add Domain | Click "+ Thêm Domain" | Open SCR-ANCHOR-11 popup |
| Edit Domain | Click "Sửa" on domain row | Open SCR-ANCHOR-11 popup (edit mode) |
| Edit Sub Domain | Click "Sửa" on sub domain row | Open SCR-ANCHOR-12 popup |
| View DE detail | Click DE row | Navigate to SCR-ANCHOR-20 |
| Delete | Context menu → Xóa | AlertDialog confirmation (destructive) |
Responsive¶
| Breakpoint | Changes |
|---|---|
| Mobile (< 768px) | Hide "Mã ID" column. "Thao tác" becomes icon-only (Pencil). Reduce indentation (pl-8, pl-12, pl-16). p-4 |
| Tablet (768-1023px) | Keep all columns. Reduce padding. p-6 |
| Desktop (>= 1024px) | Full layout as wireframe. p-10, max-w-6xl |
Accessibility¶
- Expand/collapse:
aria-expanded="true/false"on domain rows - Tree semantics:
role="treegrid", rows withrole="row",aria-level="1/2/3" - Keyboard: Enter/Space to toggle expand. Arrow keys to navigate rows
- "Sửa" links:
aria-label="Sửa Domain Con người"(include name) - "+ Thêm Domain" button:
aria-label="Thêm Domain mới" - Search:
aria-label="Tìm kiếm trong dữ liệu định vị" - Status changes announced via
aria-live="polite"region
MASTER.md Overrides¶
No overrides — uses MASTER.md Tree Table domain-specific pattern.