예제
Resource 표
표와 카드 예제를 함께 보고 더 보기에서 보기와 카드 열 수를 바꾸며, 같은 행 동작과 컬렉션 상태를 확인합니다.
공개 계약
NxButtonResourcePrimaryCellResourceRowActionsMenuResourceStatusBadgeResourceTableResourceTextCell실행 미리 보기
실시간Resource 컬렉션
조회 상태를 전환한 뒤 더 보기에서 표 또는 카드를 선택하고 카드 열 수와 너비를 조절해 보세요.
ResourceTable마지막 작업: 없음
프리셋을 선택하거나 프레임 오른쪽 아래 모서리를 드래그하세요.
| 설비 | 담당자 | 상태 | 작업 |
|---|---|---|---|
Jin Lee | |||
Mina Park | |||
Sora Kim |
카드 보기
- 담당자
Jin Lee
- 상태
- 담당자
Mina Park
- 상태
- 담당자
Sora Kim
- 상태
복사 가능한 소스
코드 예시
TSX
import { useMemo, useState } from "react";
import type { ResourceTableColumn } from "@nexia/sdk";
import {
NxButton,
ResourcePrimaryCell,
ResourceRowActionsMenu,
ResourceStatusBadge,
ResourceTable,
ResourceTextCell,
} from "@nexia/sdk/host";
type TableState = "data" | "empty" | "noResults" | "loading" | "error";
type MachineRow = {
id: string;
name: string;
code: string;
line: string;
owner: string;
status: string;
};
const rows: MachineRow[] = [
{
id: "cnc-a1",
name: "CNC A-1",
code: "MC-001",
line: "Line A",
owner: "Jin Lee",
status: "ready",
},
{
id: "press-b2",
name: "Press B-2",
code: "MC-014",
line: "Line B",
owner: "Mina Park",
status: "maintenance",
},
];
export function ResourceTableExample() {
const [state, setState] = useState<TableState>("data");
const [lastAction, setLastAction] = useState("None");
const columns = useMemo<ResourceTableColumn<MachineRow>[]>(
() => [
{
key: "machine",
header: "Machine",
size: "primary",
cell: (row) => (
<ResourcePrimaryCell
resource={{
type: "manufacturing.machine",
id: row.id,
label: row.name,
}}
label={row.name}
meta={[
{ kind: "text", key: "code", label: row.code },
{ kind: "badge", key: "line", label: row.line },
]}
onActivate={() => setLastAction(`View ${row.name}`)}
/>
),
},
{
key: "owner",
header: "Owner",
size: "text",
priority: 2,
defaultVisible: false,
cell: (row) => (
<ResourceTextCell
primary={row.owner}
secondary={row.line}
/>
),
},
{
key: "status",
header: "Status",
size: "meta",
cell: (row) => <ResourceStatusBadge status={row.status} />,
},
{
key: "actions",
header: "Actions",
size: "actions",
hideable: false,
cell: (row) => (
<ResourceRowActionsMenu
label={`Actions: ${row.name}`}
items={[
{
id: "view",
label: "View",
onSelect: () =>
setLastAction(`View ${row.name}`),
},
{
id: "edit",
label: "Edit",
onSelect: () =>
setLastAction(`Edit ${row.name}`),
},
{
id: "schedule-maintenance",
label: "Schedule maintenance",
onSelect: () =>
setLastAction(
`Schedule maintenance for ${row.name}`
),
},
{
id: "deactivate",
label: "Deactivate",
destructive: true,
onSelect: () =>
setLastAction(`Deactivate ${row.name}`),
},
]}
/>
),
},
],
[]
);
const renderCard = (row: MachineRow, index: number) => {
const primary = columns.find((column) => column.key === "machine");
const actions = columns.find((column) => column.key === "actions");
const details = columns.filter(
(column) => column.key !== "machine" && column.key !== "actions"
);
return (
<div className="space-y-3">
<div className="flex items-start justify-between gap-2">
{primary?.cell(row, index)}
<div className="shrink-0">
{actions?.cell(row, index)}
</div>
</div>
<dl className="space-y-2">
{details.map((column) => (
<div key={column.key}>
<dt className="text-sm text-text-tertiary">
{column.header}
</dt>
<dd>{column.cell(row, index)}</dd>
</div>
))}
</dl>
</div>
);
};
const noResults = state === "noResults";
return (
<div className="grid gap-4">
<div className="flex flex-wrap gap-2">
{(
["data", "empty", "noResults", "loading", "error"] as const
).map((item) => (
<NxButton
key={item}
size="xs"
variant={state === item ? "primary" : "secondary"}
onClick={() => setState(item)}
>
{item}
</NxButton>
))}
</div>
<p role="status" className="text-sm text-text-secondary">
Last action: {lastAction}
</p>
{(["table", "cards"] as const).map((defaultView) => (
<ResourceTable
key={defaultView}
tableId={`developer-example.production-machines.${defaultView}`}
label={
defaultView === "table" ? "Table view" : "Card view"
}
showLabel
rows={state === "data" ? rows : []}
columns={columns}
renderCard={renderCard}
defaultView={defaultView}
getKey={(row) => row.id}
toolbar={{}}
loading={state === "loading"}
error={state === "error"}
errorDescription="Machines could not be loaded."
onRetry={() => setState("data")}
hasActiveQuery={noResults}
emptyState={{
kind: "empty",
title: "No machines yet",
description: "Create a machine to start planning capacity.",
}}
/>
))}
</div>
);
}