diff --git a/src/pages/RestoredPages.tsx b/src/pages/RestoredPages.tsx index 55ad386..43662d6 100644 --- a/src/pages/RestoredPages.tsx +++ b/src/pages/RestoredPages.tsx @@ -800,6 +800,10 @@ export function RuntimeDevicesPage() { ); } +type NumberedPlatformDevice = PlatformDevice & { no: number }; +type NumberedDeviceAuthorization = DeviceAuthorization & { no: number }; +type NumberedPlatformSshKey = PlatformSshKey & { no: number }; + function AgentTable({ title, description }: { title: string; description: string }) { const [devices, setDevices] = useState([]); const [loading, setLoading] = useState(true); @@ -816,8 +820,14 @@ function AgentTable({ title, description }: { title: string; description: string void refresh(); }, [refresh]); - const columns = useMemo>>( + const rows = useMemo( + () => devices.map((device, index) => ({ ...device, no: devices.length - index })), + [devices] + ); + + const columns = useMemo>>( () => [ + { key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => {row.no} }, { key: 'platform', header: '플랫폼', @@ -842,7 +852,7 @@ function AgentTable({ title, description }: { title: string; description: string `${row.hostname} ${row.tailscaleHostname ?? ''} ${row.accountEmail} ${row.workspaceRoot ?? ''} ${row.sshUser ?? ''}`} @@ -916,8 +926,14 @@ export function AgentRegistrationPage() { } }; - const columns = useMemo>>( + const rows = useMemo( + () => authorizations.map((authorization, index) => ({ ...authorization, no: authorizations.length - index })), + [authorizations] + ); + + const columns = useMemo>>( () => [ + { key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => {row.no} }, { key: 'user', header: '대상 사용자', @@ -987,7 +1003,7 @@ export function AgentRegistrationPage() { `${row.authUserName ?? ''} ${row.accountEmail ?? ''} ${row.userCode} ${row.status}`} @@ -1036,14 +1052,20 @@ export function AgentSshKeysPage() { .finally(() => setLoading(false)); }, []); + const rows = useMemo( + () => keys.map((key, index) => ({ ...key, no: keys.length - index })), + [keys] + ); + return ( <> {row.no} }, { key: 'account', header: '계정', flexible: true, cell: (row) => row.accountEmail }, { key: 'label', header: '이름', width: 180, cell: (row) => row.label || '-' }, { key: 'type', header: '유형', width: 140, cell: (row) => row.keyType || '-' }, diff --git a/src/pages/runtime/RuntimeConfigPage.tsx b/src/pages/runtime/RuntimeConfigPage.tsx index 6f6eb3b..b35935d 100644 --- a/src/pages/runtime/RuntimeConfigPage.tsx +++ b/src/pages/runtime/RuntimeConfigPage.tsx @@ -441,15 +441,15 @@ export function RuntimeConfigPage() {

구성요소

-

{components.length}개

+

{components.length}

환경변수

-

{envCount}개

+

{envCount}

시크릿

-

{secretCount}개

+

{secretCount}

diff --git a/src/pages/runtime/RuntimeDeviceControlPage.tsx b/src/pages/runtime/RuntimeDeviceControlPage.tsx index d772ec8..fc100b9 100644 --- a/src/pages/runtime/RuntimeDeviceControlPage.tsx +++ b/src/pages/runtime/RuntimeDeviceControlPage.tsx @@ -20,7 +20,7 @@ type HeadscaleNode = { }; type AclRule = { id: string; action: string; sources: string[]; destinations: string[] }; -type PlatformRow = HeadscaleNode & { device?: PlatformDevice; controllers: string[] }; +type PlatformRow = HeadscaleNode & { device?: PlatformDevice; controllers: string[]; no: number }; function normalize(value?: string | null) { return (value ?? '').toLowerCase().replace(/[^a-z0-9]/g, ''); @@ -55,8 +55,10 @@ export function RuntimeDeviceControlPage() { ]) .then(([nodeResponse, aclResponse, devices]) => { const rules = aclResponse.policy?.acls ?? []; - setRows((nodeResponse.nodes ?? []).map((node) => ({ + const nodes = nodeResponse.nodes ?? []; + setRows(nodes.map((node, index) => ({ ...node, + no: nodes.length - index, device: findDevice(node, devices), controllers: findControllers(node, rules), }))); @@ -71,6 +73,7 @@ export function RuntimeDeviceControlPage() { const columns = useMemo>>( () => [ + { key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => {row.no} }, { key: 'platform', header: '플랫폼',