This commit is contained in:
@@ -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 }) {
|
function AgentTable({ title, description }: { title: string; description: string }) {
|
||||||
const [devices, setDevices] = useState<PlatformDevice[]>([]);
|
const [devices, setDevices] = useState<PlatformDevice[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -816,8 +820,14 @@ function AgentTable({ title, description }: { title: string; description: string
|
|||||||
void refresh();
|
void refresh();
|
||||||
}, [refresh]);
|
}, [refresh]);
|
||||||
|
|
||||||
const columns = useMemo<Array<DataTableColumn<PlatformDevice>>>(
|
const rows = useMemo<NumberedPlatformDevice[]>(
|
||||||
|
() => devices.map((device, index) => ({ ...device, no: devices.length - index })),
|
||||||
|
[devices]
|
||||||
|
);
|
||||||
|
|
||||||
|
const columns = useMemo<Array<DataTableColumn<NumberedPlatformDevice>>>(
|
||||||
() => [
|
() => [
|
||||||
|
{ key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => <span>{row.no}</span> },
|
||||||
{
|
{
|
||||||
key: 'platform',
|
key: 'platform',
|
||||||
header: '플랫폼',
|
header: '플랫폼',
|
||||||
@@ -842,7 +852,7 @@ function AgentTable({ title, description }: { title: string; description: string
|
|||||||
<DataTableCard
|
<DataTableCard
|
||||||
title={title}
|
title={title}
|
||||||
description={description}
|
description={description}
|
||||||
rows={devices}
|
rows={rows}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
searchPlaceholder="플랫폼명, 계정, 워크스페이스 검색"
|
searchPlaceholder="플랫폼명, 계정, 워크스페이스 검색"
|
||||||
getSearchText={(row) => `${row.hostname} ${row.tailscaleHostname ?? ''} ${row.accountEmail} ${row.workspaceRoot ?? ''} ${row.sshUser ?? ''}`}
|
getSearchText={(row) => `${row.hostname} ${row.tailscaleHostname ?? ''} ${row.accountEmail} ${row.workspaceRoot ?? ''} ${row.sshUser ?? ''}`}
|
||||||
@@ -916,8 +926,14 @@ export function AgentRegistrationPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = useMemo<Array<DataTableColumn<DeviceAuthorization>>>(
|
const rows = useMemo<NumberedDeviceAuthorization[]>(
|
||||||
|
() => authorizations.map((authorization, index) => ({ ...authorization, no: authorizations.length - index })),
|
||||||
|
[authorizations]
|
||||||
|
);
|
||||||
|
|
||||||
|
const columns = useMemo<Array<DataTableColumn<NumberedDeviceAuthorization>>>(
|
||||||
() => [
|
() => [
|
||||||
|
{ key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => <span>{row.no}</span> },
|
||||||
{
|
{
|
||||||
key: 'user',
|
key: 'user',
|
||||||
header: '대상 사용자',
|
header: '대상 사용자',
|
||||||
@@ -987,7 +1003,7 @@ export function AgentRegistrationPage() {
|
|||||||
<DataTableCard
|
<DataTableCard
|
||||||
title="등록 키 목록"
|
title="등록 키 목록"
|
||||||
description="활성 키와 최근 24시간 내 발급된 키를 확인합니다."
|
description="활성 키와 최근 24시간 내 발급된 키를 확인합니다."
|
||||||
rows={authorizations}
|
rows={rows}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
searchPlaceholder="사용자명, 이메일, 등록 키 검색"
|
searchPlaceholder="사용자명, 이메일, 등록 키 검색"
|
||||||
getSearchText={(row) => `${row.authUserName ?? ''} ${row.accountEmail ?? ''} ${row.userCode} ${row.status}`}
|
getSearchText={(row) => `${row.authUserName ?? ''} ${row.accountEmail ?? ''} ${row.userCode} ${row.status}`}
|
||||||
@@ -1036,14 +1052,20 @@ export function AgentSshKeysPage() {
|
|||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const rows = useMemo<NumberedPlatformSshKey[]>(
|
||||||
|
() => keys.map((key, index) => ({ ...key, no: keys.length - index })),
|
||||||
|
[keys]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle eyebrow="플랫폼 관리" title="SSH 키" description="저장소와 원격 실행에 사용할 SSH 키 배포 상태를 관리합니다." />
|
<PageTitle eyebrow="플랫폼 관리" title="SSH 키" description="저장소와 원격 실행에 사용할 SSH 키 배포 상태를 관리합니다." />
|
||||||
<DataTableCard
|
<DataTableCard
|
||||||
title="SSH 키 목록"
|
title="SSH 키 목록"
|
||||||
description="등록 플랫폼 계정에 연결된 SSH 키입니다."
|
description="등록 플랫폼 계정에 연결된 SSH 키입니다."
|
||||||
rows={keys}
|
rows={rows}
|
||||||
columns={[
|
columns={[
|
||||||
|
{ key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => <span>{row.no}</span> },
|
||||||
{ key: 'account', header: '계정', flexible: true, cell: (row) => row.accountEmail },
|
{ key: 'account', header: '계정', flexible: true, cell: (row) => row.accountEmail },
|
||||||
{ key: 'label', header: '이름', width: 180, cell: (row) => row.label || '-' },
|
{ key: 'label', header: '이름', width: 180, cell: (row) => row.label || '-' },
|
||||||
{ key: 'type', header: '유형', width: 140, cell: (row) => row.keyType || '-' },
|
{ key: 'type', header: '유형', width: 140, cell: (row) => row.keyType || '-' },
|
||||||
|
|||||||
@@ -441,15 +441,15 @@ export function RuntimeConfigPage() {
|
|||||||
</Card>
|
</Card>
|
||||||
<Card className="p-5">
|
<Card className="p-5">
|
||||||
<p className="text-sm text-muted-foreground">구성요소</p>
|
<p className="text-sm text-muted-foreground">구성요소</p>
|
||||||
<p className="mt-4 text-2xl font-medium text-foreground">{components.length}개</p>
|
<p className="mt-4 text-2xl font-medium text-foreground">{components.length}</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="p-5">
|
<Card className="p-5">
|
||||||
<p className="text-sm text-muted-foreground">환경변수</p>
|
<p className="text-sm text-muted-foreground">환경변수</p>
|
||||||
<p className="mt-4 text-2xl font-medium text-foreground">{envCount}개</p>
|
<p className="mt-4 text-2xl font-medium text-foreground">{envCount}</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="p-5">
|
<Card className="p-5">
|
||||||
<p className="text-sm text-muted-foreground">시크릿</p>
|
<p className="text-sm text-muted-foreground">시크릿</p>
|
||||||
<p className="mt-4 text-2xl font-medium text-foreground">{secretCount}개</p>
|
<p className="mt-4 text-2xl font-medium text-foreground">{secretCount}</p>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type HeadscaleNode = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type AclRule = { id: string; action: string; sources: string[]; destinations: string[] };
|
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) {
|
function normalize(value?: string | null) {
|
||||||
return (value ?? '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
return (value ?? '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
@@ -55,8 +55,10 @@ export function RuntimeDeviceControlPage() {
|
|||||||
])
|
])
|
||||||
.then(([nodeResponse, aclResponse, devices]) => {
|
.then(([nodeResponse, aclResponse, devices]) => {
|
||||||
const rules = aclResponse.policy?.acls ?? [];
|
const rules = aclResponse.policy?.acls ?? [];
|
||||||
setRows((nodeResponse.nodes ?? []).map((node) => ({
|
const nodes = nodeResponse.nodes ?? [];
|
||||||
|
setRows(nodes.map((node, index) => ({
|
||||||
...node,
|
...node,
|
||||||
|
no: nodes.length - index,
|
||||||
device: findDevice(node, devices),
|
device: findDevice(node, devices),
|
||||||
controllers: findControllers(node, rules),
|
controllers: findControllers(node, rules),
|
||||||
})));
|
})));
|
||||||
@@ -71,6 +73,7 @@ export function RuntimeDeviceControlPage() {
|
|||||||
|
|
||||||
const columns = useMemo<Array<DataTableColumn<PlatformRow>>>(
|
const columns = useMemo<Array<DataTableColumn<PlatformRow>>>(
|
||||||
() => [
|
() => [
|
||||||
|
{ key: 'no', header: 'No.', className: 'w-14 px-3 py-3 text-center font-medium', cell: (row) => <span>{row.no}</span> },
|
||||||
{
|
{
|
||||||
key: 'platform',
|
key: 'platform',
|
||||||
header: '플랫폼',
|
header: '플랫폼',
|
||||||
|
|||||||
Reference in New Issue
Block a user