@voyantjs/resources-ui 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/components/resources-overview.d.ts +22 -0
- package/dist/components/resources-overview.d.ts.map +1 -0
- package/dist/components/resources-overview.js +14 -0
- package/dist/components/resources-section-header.d.ts +7 -0
- package/dist/components/resources-section-header.d.ts.map +1 -0
- package/dist/components/resources-section-header.js +6 -0
- package/dist/components/resources-tabs-primary.d.ts +56 -0
- package/dist/components/resources-tabs-primary.d.ts.map +1 -0
- package/dist/components/resources-tabs-primary.js +163 -0
- package/dist/components/resources-tabs-secondary.d.ts +44 -0
- package/dist/components/resources-tabs-secondary.d.ts.map +1 -0
- package/dist/components/resources-tabs-secondary.js +108 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @voyantjs/resources-ui
|
|
2
|
+
|
|
3
|
+
Importable React UI components for Voyant resources. Bundler-consumed (Vite, Next.js, webpack, etc.).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @voyantjs/resources-ui @voyantjs/resources-react @voyantjs/voyant-ui @tanstack/react-query react react-dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`@voyantjs/voyant-ui` provides the design-system primitives. `@voyantjs/resources-react` provides the data-layer hooks. Both are required peers.
|
|
12
|
+
|
|
13
|
+
All components accept a `className` prop and merge it with `cn()`. Wrap or compose to extend; use the registry copy-paste path (`npx shadcn add @voyant/...`) for components you want to fork outright.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BookingOption, ResourceCloseoutRow, ResourceRow, ResourceSlotAssignmentRow, SlotOption } from "@voyantjs/resources-react";
|
|
2
|
+
export declare function ResourcesOverview({ bookings, slots, closeouts, filteredResources, filteredPools, liveAssignments, resourcesWithoutSupplier, unassignedReservations, search, setSearch, kindFilter, setKindFilter, hasFilters, onClearFilters, onOpenAssignment, onOpenResource, }: {
|
|
3
|
+
bookings: BookingOption[];
|
|
4
|
+
slots: SlotOption[];
|
|
5
|
+
closeouts: ResourceCloseoutRow[];
|
|
6
|
+
filteredResources: ResourceRow[];
|
|
7
|
+
filteredPools: Array<{
|
|
8
|
+
active: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
liveAssignments: ResourceSlotAssignmentRow[];
|
|
11
|
+
resourcesWithoutSupplier: ResourceRow[];
|
|
12
|
+
unassignedReservations: ResourceSlotAssignmentRow[];
|
|
13
|
+
search: string;
|
|
14
|
+
setSearch: (value: string) => void;
|
|
15
|
+
kindFilter: string;
|
|
16
|
+
setKindFilter: (value: string) => void;
|
|
17
|
+
hasFilters: boolean;
|
|
18
|
+
onClearFilters: () => void;
|
|
19
|
+
onOpenAssignment: (assignmentId: string) => void;
|
|
20
|
+
onOpenResource: (resourceId: string) => void;
|
|
21
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=resources-overview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources-overview.d.ts","sourceRoot":"","sources":["../../src/components/resources-overview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,UAAU,EACX,MAAM,2BAA2B,CAAA;AAkBlC,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,KAAK,EACL,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,sBAAsB,EACtB,MAAM,EACN,SAAS,EACT,UAAU,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,cAAc,GACf,EAAE;IACD,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,SAAS,EAAE,mBAAmB,EAAE,CAAA;IAChC,iBAAiB,EAAE,WAAW,EAAE,CAAA;IAChC,aAAa,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACzC,eAAe,EAAE,yBAAyB,EAAE,CAAA;IAC5C,wBAAwB,EAAE,WAAW,EAAE,CAAA;IACvC,sBAAsB,EAAE,yBAAyB,EAAE,CAAA;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,UAAU,EAAE,OAAO,CAAA;IACnB,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,gBAAgB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7C,2CAgIA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { labelById, resourceKindOptions, slotLabel } from "@voyantjs/resources-react";
|
|
3
|
+
import { Button, Card, CardContent, CardHeader, CardTitle, Input, OverviewMetric, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyantjs/voyant-ui/components";
|
|
4
|
+
import { CalendarDays, ExternalLink, Search, Users, Wrench } from "lucide-react";
|
|
5
|
+
export function ResourcesOverview({ bookings, slots, closeouts, filteredResources, filteredPools, liveAssignments, resourcesWithoutSupplier, unassignedReservations, search, setSearch, kindFilter, setKindFilter, hasFilters, onClearFilters, onOpenAssignment, onOpenResource, }) {
|
|
6
|
+
const activeResourcesCount = filteredResources.filter((resource) => resource.active).length;
|
|
7
|
+
const activePoolsCount = filteredPools.filter((pool) => pool.active).length;
|
|
8
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4", children: [_jsx(OverviewMetric, { title: "Active Resources", value: activeResourcesCount, description: "Assignable assets ready for use", icon: Wrench }), _jsx(OverviewMetric, { title: "Active Pools", value: activePoolsCount, description: "Shared-capacity pools live", icon: Users }), _jsx(OverviewMetric, { title: "Live Assignments", value: liveAssignments.length, description: "Reserved or assigned slot coverage", icon: CalendarDays }), _jsx(OverviewMetric, { title: "Closeouts", value: closeouts.length, description: "Active maintenance or conflict blocks", icon: ExternalLink })] }), _jsxs("div", { className: "grid gap-4 xl:grid-cols-2", children: [_jsxs(Card, { size: "sm", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: "Assignment Gaps" }) }), _jsx(CardContent, { className: "space-y-3 text-sm", children: unassignedReservations.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Every live reservation has a named resource." })) : (unassignedReservations.slice(0, 4).map((assignment) => (_jsxs("button", { type: "button", className: "block w-full rounded-md border p-3 text-left hover:bg-muted/40", onClick: () => onOpenAssignment(assignment.id), children: [_jsx("div", { className: "font-medium", children: slotLabel(slots.find((slot) => slot.id === assignment.slotId) ?? {
|
|
9
|
+
id: assignment.slotId,
|
|
10
|
+
productId: "",
|
|
11
|
+
dateLocal: assignment.slotId,
|
|
12
|
+
startsAt: assignment.slotId,
|
|
13
|
+
}) }), _jsxs("div", { className: "text-muted-foreground", children: ["Status: ", assignment.status, " \u00B7 Booking:", " ", labelById(bookings, assignment.bookingId)] })] }, assignment.id)))) })] }), _jsxs(Card, { size: "sm", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: "Ownership Gaps" }) }), _jsx(CardContent, { className: "space-y-3 text-sm", children: resourcesWithoutSupplier.length === 0 ? (_jsx("p", { className: "text-muted-foreground", children: "Every resource is linked to a supplier." })) : (resourcesWithoutSupplier.slice(0, 4).map((resource) => (_jsxs("button", { type: "button", className: "block w-full rounded-md border p-3 text-left hover:bg-muted/40", onClick: () => onOpenResource(resource.id), children: [_jsx("div", { className: "font-medium", children: resource.name }), _jsxs("div", { className: "text-muted-foreground capitalize", children: [resource.kind, " \u00B7 Capacity ", resource.capacity ?? "-", " \u00B7 No supplier assigned"] })] }, resource.id)))) })] })] }), _jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [_jsxs("div", { className: "flex flex-1 flex-col gap-3 md:flex-row md:items-center", children: [_jsxs("div", { className: "relative w-full max-w-sm", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { placeholder: "Search resources...", value: search, onChange: (event) => setSearch(event.target.value), className: "pl-9" })] }), _jsxs(Select, { value: kindFilter, onValueChange: (value) => setKindFilter(value ?? "all"), children: [_jsx(SelectTrigger, { className: "w-full md:w-56", children: _jsx(SelectValue, { placeholder: "All kinds" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All kinds" }), resourceKindOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] })] }), hasFilters ? (_jsx(Button, { variant: "outline", onClick: onClearFilters, children: "Clear Filters" })) : null] })] }));
|
|
14
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function ResourcesSectionHeader({ title, description, actionLabel, onAction, }: {
|
|
2
|
+
title: string;
|
|
3
|
+
description: string;
|
|
4
|
+
actionLabel: string;
|
|
5
|
+
onAction: () => void;
|
|
6
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=resources-section-header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources-section-header.d.ts","sourceRoot":"","sources":["../../src/components/resources-section-header.tsx"],"names":[],"mappings":"AAGA,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,WAAW,EACX,WAAW,EACX,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,2CAaA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from "@voyantjs/voyant-ui/components";
|
|
3
|
+
import { Plus } from "lucide-react";
|
|
4
|
+
export function ResourcesSectionHeader({ title, description, actionLabel, onAction, }) {
|
|
5
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs(Button, { onClick: onAction, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), actionLabel] })] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { OnChangeFn, RowSelectionState } from "@tanstack/react-table";
|
|
2
|
+
import { type ProductOption, type ResourceAllocationRow, type ResourcePoolRow, type ResourceRow, type SupplierOption } from "@voyantjs/resources-react";
|
|
3
|
+
type BulkFn = (args: {
|
|
4
|
+
ids: string[];
|
|
5
|
+
endpoint: string;
|
|
6
|
+
target: string;
|
|
7
|
+
noun: string;
|
|
8
|
+
payload: Record<string, unknown>;
|
|
9
|
+
successVerb: string;
|
|
10
|
+
clearSelection: () => void;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
type DeleteFn = (args: {
|
|
13
|
+
ids: string[];
|
|
14
|
+
endpoint: string;
|
|
15
|
+
target: string;
|
|
16
|
+
noun: string;
|
|
17
|
+
clearSelection: () => void;
|
|
18
|
+
}) => Promise<void>;
|
|
19
|
+
export declare function ResourcesTab(props: {
|
|
20
|
+
suppliers: SupplierOption[];
|
|
21
|
+
filteredResources: ResourceRow[];
|
|
22
|
+
resourceSelection: RowSelectionState;
|
|
23
|
+
setResourceSelection: OnChangeFn<RowSelectionState>;
|
|
24
|
+
bulkActionTarget: string | null;
|
|
25
|
+
handleBulkUpdate: BulkFn;
|
|
26
|
+
handleBulkDelete: DeleteFn;
|
|
27
|
+
onCreate: () => void;
|
|
28
|
+
onOpenRoute: (resourceId: string) => void;
|
|
29
|
+
onEdit: (row: ResourceRow) => void;
|
|
30
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function PoolsTab(props: {
|
|
32
|
+
products: ProductOption[];
|
|
33
|
+
filteredPools: ResourcePoolRow[];
|
|
34
|
+
poolSelection: RowSelectionState;
|
|
35
|
+
setPoolSelection: OnChangeFn<RowSelectionState>;
|
|
36
|
+
bulkActionTarget: string | null;
|
|
37
|
+
handleBulkUpdate: BulkFn;
|
|
38
|
+
handleBulkDelete: DeleteFn;
|
|
39
|
+
onCreate: () => void;
|
|
40
|
+
onOpenRoute: (poolId: string) => void;
|
|
41
|
+
onEdit: (row: ResourcePoolRow) => void;
|
|
42
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
export declare function AllocationsTab(props: {
|
|
44
|
+
pools: ResourcePoolRow[];
|
|
45
|
+
products: ProductOption[];
|
|
46
|
+
filteredAllocations: ResourceAllocationRow[];
|
|
47
|
+
allocationSelection: RowSelectionState;
|
|
48
|
+
setAllocationSelection: OnChangeFn<RowSelectionState>;
|
|
49
|
+
bulkActionTarget: string | null;
|
|
50
|
+
handleBulkDelete: DeleteFn;
|
|
51
|
+
onCreate: () => void;
|
|
52
|
+
onOpenRoute: (allocationId: string) => void;
|
|
53
|
+
onEdit: (row: ResourceAllocationRow) => void;
|
|
54
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=resources-tabs-primary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources-tabs-primary.d.ts","sourceRoot":"","sources":["../../src/components/resources-tabs-primary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACrF,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAA;AAalC,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE;IACnB,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAEnB,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE;IACrB,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AA0JnB,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,SAAS,EAAE,cAAc,EAAE,CAAA;IAC3B,iBAAiB,EAAE,WAAW,EAAE,CAAA;IAChC,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,oBAAoB,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAA;IACnD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,QAAQ,CAAA;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,MAAM,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAA;CACnC,2CA+EA;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,aAAa,EAAE,eAAe,EAAE,CAAA;IAChC,aAAa,EAAE,iBAAiB,CAAA;IAChC,gBAAgB,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAC/C,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,QAAQ,CAAA;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,MAAM,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;CACvC,2CA+EA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,mBAAmB,EAAE,qBAAqB,EAAE,CAAA;IAC5C,mBAAmB,EAAE,iBAAiB,CAAA;IACtC,sBAAsB,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAA;IACrD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,EAAE,QAAQ,CAAA;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,MAAM,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;CAC7C,2CA2CA"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { formatSelectionLabel, labelById, } from "@voyantjs/resources-react";
|
|
3
|
+
import { Badge, Button, ConfirmActionButton, SelectionActionBar, } from "@voyantjs/voyant-ui/components";
|
|
4
|
+
import { DataTable } from "@voyantjs/voyant-ui/components/data-table";
|
|
5
|
+
import { DataTableColumnHeader } from "@voyantjs/voyant-ui/components/data-table-column-header";
|
|
6
|
+
import { TabsContent } from "@voyantjs/voyant-ui/components/tabs";
|
|
7
|
+
import { ExternalLink } from "lucide-react";
|
|
8
|
+
import { ResourcesSectionHeader } from "./resources-section-header";
|
|
9
|
+
const resourceColumns = (suppliers, onView) => [
|
|
10
|
+
{
|
|
11
|
+
accessorKey: "name",
|
|
12
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Resource" }),
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
accessorKey: "kind",
|
|
16
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Kind" }),
|
|
17
|
+
cell: ({ row }) => (_jsx(Badge, { variant: "outline", className: "capitalize", children: row.original.kind })),
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: "supplierId",
|
|
21
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Supplier" }),
|
|
22
|
+
cell: ({ row }) => labelById(suppliers, row.original.supplierId),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
accessorKey: "capacity",
|
|
26
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Capacity" }),
|
|
27
|
+
cell: ({ row }) => row.original.capacity ?? "-",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
accessorKey: "active",
|
|
31
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Status" }),
|
|
32
|
+
cell: ({ row }) => (_jsx(Badge, { variant: row.original.active ? "default" : "secondary", children: row.original.active ? "Active" : "Inactive" })),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "view",
|
|
36
|
+
header: "View",
|
|
37
|
+
cell: ({ row }) => (_jsxs(Button, { variant: "ghost", size: "sm", onClick: (event) => {
|
|
38
|
+
event.stopPropagation();
|
|
39
|
+
onView(row.original.id);
|
|
40
|
+
}, children: [_jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), "Open"] })),
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
const poolColumns = (products, onView) => [
|
|
44
|
+
{
|
|
45
|
+
accessorKey: "name",
|
|
46
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Pool" }),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
accessorKey: "kind",
|
|
50
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Kind" }),
|
|
51
|
+
cell: ({ row }) => (_jsx(Badge, { variant: "outline", className: "capitalize", children: row.original.kind })),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
accessorKey: "productId",
|
|
55
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Product" }),
|
|
56
|
+
cell: ({ row }) => labelById(products, row.original.productId),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
accessorKey: "sharedCapacity",
|
|
60
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Shared Capacity" }),
|
|
61
|
+
cell: ({ row }) => row.original.sharedCapacity ?? "-",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "view",
|
|
65
|
+
header: "View",
|
|
66
|
+
cell: ({ row }) => (_jsxs(Button, { variant: "ghost", size: "sm", onClick: (event) => {
|
|
67
|
+
event.stopPropagation();
|
|
68
|
+
onView(row.original.id);
|
|
69
|
+
}, children: [_jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), "Open"] })),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
const allocationColumns = (pools, products, onView) => [
|
|
73
|
+
{
|
|
74
|
+
accessorKey: "poolId",
|
|
75
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Pool" }),
|
|
76
|
+
cell: ({ row }) => labelById(pools, row.original.poolId),
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
accessorKey: "productId",
|
|
80
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Product" }),
|
|
81
|
+
cell: ({ row }) => labelById(products, row.original.productId),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
accessorKey: "allocationMode",
|
|
85
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Mode" }),
|
|
86
|
+
cell: ({ row }) => (_jsx(Badge, { variant: "outline", className: "capitalize", children: row.original.allocationMode })),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
accessorKey: "quantityRequired",
|
|
90
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Qty Required" }),
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
accessorKey: "priority",
|
|
94
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Priority" }),
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: "view",
|
|
98
|
+
header: "View",
|
|
99
|
+
cell: ({ row }) => (_jsxs(Button, { variant: "ghost", size: "sm", onClick: (event) => {
|
|
100
|
+
event.stopPropagation();
|
|
101
|
+
onView(row.original.id);
|
|
102
|
+
}, children: [_jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), "Open"] })),
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
export function ResourcesTab(props) {
|
|
106
|
+
return (_jsxs(TabsContent, { value: "resources", className: "space-y-4", children: [_jsx(ResourcesSectionHeader, { title: "Resources", description: "Guides, vehicles, rooms, and other assignable assets.", actionLabel: "New Resource", onAction: props.onCreate }), _jsx(DataTable, { columns: resourceColumns(props.suppliers, props.onOpenRoute), data: props.filteredResources, emptyMessage: "No resources match the current filters.", enableRowSelection: true, getRowId: (row) => row.id, rowSelection: props.resourceSelection, onRowSelectionChange: props.setResourceSelection, renderSelectionActions: ({ selectedRows, clearSelection }) => (_jsxs(SelectionActionBar, { selectedCount: selectedRows.length, onClear: clearSelection, children: [_jsx(ConfirmActionButton, { buttonLabel: "Activate", confirmLabel: "Activate Resources", title: `Activate ${formatSelectionLabel(selectedRows.length, "resource")}?`, description: "This makes the selected resources available again for assignment and planning.", disabled: props.bulkActionTarget === "resources-activate", onConfirm: () => props.handleBulkUpdate({
|
|
107
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
108
|
+
endpoint: "/v1/resources/resources",
|
|
109
|
+
target: "resources-activate",
|
|
110
|
+
noun: "resource",
|
|
111
|
+
payload: { active: true },
|
|
112
|
+
successVerb: "Activated",
|
|
113
|
+
clearSelection,
|
|
114
|
+
}) }), _jsx(ConfirmActionButton, { buttonLabel: "Deactivate", confirmLabel: "Deactivate Resources", title: `Deactivate ${formatSelectionLabel(selectedRows.length, "resource")}?`, description: "This preserves the selected resources but removes them from active operational use.", disabled: props.bulkActionTarget === "resources-deactivate", onConfirm: () => props.handleBulkUpdate({
|
|
115
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
116
|
+
endpoint: "/v1/resources/resources",
|
|
117
|
+
target: "resources-deactivate",
|
|
118
|
+
noun: "resource",
|
|
119
|
+
payload: { active: false },
|
|
120
|
+
successVerb: "Deactivated",
|
|
121
|
+
clearSelection,
|
|
122
|
+
}) }), _jsx(ConfirmActionButton, { buttonLabel: "Delete Selected", confirmLabel: "Delete Resources", title: `Delete ${formatSelectionLabel(selectedRows.length, "resource")}?`, description: "This permanently removes the selected resources. Use Deactivate if you only need to take them out of rotation.", disabled: props.bulkActionTarget === "resources-delete", variant: "destructive", confirmVariant: "destructive", onConfirm: () => props.handleBulkDelete({
|
|
123
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
124
|
+
endpoint: "/v1/resources/resources",
|
|
125
|
+
target: "resources-delete",
|
|
126
|
+
noun: "resource",
|
|
127
|
+
clearSelection,
|
|
128
|
+
}) })] })), onRowClick: (row) => props.onEdit(row.original) })] }));
|
|
129
|
+
}
|
|
130
|
+
export function PoolsTab(props) {
|
|
131
|
+
return (_jsxs(TabsContent, { value: "pools", className: "space-y-4", children: [_jsx(ResourcesSectionHeader, { title: "Pools", description: "Shared capacity groups by product or operational need.", actionLabel: "New Pool", onAction: props.onCreate }), _jsx(DataTable, { columns: poolColumns(props.products, props.onOpenRoute), data: props.filteredPools, emptyMessage: "No pools match the current filters.", enableRowSelection: true, getRowId: (row) => row.id, rowSelection: props.poolSelection, onRowSelectionChange: props.setPoolSelection, renderSelectionActions: ({ selectedRows, clearSelection }) => (_jsxs(SelectionActionBar, { selectedCount: selectedRows.length, onClear: clearSelection, children: [_jsx(ConfirmActionButton, { buttonLabel: "Activate", confirmLabel: "Activate Pools", title: `Activate ${formatSelectionLabel(selectedRows.length, "pool")}?`, description: "This re-enables the selected resource pools for live capacity planning.", disabled: props.bulkActionTarget === "pools-activate", onConfirm: () => props.handleBulkUpdate({
|
|
132
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
133
|
+
endpoint: "/v1/resources/pools",
|
|
134
|
+
target: "pools-activate",
|
|
135
|
+
noun: "pool",
|
|
136
|
+
payload: { active: true },
|
|
137
|
+
successVerb: "Activated",
|
|
138
|
+
clearSelection,
|
|
139
|
+
}) }), _jsx(ConfirmActionButton, { buttonLabel: "Deactivate", confirmLabel: "Deactivate Pools", title: `Deactivate ${formatSelectionLabel(selectedRows.length, "pool")}?`, description: "This keeps the selected pools for reference but removes them from active planning.", disabled: props.bulkActionTarget === "pools-deactivate", onConfirm: () => props.handleBulkUpdate({
|
|
140
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
141
|
+
endpoint: "/v1/resources/pools",
|
|
142
|
+
target: "pools-deactivate",
|
|
143
|
+
noun: "pool",
|
|
144
|
+
payload: { active: false },
|
|
145
|
+
successVerb: "Deactivated",
|
|
146
|
+
clearSelection,
|
|
147
|
+
}) }), _jsx(ConfirmActionButton, { buttonLabel: "Delete Selected", confirmLabel: "Delete Pools", title: `Delete ${formatSelectionLabel(selectedRows.length, "pool")}?`, description: "This permanently removes the selected pools and any pool-level grouping they provide.", disabled: props.bulkActionTarget === "pools-delete", variant: "destructive", confirmVariant: "destructive", onConfirm: () => props.handleBulkDelete({
|
|
148
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
149
|
+
endpoint: "/v1/resources/pools",
|
|
150
|
+
target: "pools-delete",
|
|
151
|
+
noun: "pool",
|
|
152
|
+
clearSelection,
|
|
153
|
+
}) })] })), onRowClick: (row) => props.onEdit(row.original) })] }));
|
|
154
|
+
}
|
|
155
|
+
export function AllocationsTab(props) {
|
|
156
|
+
return (_jsxs(TabsContent, { value: "allocations", className: "space-y-4", children: [_jsx(ResourcesSectionHeader, { title: "Allocations", description: "Attach pools to products, rules, and start times.", actionLabel: "New Allocation", onAction: props.onCreate }), _jsx(DataTable, { columns: allocationColumns(props.pools, props.products, props.onOpenRoute), data: props.filteredAllocations, emptyMessage: "No allocations match the current filters.", enableRowSelection: true, getRowId: (row) => row.id, rowSelection: props.allocationSelection, onRowSelectionChange: props.setAllocationSelection, renderSelectionActions: ({ selectedRows, clearSelection }) => (_jsx(SelectionActionBar, { selectedCount: selectedRows.length, onClear: clearSelection, children: _jsx(ConfirmActionButton, { buttonLabel: "Delete Selected", confirmLabel: "Delete Allocations", title: `Delete ${formatSelectionLabel(selectedRows.length, "allocation")}?`, description: "This permanently removes the selected allocation rules from resource planning.", disabled: props.bulkActionTarget === "allocations-delete", variant: "destructive", confirmVariant: "destructive", onConfirm: () => props.handleBulkDelete({
|
|
157
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
158
|
+
endpoint: "/v1/resources/allocations",
|
|
159
|
+
target: "allocations-delete",
|
|
160
|
+
noun: "allocation",
|
|
161
|
+
clearSelection,
|
|
162
|
+
}) }) })), onRowClick: (row) => props.onEdit(row.original) })] }));
|
|
163
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { OnChangeFn, RowSelectionState } from "@tanstack/react-table";
|
|
2
|
+
import { type BookingOption, type ResourceCloseoutRow, type ResourceRow, type ResourceSlotAssignmentRow, type SlotOption } from "@voyantjs/resources-react";
|
|
3
|
+
type BulkFn = (args: {
|
|
4
|
+
ids: string[];
|
|
5
|
+
endpoint: string;
|
|
6
|
+
target: string;
|
|
7
|
+
noun: string;
|
|
8
|
+
payload: Record<string, unknown>;
|
|
9
|
+
successVerb: string;
|
|
10
|
+
clearSelection: () => void;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
type DeleteFn = (args: {
|
|
13
|
+
ids: string[];
|
|
14
|
+
endpoint: string;
|
|
15
|
+
target: string;
|
|
16
|
+
noun: string;
|
|
17
|
+
clearSelection: () => void;
|
|
18
|
+
}) => Promise<void>;
|
|
19
|
+
export declare function AssignmentsTab(props: {
|
|
20
|
+
slots: SlotOption[];
|
|
21
|
+
resources: ResourceRow[];
|
|
22
|
+
bookings: BookingOption[];
|
|
23
|
+
filteredAssignments: ResourceSlotAssignmentRow[];
|
|
24
|
+
assignmentSelection: RowSelectionState;
|
|
25
|
+
setAssignmentSelection: OnChangeFn<RowSelectionState>;
|
|
26
|
+
bulkActionTarget: string | null;
|
|
27
|
+
handleBulkUpdate: BulkFn;
|
|
28
|
+
handleBulkDelete: DeleteFn;
|
|
29
|
+
onCreate: () => void;
|
|
30
|
+
onOpenRoute: (assignmentId: string) => void;
|
|
31
|
+
onEdit: (row: ResourceSlotAssignmentRow) => void;
|
|
32
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export declare function CloseoutsTab(props: {
|
|
34
|
+
resources: ResourceRow[];
|
|
35
|
+
filteredCloseouts: ResourceCloseoutRow[];
|
|
36
|
+
closeoutSelection: RowSelectionState;
|
|
37
|
+
setCloseoutSelection: OnChangeFn<RowSelectionState>;
|
|
38
|
+
bulkActionTarget: string | null;
|
|
39
|
+
handleBulkDelete: DeleteFn;
|
|
40
|
+
onCreate: () => void;
|
|
41
|
+
onEdit: (row: ResourceCloseoutRow) => void;
|
|
42
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=resources-tabs-secondary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources-tabs-secondary.d.ts","sourceRoot":"","sources":["../../src/components/resources-tabs-secondary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACrF,OAAO,EACL,KAAK,aAAa,EAIlB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,yBAAyB,EAC9B,KAAK,UAAU,EAEhB,MAAM,2BAA2B,CAAA;AAalC,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE;IACnB,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAEnB,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE;IACrB,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AA2FnB,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,mBAAmB,EAAE,yBAAyB,EAAE,CAAA;IAChD,mBAAmB,EAAE,iBAAiB,CAAA;IACtC,sBAAsB,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAA;IACrD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,QAAQ,CAAA;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,MAAM,EAAE,CAAC,GAAG,EAAE,yBAAyB,KAAK,IAAI,CAAA;CACjD,2CA+EA;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;IACxC,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,oBAAoB,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAA;IACnD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,EAAE,QAAQ,CAAA;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,MAAM,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAC3C,2CA2CA"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { formatDateTime, formatSelectionLabel, labelById, slotLabel, } from "@voyantjs/resources-react";
|
|
3
|
+
import { Badge, Button, ConfirmActionButton, SelectionActionBar, } from "@voyantjs/voyant-ui/components";
|
|
4
|
+
import { DataTable } from "@voyantjs/voyant-ui/components/data-table";
|
|
5
|
+
import { DataTableColumnHeader } from "@voyantjs/voyant-ui/components/data-table-column-header";
|
|
6
|
+
import { TabsContent } from "@voyantjs/voyant-ui/components/tabs";
|
|
7
|
+
import { ExternalLink } from "lucide-react";
|
|
8
|
+
import { ResourcesSectionHeader } from "./resources-section-header";
|
|
9
|
+
const assignmentColumns = (slots, resources, bookings, onView) => [
|
|
10
|
+
{
|
|
11
|
+
accessorKey: "slotId",
|
|
12
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Slot" }),
|
|
13
|
+
cell: ({ row }) => slotLabel(slots.find((slot) => slot.id === row.original.slotId) ?? {
|
|
14
|
+
id: row.original.slotId,
|
|
15
|
+
productId: "",
|
|
16
|
+
dateLocal: row.original.slotId,
|
|
17
|
+
startsAt: row.original.slotId,
|
|
18
|
+
}),
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
accessorKey: "resourceId",
|
|
22
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Resource" }),
|
|
23
|
+
cell: ({ row }) => labelById(resources, row.original.resourceId),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
accessorKey: "bookingId",
|
|
27
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Booking" }),
|
|
28
|
+
cell: ({ row }) => labelById(bookings, row.original.bookingId),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
accessorKey: "status",
|
|
32
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Status" }),
|
|
33
|
+
cell: ({ row }) => (_jsx(Badge, { variant: "outline", className: "capitalize", children: row.original.status })),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
accessorKey: "releasedAt",
|
|
37
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Released" }),
|
|
38
|
+
cell: ({ row }) => formatDateTime(row.original.releasedAt),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "view",
|
|
42
|
+
header: "View",
|
|
43
|
+
cell: ({ row }) => (_jsxs(Button, { variant: "ghost", size: "sm", onClick: (event) => {
|
|
44
|
+
event.stopPropagation();
|
|
45
|
+
onView(row.original.id);
|
|
46
|
+
}, children: [_jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), "Open"] })),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
const closeoutColumns = (resources) => [
|
|
50
|
+
{
|
|
51
|
+
accessorKey: "resourceId",
|
|
52
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Resource" }),
|
|
53
|
+
cell: ({ row }) => labelById(resources, row.original.resourceId),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
accessorKey: "dateLocal",
|
|
57
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Date" }),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
accessorKey: "startsAt",
|
|
61
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Starts" }),
|
|
62
|
+
cell: ({ row }) => formatDateTime(row.original.startsAt),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
accessorKey: "endsAt",
|
|
66
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Ends" }),
|
|
67
|
+
cell: ({ row }) => formatDateTime(row.original.endsAt),
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
accessorKey: "reason",
|
|
71
|
+
header: ({ column }) => _jsx(DataTableColumnHeader, { column: column, title: "Reason" }),
|
|
72
|
+
cell: ({ row }) => row.original.reason ?? "-",
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
export function AssignmentsTab(props) {
|
|
76
|
+
return (_jsxs(TabsContent, { value: "assignments", className: "space-y-4", children: [_jsx(ResourcesSectionHeader, { title: "Slot Assignments", description: "Reserve or assign specific resources against live slots and bookings.", actionLabel: "New Assignment", onAction: props.onCreate }), _jsx(DataTable, { columns: assignmentColumns(props.slots, props.resources, props.bookings, props.onOpenRoute), data: props.filteredAssignments, emptyMessage: "No assignments match the current filters.", enableRowSelection: true, getRowId: (row) => row.id, rowSelection: props.assignmentSelection, onRowSelectionChange: props.setAssignmentSelection, renderSelectionActions: ({ selectedRows, clearSelection }) => (_jsxs(SelectionActionBar, { selectedCount: selectedRows.length, onClear: clearSelection, children: [_jsx(ConfirmActionButton, { buttonLabel: "Assign", confirmLabel: "Mark Assigned", title: `Mark ${formatSelectionLabel(selectedRows.length, "assignment")} as assigned?`, description: "This marks the selected reservations as actively assigned without deleting any linkage.", disabled: props.bulkActionTarget === "assignments-assigned", onConfirm: () => props.handleBulkUpdate({
|
|
77
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
78
|
+
endpoint: "/v1/resources/slot-assignments",
|
|
79
|
+
target: "assignments-assigned",
|
|
80
|
+
noun: "assignment",
|
|
81
|
+
payload: { status: "assigned" },
|
|
82
|
+
successVerb: "Updated",
|
|
83
|
+
clearSelection,
|
|
84
|
+
}) }), _jsx(ConfirmActionButton, { buttonLabel: "Release", confirmLabel: "Release Assignments", title: `Release ${formatSelectionLabel(selectedRows.length, "assignment")}?`, description: "This marks the selected reservations as released while keeping the assignment history intact.", disabled: props.bulkActionTarget === "assignments-released", onConfirm: () => props.handleBulkUpdate({
|
|
85
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
86
|
+
endpoint: "/v1/resources/slot-assignments",
|
|
87
|
+
target: "assignments-released",
|
|
88
|
+
noun: "assignment",
|
|
89
|
+
payload: { status: "released" },
|
|
90
|
+
successVerb: "Released",
|
|
91
|
+
clearSelection,
|
|
92
|
+
}) }), _jsx(ConfirmActionButton, { buttonLabel: "Delete Selected", confirmLabel: "Delete Assignments", title: `Delete ${formatSelectionLabel(selectedRows.length, "assignment")}?`, description: "This permanently removes the selected slot assignments. Use Release if you only need to free the resource.", disabled: props.bulkActionTarget === "assignments-delete", variant: "destructive", confirmVariant: "destructive", onConfirm: () => props.handleBulkDelete({
|
|
93
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
94
|
+
endpoint: "/v1/resources/slot-assignments",
|
|
95
|
+
target: "assignments-delete",
|
|
96
|
+
noun: "assignment",
|
|
97
|
+
clearSelection,
|
|
98
|
+
}) })] })), onRowClick: (row) => props.onEdit(row.original) })] }));
|
|
99
|
+
}
|
|
100
|
+
export function CloseoutsTab(props) {
|
|
101
|
+
return (_jsxs(TabsContent, { value: "closeouts", className: "space-y-4", children: [_jsx(ResourcesSectionHeader, { title: "Resource Closeouts", description: "Block assets for maintenance, charter use, or operational conflicts.", actionLabel: "New Closeout", onAction: props.onCreate }), _jsx(DataTable, { columns: closeoutColumns(props.resources), data: props.filteredCloseouts, emptyMessage: "No closeouts match the current filters.", enableRowSelection: true, getRowId: (row) => row.id, rowSelection: props.closeoutSelection, onRowSelectionChange: props.setCloseoutSelection, renderSelectionActions: ({ selectedRows, clearSelection }) => (_jsx(SelectionActionBar, { selectedCount: selectedRows.length, onClear: clearSelection, children: _jsx(ConfirmActionButton, { buttonLabel: "Delete Selected", confirmLabel: "Delete Closeouts", title: `Delete ${formatSelectionLabel(selectedRows.length, "closeout")}?`, description: "This permanently removes the selected closeouts and may return the resources to operational use.", disabled: props.bulkActionTarget === "closeouts-delete", variant: "destructive", confirmVariant: "destructive", onConfirm: () => props.handleBulkDelete({
|
|
102
|
+
ids: selectedRows.map((row) => row.original.id),
|
|
103
|
+
endpoint: "/v1/resources/closeouts",
|
|
104
|
+
target: "closeouts-delete",
|
|
105
|
+
noun: "closeout",
|
|
106
|
+
clearSelection,
|
|
107
|
+
}) }) })), onRowClick: (row) => props.onEdit(row.original) })] }));
|
|
108
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ResourcesOverview } from "./components/resources-overview";
|
|
2
|
+
export { ResourcesSectionHeader } from "./components/resources-section-header";
|
|
3
|
+
export { AllocationsTab, PoolsTab, ResourcesTab } from "./components/resources-tabs-primary";
|
|
4
|
+
export { AssignmentsTab, CloseoutsTab } from "./components/resources-tabs-secondary";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AAC5F,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ResourcesOverview } from "./components/resources-overview";
|
|
2
|
+
export { ResourcesSectionHeader } from "./components/resources-section-header";
|
|
3
|
+
export { AllocationsTab, PoolsTab, ResourcesTab } from "./components/resources-tabs-primary";
|
|
4
|
+
export { AssignmentsTab, CloseoutsTab } from "./components/resources-tabs-secondary";
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voyantjs/resources-ui",
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/voyantjs/voyant.git",
|
|
8
|
+
"directory": "packages/resources-ui"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts",
|
|
14
|
+
"./components/*": "./src/components/*.tsx"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.build.json",
|
|
18
|
+
"clean": "rm -rf dist",
|
|
19
|
+
"prepack": "pnpm run build",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"lint": "biome check src/",
|
|
22
|
+
"test": "vitest run --passWithNoTests"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@tanstack/react-query": "^5.0.0",
|
|
26
|
+
"@tanstack/react-table": "^8.0.0",
|
|
27
|
+
"@voyantjs/resources-react": "workspace:*",
|
|
28
|
+
"@voyantjs/voyant-ui": "workspace:*",
|
|
29
|
+
"react": "^19.0.0",
|
|
30
|
+
"react-dom": "^19.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@tanstack/react-query": "^5.96.2",
|
|
34
|
+
"@tanstack/react-table": "^8.21.3",
|
|
35
|
+
"@types/react": "^19.2.14",
|
|
36
|
+
"@types/react-dom": "^19.2.3",
|
|
37
|
+
"@voyantjs/resources-react": "workspace:*",
|
|
38
|
+
"@voyantjs/voyant-typescript-config": "workspace:*",
|
|
39
|
+
"@voyantjs/voyant-ui": "workspace:*",
|
|
40
|
+
"lucide-react": "^0.475.0",
|
|
41
|
+
"react": "^19.2.4",
|
|
42
|
+
"react-dom": "^19.2.4",
|
|
43
|
+
"typescript": "^6.0.2",
|
|
44
|
+
"vitest": "^4.1.2"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public",
|
|
51
|
+
"exports": {
|
|
52
|
+
".": {
|
|
53
|
+
"types": "./dist/index.d.ts",
|
|
54
|
+
"import": "./dist/index.js"
|
|
55
|
+
},
|
|
56
|
+
"./components/*": {
|
|
57
|
+
"types": "./dist/components/*.d.ts",
|
|
58
|
+
"import": "./dist/components/*.js"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"main": "./dist/index.js",
|
|
62
|
+
"types": "./dist/index.d.ts"
|
|
63
|
+
}
|
|
64
|
+
}
|