@upbound/monarch-blocks 0.5.0 → 0.6.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/dist/index.js CHANGED
@@ -67,6 +67,9 @@ var twMerge = extendTailwindMerge({
67
67
  function cn(...inputs) {
68
68
  return twMerge(clsx(inputs));
69
69
  }
70
+ function sortBy(items, getKey) {
71
+ return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));
72
+ }
70
73
 
71
74
  // src/hooks/use-mounted.ts
72
75
  import { useSyncExternalStore } from "react";
@@ -1279,7 +1282,10 @@ function CelAddFilterButton({
1279
1282
  list.push(column);
1280
1283
  groupMap.set(key, list);
1281
1284
  }
1282
- const groups = Array.from(groupMap.entries()).map(([value, items]) => ({ value, items }));
1285
+ const groups = sortBy(
1286
+ Array.from(groupMap.entries()).map(([value, items]) => ({ value, items: sortBy(items, (item) => item.title) })),
1287
+ (group) => group.value
1288
+ );
1283
1289
  return /* @__PURE__ */ jsxs(
1284
1290
  Combobox,
1285
1291
  {
@@ -1507,7 +1513,7 @@ function CelCheckboxComboboxPill({
1507
1513
  container
1508
1514
  }) {
1509
1515
  var _a;
1510
- const options = (_a = columnDef.options) != null ? _a : [];
1516
+ const options = sortBy((_a = columnDef.options) != null ? _a : [], (o) => o.label);
1511
1517
  const value = isCheckboxCelValue(condition.value) ? condition.value : [];
1512
1518
  const selected = options.filter((option) => value.includes(option.value));
1513
1519
  const allowedOperators = getAllowedOperators(columnDef);
@@ -1596,7 +1602,7 @@ function CelRadioComboboxPill({
1596
1602
  container
1597
1603
  }) {
1598
1604
  var _a, _b;
1599
- const options = (_a = columnDef.options) != null ? _a : [];
1605
+ const options = sortBy((_a = columnDef.options) != null ? _a : [], (o) => o.label);
1600
1606
  const value = typeof condition.value === "string" ? condition.value : "";
1601
1607
  const selected = (_b = options.find((option) => option.value === value)) != null ? _b : null;
1602
1608
  const allowedOperators = getAllowedOperators(columnDef);
@@ -2761,7 +2767,7 @@ function ChatThread({
2761
2767
  ] }, msg.id)),
2762
2768
  isThinking && /* @__PURE__ */ jsx5(ChatThinkingIndicator, {})
2763
2769
  ] }) }),
2764
- /* @__PURE__ */ jsx5(MessageScrollerButton, { direction: "end", children: /* @__PURE__ */ jsx5(Icon2, { name: "arrow-down" }) })
2770
+ /* @__PURE__ */ jsx5(MessageScrollerButton, { direction: "end", variant: "secondary", size: "icon-sm", children: /* @__PURE__ */ jsx5(Icon2, { name: "arrow-down" }) })
2765
2771
  ] }) }),
2766
2772
  /* @__PURE__ */ jsx5(
2767
2773
  ChatInput,
@@ -3143,7 +3149,15 @@ function CellContextualFilter({
3143
3149
  );
3144
3150
  }
3145
3151
  return /* @__PURE__ */ jsxs5(ContextMenuContent, { children: [
3146
- /* @__PURE__ */ jsx7(ContextMenuItem, { disabled, onClick: (event) => event.stopPropagation(), onSelect: handleSelect, children: "Filter by this value" }),
3152
+ /* @__PURE__ */ jsx7(
3153
+ ContextMenuItem,
3154
+ {
3155
+ disabled,
3156
+ onClick: (event) => event.stopPropagation(),
3157
+ onSelect: handleSelect,
3158
+ children: "Filter by this value"
3159
+ }
3160
+ ),
3147
3161
  contextualMenuActions.length > 0 && /* @__PURE__ */ jsxs5(Fragment4, { children: [
3148
3162
  /* @__PURE__ */ jsx7(ContextMenuSeparator, {}),
3149
3163
  contextualMenuActions.map(renderAction)
@@ -3475,8 +3489,25 @@ function RowActions({
3475
3489
  contentClassName
3476
3490
  }) {
3477
3491
  return /* @__PURE__ */ jsxs7(DropdownMenu3, { children: [
3478
- /* @__PURE__ */ jsx9(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx9(Button4, { variant: "ghost", size: "icon-xs", "aria-label": "Row actions", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx9(Icon5, { name: "ellipsis-vertical", size: "sm" }) }) }),
3479
- /* @__PURE__ */ jsx9(DropdownMenuContent3, { align, className: contentClassName, onClick: (event) => event.stopPropagation(), children })
3492
+ /* @__PURE__ */ jsx9(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx9(
3493
+ Button4,
3494
+ {
3495
+ variant: "ghost",
3496
+ size: "icon-xs",
3497
+ "aria-label": "Row actions",
3498
+ onClick: (e) => e.stopPropagation(),
3499
+ children: /* @__PURE__ */ jsx9(Icon5, { name: "ellipsis-vertical", size: "sm" })
3500
+ }
3501
+ ) }),
3502
+ /* @__PURE__ */ jsx9(
3503
+ DropdownMenuContent3,
3504
+ {
3505
+ align,
3506
+ className: contentClassName,
3507
+ onClick: (event) => event.stopPropagation(),
3508
+ children
3509
+ }
3510
+ )
3480
3511
  ] });
3481
3512
  }
3482
3513
  function RowActionItem({
@@ -4380,6 +4411,7 @@ function DataTablePagination({
4380
4411
  PaginationLink,
4381
4412
  {
4382
4413
  href: "#",
4414
+ size: "icon",
4383
4415
  isActive: page === currentPage,
4384
4416
  onClick: (e) => {
4385
4417
  e.preventDefault();
@@ -5021,6 +5053,9 @@ function composeRefs(...refs) {
5021
5053
  }
5022
5054
  };
5023
5055
  }
5056
+ function hasOrder(filter) {
5057
+ return typeof filter.order === "number";
5058
+ }
5024
5059
  function FilterBar(_a) {
5025
5060
  var _b = _a, {
5026
5061
  filters,
@@ -5042,7 +5077,8 @@ function FilterBar(_a) {
5042
5077
  "ref"
5043
5078
  ]);
5044
5079
  const usedKeys = new Set(activeFilters.map((f) => f.key));
5045
- const availableFilters = filters.filter((f) => !usedKeys.has(f.key));
5080
+ const remainingFilters = filters.filter((f) => !usedKeys.has(f.key));
5081
+ const availableFilters = filters.some(hasOrder) ? remainingFilters : sortBy(remainingFilters, (f) => f.label);
5046
5082
  const shouldShowFilters = availableFilters.length > 0 || activeFilters.length > 0;
5047
5083
  const [pendingOpenKey, setPendingOpenKey] = React9.useState(null);
5048
5084
  function handleAddFilter(key) {
@@ -5177,7 +5213,8 @@ function CheckboxFilterChip({
5177
5213
  onRemove
5178
5214
  }) {
5179
5215
  var _a, _b;
5180
- const { label, options, searchable = false } = definition;
5216
+ const { label, searchable = false } = definition;
5217
+ const options = sortBy(definition.options, (o) => o.label);
5181
5218
  const values = asCheckboxValue(value);
5182
5219
  const displayLabel = values.length === 0 ? "Any" : values.length === 1 ? (_b = (_a = options.find((o) => o.value === values[0])) == null ? void 0 : _a.label) != null ? _b : values[0] : `${values.length} selected`;
5183
5220
  function toggle(optionValue) {
@@ -5262,7 +5299,8 @@ function RadioFilterChip({
5262
5299
  onRemove
5263
5300
  }) {
5264
5301
  var _a, _b, _c;
5265
- const { label, options, searchable = false } = definition;
5302
+ const { label, searchable = false } = definition;
5303
+ const options = sortBy(definition.options, (o) => o.label);
5266
5304
  const selectedValue = asRadioValue(value);
5267
5305
  const displayLabel = selectedValue ? (_b = (_a = options.find((o) => o.value === selectedValue)) == null ? void 0 : _a.label) != null ? _b : selectedValue : "Any";
5268
5306
  const selected = (_c = options.find((o) => o.value === selectedValue)) != null ? _c : null;
@@ -5517,21 +5555,21 @@ function toFilterOption(opt) {
5517
5555
  return typeof opt === "string" ? { value: opt, label: opt } : { value: opt.value, label: opt.label };
5518
5556
  }
5519
5557
  function toFilterBarDefinition(key, filter) {
5520
- var _a, _b, _c;
5521
- const base = { key, label: filter.title, order: (_a = filter.order) != null ? _a : 0 };
5558
+ var _a, _b;
5559
+ const base = { key, label: filter.title, order: filter.order };
5522
5560
  if (isCheckboxColumnFilter(filter)) {
5523
5561
  const options = "options" in filter && filter.options ? filter.options : [];
5524
5562
  return __spreadProps(__spreadValues({}, base), {
5525
5563
  type: "checkbox",
5526
5564
  options: options.map(toFilterOption),
5527
- searchable: (_b = filter.searchable) != null ? _b : true
5565
+ searchable: (_a = filter.searchable) != null ? _a : true
5528
5566
  });
5529
5567
  }
5530
5568
  if (isRadioColumnFilter(filter)) {
5531
5569
  return __spreadProps(__spreadValues({}, base), {
5532
5570
  type: "radio",
5533
5571
  options: filter.options.map(toFilterOption),
5534
- searchable: (_c = filter.searchable) != null ? _c : true
5572
+ searchable: (_b = filter.searchable) != null ? _b : true
5535
5573
  });
5536
5574
  }
5537
5575
  if (isDateRangeColumnFilter(filter)) {
@@ -5564,7 +5602,12 @@ function ViewFilter({
5564
5602
  [columns]
5565
5603
  );
5566
5604
  const filterDefinitions = React10.useMemo(
5567
- () => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) => a.order - b.order),
5605
+ () => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) => {
5606
+ if (a.order == null && b.order == null) return 0;
5607
+ if (a.order == null) return 1;
5608
+ if (b.order == null) return -1;
5609
+ return a.order - b.order;
5610
+ }),
5568
5611
  [filterableColumns]
5569
5612
  );
5570
5613
  const emptyValueByKey = React10.useMemo(
@@ -6224,31 +6267,945 @@ function FloatingWidget({ title = "Ask AI", subtitle, menuItems, children, class
6224
6267
  );
6225
6268
  }
6226
6269
 
6270
+ // src/graph/graph-actions-provider.tsx
6271
+ import * as React14 from "react";
6272
+
6273
+ // src/graph/hooks/useGraphActionsContext.ts
6274
+ import { createContext as createContext3, useContext as useContext3 } from "react";
6275
+ var GraphActionsContext = createContext3(null);
6276
+ var useGraphActionsContext = () => {
6277
+ const context = useContext3(GraphActionsContext);
6278
+ if (!context) {
6279
+ throw new Error("useGraphActionsContext must be used within GraphActionsProvider");
6280
+ }
6281
+ return context;
6282
+ };
6283
+
6284
+ // src/graph/hooks/useGraphActions.ts
6285
+ import { useCallback as useCallback9, useState as useState12 } from "react";
6286
+
6287
+ // src/graph/graph-node.tsx
6288
+ import * as React13 from "react";
6289
+ import { getIncomers, getOutgoers, Handle, Position as Position2 } from "reactflow";
6290
+ import { Badge as Badge4, Card as Card2, Icon as Icon13, Spinner, Tooltip as Tooltip8, TooltipContent as TooltipContent7, TooltipTrigger as TooltipTrigger7 } from "@upbound/monarch-core";
6291
+
6292
+ // src/graph/consts.ts
6293
+ var GRAPH_NODE_WIDTH = 260;
6294
+ var GRAPH_NODE_HEIGHT = 106;
6295
+ var GRAPH_NODE_COLLAPSED_HEIGHT = 47;
6296
+ var GRAPH_NODE_SEP = 22;
6297
+ var GRAPH_RANK_SEP = 54;
6298
+
6299
+ // src/graph/graph-edge.tsx
6300
+ import { getSmoothStepPath, getStraightPath, Position } from "reactflow";
6301
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
6302
+ var GraphEdge = ({
6303
+ id,
6304
+ sourceX,
6305
+ sourceY,
6306
+ targetX,
6307
+ targetY,
6308
+ targetPosition
6309
+ }) => {
6310
+ const halfDistanceWidth = (targetX - sourceX) / 2;
6311
+ const [straightEdgePath] = getStraightPath({
6312
+ sourceX: sourceX - 4,
6313
+ sourceY,
6314
+ targetX: Math.max(sourceX + halfDistanceWidth, GRAPH_NODE_WIDTH / 2),
6315
+ targetY: sourceY
6316
+ });
6317
+ const [edgePath] = getSmoothStepPath({
6318
+ sourceX: Math.max(sourceX + halfDistanceWidth, GRAPH_NODE_WIDTH / 2),
6319
+ sourceY,
6320
+ sourcePosition: Position.Bottom,
6321
+ targetX: targetX + 4,
6322
+ targetY,
6323
+ targetPosition,
6324
+ borderRadius: 8,
6325
+ offset: 0
6326
+ });
6327
+ return /* @__PURE__ */ jsxs15("g", { id, className: "react-flow__edge-path", children: [
6328
+ /* @__PURE__ */ jsx19("path", { d: straightEdgePath, className: "stroke-border fill-transparent stroke-2" }),
6329
+ /* @__PURE__ */ jsx19("path", { d: edgePath, className: "stroke-border fill-transparent stroke-2" })
6330
+ ] });
6331
+ };
6332
+
6333
+ // src/graph/graph-node.tsx
6334
+ import { Fragment as Fragment10, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
6335
+ function isDefaultNode(node) {
6336
+ return node.type !== "loading";
6337
+ }
6338
+ function GraphNode(_a) {
6339
+ var _b = _a, { id, data } = _b, props = __objRest(_b, ["id", "data"]);
6340
+ var _a2, _b2;
6341
+ const { nodes: originalNodes, edges: originalEdges } = useGraphActionsContext();
6342
+ const nodes = originalNodes;
6343
+ const edges = originalEdges;
6344
+ const handleClick = React13.useCallback(() => {
6345
+ var _a3;
6346
+ (_a3 = data == null ? void 0 : data.onClick) == null ? void 0 : _a3.call(data, id, data);
6347
+ }, [data, id]);
6348
+ const compact = (_a2 = data == null ? void 0 : data.compact) != null ? _a2 : false;
6349
+ const state = (_b2 = data == null ? void 0 : data.state) != null ? _b2 : "default";
6350
+ const compactBadges = React13.useMemo(() => {
6351
+ const badges = data.badges.compact || [];
6352
+ if (state === "paused") {
6353
+ return [
6354
+ { children: /* @__PURE__ */ jsx20(Icon13, { name: "pause", size: "xs" }), variant: "secondary", tooltipContent: "Resource is paused" },
6355
+ ...badges
6356
+ ];
6357
+ }
6358
+ return badges;
6359
+ }, [data.badges.compact, state]);
6360
+ const defaultBadges = React13.useMemo(() => {
6361
+ const badges = data.badges.default || [];
6362
+ if (state === "paused") {
6363
+ return [
6364
+ {
6365
+ children: /* @__PURE__ */ jsxs16(Fragment10, { children: [
6366
+ /* @__PURE__ */ jsx20(Icon13, { name: "pause", size: "xs", className: "mr-1" }),
6367
+ " Paused"
6368
+ ] }),
6369
+ variant: "secondary",
6370
+ tooltipContent: "Resource is paused"
6371
+ },
6372
+ ...badges
6373
+ ];
6374
+ }
6375
+ return badges;
6376
+ }, [data.badges.default, state]);
6377
+ const currentNode = React13.useMemo(
6378
+ () => ({
6379
+ id,
6380
+ position: { x: 0, y: 0 },
6381
+ // Position not needed for edge calculations
6382
+ data,
6383
+ type: props.type
6384
+ }),
6385
+ [id, data, props.type]
6386
+ );
6387
+ const _hasIncomingEdge = React13.useMemo(() => {
6388
+ return getIncomers(currentNode, nodes, edges).length > 0;
6389
+ }, [currentNode, nodes, edges]);
6390
+ const hasOutgoingEdge = React13.useMemo(() => {
6391
+ return getOutgoers(currentNode, nodes, edges).length > 0;
6392
+ }, [currentNode, nodes, edges]);
6393
+ const targetX = GRAPH_NODE_WIDTH / 2 - 4;
6394
+ const sourceX = 4;
6395
+ return /* @__PURE__ */ jsxs16(
6396
+ Card2,
6397
+ {
6398
+ className: cn(
6399
+ "relative gap-1.5 overflow-visible rounded-lg py-0",
6400
+ `flex h-[106px]! w-[260px]! flex-col pt-2.5! pb-0!`,
6401
+ `hover:shadow-md motion-safe:transition-shadow`,
6402
+ compact && `h-[47px]!`
6403
+ ),
6404
+ style: { height: compact ? GRAPH_NODE_COLLAPSED_HEIGHT : GRAPH_NODE_HEIGHT, width: GRAPH_NODE_WIDTH },
6405
+ children: [
6406
+ /* @__PURE__ */ jsx20(
6407
+ Handle,
6408
+ {
6409
+ type: "target",
6410
+ position: Position2.Left,
6411
+ style: {
6412
+ visibility: "hidden",
6413
+ width: 0
6414
+ },
6415
+ isConnectable: false
6416
+ }
6417
+ ),
6418
+ /* @__PURE__ */ jsxs16("div", { className: "flex w-full flex-1 cursor-pointer flex-col", onClick: handleClick, children: [
6419
+ /* @__PURE__ */ jsxs16("div", { className: cn("flex w-full justify-between gap-1 px-2.5", compact && "flex-row-reverse items-start"), children: [
6420
+ !!compact && /* @__PURE__ */ jsxs16(Fragment10, { children: [
6421
+ compactBadges.length > 0 && /* @__PURE__ */ jsx20("div", { className: "flex shrink-0 flex-row items-center gap-1.5 overflow-hidden", children: compactBadges.map((_c, index) => {
6422
+ var _d = _c, { tooltipContent, variant } = _d, badge = __objRest(_d, ["tooltipContent", "variant"]);
6423
+ return /* @__PURE__ */ jsxs16(Tooltip8, { children: [
6424
+ /* @__PURE__ */ jsx20(TooltipTrigger7, { children: /* @__PURE__ */ jsx20(
6425
+ Badge4,
6426
+ __spreadProps(__spreadValues({
6427
+ variant
6428
+ }, badge), {
6429
+ className: "flex size-[20px]! cursor-default! items-center justify-center p-0!",
6430
+ children: badge.children
6431
+ })
6432
+ ) }),
6433
+ tooltipContent && /* @__PURE__ */ jsx20(TooltipContent7, { children: tooltipContent })
6434
+ ] }, index);
6435
+ }) }),
6436
+ state === "progressing" && /* @__PURE__ */ jsx20("div", { className: "flex shrink-0 flex-row items-center gap-1.5 overflow-hidden", children: /* @__PURE__ */ jsx20("div", { className: "flex size-[20px]! items-center justify-center", children: /* @__PURE__ */ jsx20(Spinner, { size: "sm" }) }) })
6437
+ ] }),
6438
+ /* @__PURE__ */ jsxs16("div", { className: "mr-auto grow-0 overflow-hidden", children: [
6439
+ /* @__PURE__ */ jsx20("h5", { className: "text-body-sm/tight truncate font-bold", children: data.title }),
6440
+ /* @__PURE__ */ jsx20("p", { className: "text-body-sm truncate leading-none", children: data.subtitle }),
6441
+ !compact && /* @__PURE__ */ jsx20("p", { className: "text-body-sm text-muted-foreground mt-1 truncate", children: data.name })
6442
+ ] }),
6443
+ /* @__PURE__ */ jsx20(
6444
+ "span",
6445
+ {
6446
+ className: cn(
6447
+ "bg-foreground text-background inline-flex h-[26px] w-auto shrink-0 items-center justify-center rounded-md px-[7px] text-[10px] font-semibold",
6448
+ ["progressing", "paused"].includes(state) && "opacity-30",
6449
+ data.typeDescriptors.className
6450
+ ),
6451
+ children: data.typeDescriptors.default
6452
+ }
6453
+ )
6454
+ ] }),
6455
+ !compact && /* @__PURE__ */ jsx20(Fragment10, { children: (defaultBadges.length > 0 || state === "progressing") && /* @__PURE__ */ jsxs16("div", { className: "mt-auto flex h-8 items-center border-t px-2.5", children: [
6456
+ /* @__PURE__ */ jsx20("div", { className: "flex gap-1.5 overflow-hidden overflow-x-auto", children: defaultBadges.map((_e, index) => {
6457
+ var _f = _e, { tooltipContent, variant } = _f, badge = __objRest(_f, ["tooltipContent", "variant"]);
6458
+ return /* @__PURE__ */ jsxs16(Tooltip8, { children: [
6459
+ /* @__PURE__ */ jsx20(TooltipTrigger7, { children: /* @__PURE__ */ jsx20(Badge4, __spreadProps(__spreadValues({ variant }, badge), { className: "cursor-default! py-px! whitespace-nowrap", children: badge.children })) }),
6460
+ tooltipContent && /* @__PURE__ */ jsx20(TooltipContent7, { children: tooltipContent })
6461
+ ] }, index);
6462
+ }) }),
6463
+ state === "progressing" && /* @__PURE__ */ jsx20("div", { className: "ml-auto flex size-[20px]! items-center justify-center", children: /* @__PURE__ */ jsx20(Spinner, { size: "sm" }) })
6464
+ ] }) })
6465
+ ] }),
6466
+ !!hasOutgoingEdge && /* @__PURE__ */ jsxs16(
6467
+ "div",
6468
+ {
6469
+ className: "absolute top-0 right-0 h-full w-auto translate-x-full",
6470
+ style: {
6471
+ width: GRAPH_RANK_SEP
6472
+ },
6473
+ children: [
6474
+ /* @__PURE__ */ jsx20("svg", { height: 20, width: GRAPH_NODE_SEP, className: "absolute top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsx20(
6475
+ GraphEdge,
6476
+ {
6477
+ id: `${id}-expadable`,
6478
+ sourceX,
6479
+ sourceY: 10,
6480
+ targetX,
6481
+ targetY: 10,
6482
+ sourcePosition: Position2.Right,
6483
+ targetPosition: Position2.Left,
6484
+ source: id,
6485
+ target: id,
6486
+ stopOpacity: 0
6487
+ }
6488
+ ) }),
6489
+ /* @__PURE__ */ jsxs16(Tooltip8, { children: [
6490
+ /* @__PURE__ */ jsx20(TooltipTrigger7, { asChild: true, children: /* @__PURE__ */ jsx20(
6491
+ "button",
6492
+ {
6493
+ type: "button",
6494
+ "aria-label": data.expanded ? "Collapse" : "Expand",
6495
+ className: "bg-foreground text-background hover:bg-foreground/90 focus-visible:ring-ring/30 absolute top-[calc(50%)] left-[calc(50%)] inline-flex size-4 -translate-1/2 items-center justify-center rounded-full p-0 text-center text-[10px] leading-none duration-150 outline-none focus-visible:ring-2 motion-safe:transition-colors",
6496
+ onClick: (e) => {
6497
+ var _a3;
6498
+ e.stopPropagation();
6499
+ (_a3 = data.onExpandToggle) == null ? void 0 : _a3.call(data, id);
6500
+ },
6501
+ children: /* @__PURE__ */ jsx20(Icon13, { name: data.expanded ? "minus" : "plus", size: "xs" })
6502
+ }
6503
+ ) }),
6504
+ /* @__PURE__ */ jsx20(TooltipContent7, { children: data.expanded ? "Collapse" : "Expand" })
6505
+ ] })
6506
+ ]
6507
+ }
6508
+ ),
6509
+ /* @__PURE__ */ jsx20(
6510
+ Handle,
6511
+ {
6512
+ type: "source",
6513
+ position: Position2.Right,
6514
+ style: {
6515
+ visibility: "hidden",
6516
+ width: 0
6517
+ },
6518
+ isConnectable: false
6519
+ }
6520
+ )
6521
+ ]
6522
+ }
6523
+ );
6524
+ }
6525
+ function GraphNodeSkeleton(_props) {
6526
+ const compact = false;
6527
+ return /* @__PURE__ */ jsxs16(
6528
+ Card2,
6529
+ {
6530
+ className: cn(
6531
+ `flex h-[106px]! w-[260px]! flex-col gap-1.5 rounded-lg px-0 py-0 pt-2.5! pb-0! hover:shadow-md motion-safe:transition-shadow`,
6532
+ compact && `h-[47px]!`
6533
+ ),
6534
+ children: [
6535
+ /* @__PURE__ */ jsx20(
6536
+ Handle,
6537
+ {
6538
+ type: "target",
6539
+ position: Position2.Left,
6540
+ style: {
6541
+ visibility: "hidden",
6542
+ width: 0
6543
+ },
6544
+ isConnectable: false
6545
+ }
6546
+ ),
6547
+ /* @__PURE__ */ jsxs16("div", { className: cn("flex w-full gap-1 px-2.5", compact && "flex-row-reverse"), children: [
6548
+ /* @__PURE__ */ jsxs16("div", { className: cn("grow-0 overflow-hidden", compact && "mr-auto"), children: [
6549
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted mb-1 h-3 w-16 animate-pulse rounded-sm" }),
6550
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted h-3 w-40 animate-pulse rounded-sm" }),
6551
+ !compact && /* @__PURE__ */ jsx20("div", { className: "bg-muted mt-2 h-3 w-48 animate-pulse rounded-sm" })
6552
+ ] }),
6553
+ /* @__PURE__ */ jsx20("div", { className: cn("bg-muted size-[26px] shrink-0 animate-pulse rounded-md", !compact && "ml-auto") })
6554
+ ] }),
6555
+ !compact && /* @__PURE__ */ jsx20("div", { className: "mt-auto flex h-8 items-center border-t px-2.5", children: /* @__PURE__ */ jsxs16("div", { className: "flex gap-1.5 overflow-hidden overflow-x-auto", children: [
6556
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted h-4 w-12 animate-pulse rounded-sm" }),
6557
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted h-4 w-12 animate-pulse rounded-sm" })
6558
+ ] }) }),
6559
+ /* @__PURE__ */ jsx20(
6560
+ Handle,
6561
+ {
6562
+ type: "source",
6563
+ position: Position2.Right,
6564
+ style: {
6565
+ visibility: "hidden",
6566
+ width: 0
6567
+ },
6568
+ isConnectable: false
6569
+ }
6570
+ )
6571
+ ]
6572
+ }
6573
+ );
6574
+ }
6575
+
6576
+ // src/graph/hooks/useGraphActions.ts
6577
+ var useGraphActions = (initialNodes = [], initialEdges = []) => {
6578
+ const [nodes, setNodes] = useState12(initialNodes);
6579
+ const [edges, setEdges] = useState12(initialEdges);
6580
+ const addNodes = useCallback9((newNodes) => {
6581
+ setNodes((prevNodes) => {
6582
+ const existingIds = new Set(prevNodes.map((node) => node.id));
6583
+ const uniqueNewNodes = newNodes.filter((node) => !existingIds.has(node.id));
6584
+ return [...prevNodes, ...uniqueNewNodes];
6585
+ });
6586
+ }, []);
6587
+ const addEdges = useCallback9((newEdges) => {
6588
+ setEdges((prevEdges) => {
6589
+ const existingIds = new Set(prevEdges.map((edge) => edge.id));
6590
+ const uniqueNewEdges = newEdges.filter((edge) => !existingIds.has(edge.id));
6591
+ return [...prevEdges, ...uniqueNewEdges];
6592
+ });
6593
+ }, []);
6594
+ const removeNodes = useCallback9((nodeIds) => {
6595
+ const nodeIdSet = new Set(nodeIds);
6596
+ setNodes((prevNodes) => prevNodes.filter((node) => !nodeIdSet.has(node.id)));
6597
+ setEdges((prevEdges) => prevEdges.filter((edge) => !nodeIdSet.has(edge.source) && !nodeIdSet.has(edge.target)));
6598
+ }, []);
6599
+ const removeEdges = useCallback9((edgeIds) => {
6600
+ const edgeIdSet = new Set(edgeIds);
6601
+ setEdges((prevEdges) => prevEdges.filter((edge) => !edgeIdSet.has(edge.id)));
6602
+ }, []);
6603
+ const resetGraph = useCallback9(() => {
6604
+ setNodes(initialNodes);
6605
+ setEdges(initialEdges);
6606
+ }, [initialNodes, initialEdges]);
6607
+ const updateNode = useCallback9((nodeId, node) => {
6608
+ setNodes((prevNodes) => prevNodes.map((n) => n.id === nodeId ? node : n));
6609
+ }, []);
6610
+ const toggleNodeExpansion = useCallback9((nodeId) => {
6611
+ setNodes(
6612
+ (prevNodes) => prevNodes.map((node) => {
6613
+ if (node.id === nodeId && isDefaultNode(node)) {
6614
+ return __spreadProps(__spreadValues({}, node), {
6615
+ data: __spreadProps(__spreadValues({}, node.data), {
6616
+ expanded: !node.data.expanded
6617
+ })
6618
+ });
6619
+ }
6620
+ return node;
6621
+ })
6622
+ );
6623
+ }, []);
6624
+ return {
6625
+ nodes,
6626
+ edges,
6627
+ addNodes,
6628
+ addEdges,
6629
+ removeNodes,
6630
+ removeEdges,
6631
+ setNodes,
6632
+ setEdges,
6633
+ resetGraph,
6634
+ updateNode,
6635
+ toggleNodeExpansion
6636
+ };
6637
+ };
6638
+
6639
+ // src/graph/graph-actions-provider.tsx
6640
+ import { jsx as jsx21 } from "react/jsx-runtime";
6641
+ var GraphActionsProvider = React14.forwardRef(
6642
+ ({ initialNodes = [], initialEdges = [], children }, ref) => {
6643
+ const graphActions = useGraphActions(initialNodes, initialEdges);
6644
+ React14.useImperativeHandle(
6645
+ ref,
6646
+ () => ({
6647
+ addNodes: graphActions.addNodes,
6648
+ addEdges: graphActions.addEdges,
6649
+ setNodes: graphActions.setNodes,
6650
+ setEdges: graphActions.setEdges,
6651
+ toggleNodeExpansion: graphActions.toggleNodeExpansion,
6652
+ updateNode: graphActions.updateNode,
6653
+ reset: graphActions.resetGraph
6654
+ }),
6655
+ [graphActions]
6656
+ );
6657
+ return /* @__PURE__ */ jsx21(GraphActionsContext.Provider, { value: graphActions, children });
6658
+ }
6659
+ );
6660
+ GraphActionsProvider.displayName = "GraphActionsProvider";
6661
+
6662
+ // src/graph/graph.tsx
6663
+ import * as React16 from "react";
6664
+ import {
6665
+ getCoreRowModel as getCoreRowModel2,
6666
+ getFacetedRowModel as getFacetedRowModel2,
6667
+ getFacetedUniqueValues as getFacetedUniqueValues2,
6668
+ getFilteredRowModel as getFilteredRowModel2,
6669
+ useReactTable as useReactTable2
6670
+ } from "@tanstack/react-table";
6671
+ import { Icon as Icon14, InputGroup as InputGroup4, InputGroupAddon as InputGroupAddon4, InputGroupInput as InputGroupInput3 } from "@upbound/monarch-core";
6672
+
6673
+ // src/graph/graph-view.tsx
6674
+ import * as React15 from "react";
6675
+ import {
6676
+ Background,
6677
+ Controls,
6678
+ MiniMap,
6679
+ ReactFlow,
6680
+ ReactFlowProvider,
6681
+ useReactFlow
6682
+ } from "reactflow";
6683
+
6684
+ // src/graph/hooks/useAutoLayout.ts
6685
+ import { useMemo as useMemo10 } from "react";
6686
+ import { Position as Position3 } from "reactflow";
6687
+ var TILE_HORIZONTAL_DISTANCE = GRAPH_RANK_SEP;
6688
+ var TILE_VERTICAL_DISTANCE = GRAPH_NODE_SEP;
6689
+ var TILE_HEIGHT = GRAPH_NODE_HEIGHT;
6690
+ var TILE_WIDTH = GRAPH_NODE_WIDTH;
6691
+ var getNodeDepth = (nodeId, edges, visited = /* @__PURE__ */ new Set(), maxDepth = 100) => {
6692
+ if (visited.has(nodeId)) {
6693
+ console.warn(`Cycle detected in graph at node: ${nodeId}. Returning depth 0 to prevent infinite recursion.`);
6694
+ return 0;
6695
+ }
6696
+ if (visited.size >= maxDepth) {
6697
+ console.warn(`Maximum depth limit (${maxDepth}) reached for node: ${nodeId}.`);
6698
+ return visited.size;
6699
+ }
6700
+ const parentEdge = edges.find((edge) => edge.target === nodeId);
6701
+ if (!parentEdge) {
6702
+ return 0;
6703
+ }
6704
+ const newVisited = /* @__PURE__ */ new Set([...visited, nodeId]);
6705
+ return 1 + getNodeDepth(parentEdge.source, edges, newVisited, maxDepth);
6706
+ };
6707
+ var flatNodeTree = (nodeTree) => {
6708
+ const { node, children } = nodeTree;
6709
+ if (!children) {
6710
+ return [node];
6711
+ }
6712
+ return [node, ...children.flatMap(flatNodeTree)];
6713
+ };
6714
+ var getChildren = (nodeId, nodes, edges) => {
6715
+ const nodeEdges = edges.filter((edge) => edge.source === nodeId);
6716
+ return nodeEdges.map((edge) => nodes.find((node) => node.id === edge.target)).filter((node) => node !== void 0).map((node) => ({
6717
+ node,
6718
+ children: getChildren(node.id, nodes, edges)
6719
+ }));
6720
+ };
6721
+ var getTrees = (nodes, edges) => nodes.filter((node) => !edges.some((edge) => edge.target === node.id)).map((node) => ({
6722
+ node,
6723
+ children: getChildren(node.id, nodes, edges)
6724
+ }));
6725
+ var getLowestPositionYInSubtree = (nodeTree) => {
6726
+ const { node, children } = nodeTree;
6727
+ const lowestY = node.position.y;
6728
+ if (!(children == null ? void 0 : children.length)) {
6729
+ return lowestY;
6730
+ }
6731
+ const visibleChildren = children.filter(({ node: { hidden } }) => !hidden);
6732
+ if (visibleChildren.length === 0) {
6733
+ return lowestY;
6734
+ }
6735
+ const childLowestYPositions = visibleChildren.map((child) => getLowestPositionYInSubtree(child));
6736
+ const lowestChildY = Math.max(...childLowestYPositions);
6737
+ return Math.max(lowestY, lowestChildY);
6738
+ };
6739
+ var positionNodes = (treeNodes, rootFlattenTree, allEdges, parentY) => {
6740
+ const flattenTree = rootFlattenTree || treeNodes.flatMap(flatNodeTree);
6741
+ return treeNodes.reduce((actualTreeNodes, nodeTree, treeNodeIndex) => {
6742
+ const { node, children } = nodeTree;
6743
+ const depth = allEdges ? getNodeDepth(node.id, allEdges) : 0;
6744
+ const getPositionY = () => {
6745
+ if (treeNodeIndex > 0) {
6746
+ const previousSibling = actualTreeNodes[treeNodeIndex - 1];
6747
+ const lowestYInPreviousSubtree = getLowestPositionYInSubtree(previousSibling);
6748
+ return lowestYInPreviousSubtree + TILE_HEIGHT + TILE_VERTICAL_DISTANCE;
6749
+ }
6750
+ if (parentY !== void 0) {
6751
+ return parentY;
6752
+ }
6753
+ return (TILE_HEIGHT + TILE_VERTICAL_DISTANCE) * treeNodeIndex;
6754
+ };
6755
+ const position = {
6756
+ x: depth * (TILE_WIDTH + TILE_HORIZONTAL_DISTANCE),
6757
+ y: getPositionY()
6758
+ };
6759
+ const positionedNode = __spreadProps(__spreadValues({}, node), {
6760
+ targetPosition: Position3.Left,
6761
+ sourcePosition: Position3.Right,
6762
+ position
6763
+ });
6764
+ if (!(children == null ? void 0 : children.length)) {
6765
+ return [
6766
+ ...actualTreeNodes,
6767
+ __spreadProps(__spreadValues({}, nodeTree), {
6768
+ node: positionedNode
6769
+ })
6770
+ ];
6771
+ }
6772
+ const nodeWithChildren = __spreadProps(__spreadValues({}, nodeTree), {
6773
+ node: positionedNode,
6774
+ children: positionNodes(
6775
+ children.sort((a, b) => {
6776
+ return a.node.id.localeCompare(b.node.id);
6777
+ }),
6778
+ flattenTree,
6779
+ allEdges,
6780
+ position.y
6781
+ // Pass parent's Y position to children
6782
+ )
6783
+ });
6784
+ return [...actualTreeNodes, nodeWithChildren];
6785
+ }, []);
6786
+ };
6787
+ var getLaidOutElements = (nodes, edges) => {
6788
+ const nodeTrees = getTrees(nodes, edges);
6789
+ const positionedNodes = positionNodes(nodeTrees, void 0, edges).flatMap(flatNodeTree);
6790
+ return { nodes: positionedNodes, edges };
6791
+ };
6792
+ var useAutoLayout = (nodes, edges, { viewportFocusNodeId }) => {
6793
+ const laidOutElements = useMemo10(() => {
6794
+ if (nodes.length === 0) {
6795
+ return { nodes, edges, nodeMap: /* @__PURE__ */ new Map() };
6796
+ }
6797
+ const visibleNodes = nodes.filter((node) => !node.hidden);
6798
+ const visibleNodeIds = new Set(visibleNodes.map((node) => node.id));
6799
+ const visibleEdges = edges.filter((edge) => visibleNodeIds.has(edge.source) && visibleNodeIds.has(edge.target));
6800
+ const { nodes: laidOutNodes, edges: laidOutEdges } = getLaidOutElements(visibleNodes, visibleEdges);
6801
+ const laidOutNodeMap = new Map(laidOutNodes.map((node) => [node.id, node]));
6802
+ if (viewportFocusNodeId) {
6803
+ const highlightedNode = laidOutNodeMap.get(viewportFocusNodeId);
6804
+ if (highlightedNode) {
6805
+ laidOutNodeMap.set(viewportFocusNodeId, __spreadProps(__spreadValues({}, highlightedNode), {
6806
+ data: __spreadProps(__spreadValues({}, highlightedNode.data), { isHighlighted: true })
6807
+ }));
6808
+ }
6809
+ }
6810
+ const finalNodes = nodes.filter((node) => !node.hidden).map((node) => laidOutNodeMap.get(node.id) || node);
6811
+ return {
6812
+ nodes: finalNodes,
6813
+ edges: laidOutEdges,
6814
+ nodeMap: laidOutNodeMap
6815
+ };
6816
+ }, [nodes, edges, viewportFocusNodeId]);
6817
+ return laidOutElements;
6818
+ };
6819
+
6820
+ // src/graph/hooks/useNodeVisibility.ts
6821
+ import { useCallback as useCallback10, useMemo as useMemo11 } from "react";
6822
+ var useNodeVisibility = (nodes, edges) => {
6823
+ const hasRealChildren = useCallback10(
6824
+ (nodeId) => {
6825
+ const childEdges = edges.filter((edge) => edge.source === nodeId);
6826
+ const childNodes = childEdges.map((edge) => nodes.find((node) => node.id === edge.target)).filter(Boolean);
6827
+ return childNodes.some((child) => child && child.type !== "loading");
6828
+ },
6829
+ [nodes, edges]
6830
+ );
6831
+ const areAllAncestorsExpanded = useCallback10(
6832
+ (nodeId) => {
6833
+ const parentEdges = edges.filter((edge) => edge.target === nodeId);
6834
+ if (parentEdges.length === 0) {
6835
+ return true;
6836
+ }
6837
+ for (const parentEdge of parentEdges) {
6838
+ const parentNode = nodes.find((node) => node.id === parentEdge.source);
6839
+ if (!parentNode) {
6840
+ return false;
6841
+ }
6842
+ const isParentExpanded = isDefaultNode(parentNode) ? Boolean(parentNode.data.expanded) : true;
6843
+ if (!isParentExpanded) {
6844
+ return false;
6845
+ }
6846
+ }
6847
+ return parentEdges.every((parentEdge) => areAllAncestorsExpanded(parentEdge.source));
6848
+ },
6849
+ [nodes, edges]
6850
+ );
6851
+ const visibleNodes = useMemo11(() => {
6852
+ return nodes.map((node) => {
6853
+ const shouldBeVisible = areAllAncestorsExpanded(node.id);
6854
+ if (node.type === "loading") {
6855
+ const loadingNode = {
6856
+ id: node.id,
6857
+ position: node.position,
6858
+ type: "loading",
6859
+ hidden: !shouldBeVisible,
6860
+ data: node.data
6861
+ };
6862
+ return loadingNode;
6863
+ }
6864
+ if (isDefaultNode(node)) {
6865
+ const expandedNode = {
6866
+ id: node.id,
6867
+ position: node.position,
6868
+ type: node.type,
6869
+ hidden: !shouldBeVisible,
6870
+ data: __spreadProps(__spreadValues({}, node.data), {
6871
+ expanded: Boolean(node.data.expanded),
6872
+ isExpandable: hasRealChildren(node.id)
6873
+ // onExpandToggle will be added later in GraphView
6874
+ })
6875
+ };
6876
+ return expandedNode;
6877
+ }
6878
+ return node;
6879
+ });
6880
+ }, [nodes, areAllAncestorsExpanded, hasRealChildren]);
6881
+ const visibleEdges = useMemo11(() => {
6882
+ const visibleNodeIds = new Set(visibleNodes.filter((node) => !node.hidden).map((node) => node.id));
6883
+ return edges.filter((edge) => visibleNodeIds.has(edge.source) && visibleNodeIds.has(edge.target));
6884
+ }, [visibleNodes, edges]);
6885
+ return { nodes: visibleNodes, edges: visibleEdges };
6886
+ };
6887
+
6888
+ // src/graph/graph-view.tsx
6889
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
6890
+ var GraphViewInternal = ({ nodeTypes: parentNodeTypes, edgeTypes: parentEdgeTypes, children, viewportFocusNodeId }) => {
6891
+ const { nodes, edges, toggleNodeExpansion } = useGraphActionsContext();
6892
+ const nodeTypes = React15.useMemo(
6893
+ () => __spreadValues({
6894
+ default: GraphNode,
6895
+ loading: GraphNodeSkeleton
6896
+ }, parentNodeTypes),
6897
+ [parentNodeTypes]
6898
+ );
6899
+ const edgeTypes = React15.useMemo(
6900
+ () => __spreadValues({
6901
+ default: GraphEdge
6902
+ }, parentEdgeTypes),
6903
+ [parentEdgeTypes]
6904
+ );
6905
+ const { nodes: visibleNodes, edges: visibleEdges } = useNodeVisibility(nodes, edges);
6906
+ const nodesWithExpansion = React15.useMemo(() => {
6907
+ return visibleNodes.map((node) => {
6908
+ if (isDefaultNode(node) && !node.data.onExpandToggle) {
6909
+ return __spreadProps(__spreadValues({}, node), {
6910
+ data: __spreadProps(__spreadValues({}, node.data), {
6911
+ onExpandToggle: toggleNodeExpansion
6912
+ })
6913
+ });
6914
+ }
6915
+ return node;
6916
+ });
6917
+ }, [visibleNodes, toggleNodeExpansion]);
6918
+ const {
6919
+ nodes: layoutedNodes,
6920
+ edges: layoutedEdges,
6921
+ nodeMap
6922
+ } = useAutoLayout(nodesWithExpansion, visibleEdges, {
6923
+ viewportFocusNodeId
6924
+ });
6925
+ useViewportFocus(nodeMap, viewportFocusNodeId);
6926
+ return /* @__PURE__ */ jsxs17(
6927
+ ReactFlow,
6928
+ {
6929
+ nodeTypes,
6930
+ edgeTypes,
6931
+ nodes: layoutedNodes,
6932
+ edges: layoutedEdges,
6933
+ nodesConnectable: false,
6934
+ nodesDraggable: false,
6935
+ fitView: viewportFocusNodeId ? false : true,
6936
+ fitViewOptions: {
6937
+ maxZoom: 1
6938
+ },
6939
+ proOptions: {
6940
+ hideAttribution: true
6941
+ },
6942
+ panOnScroll: true,
6943
+ selectionOnDrag: true,
6944
+ children: [
6945
+ /* @__PURE__ */ jsx22(Background, { className: "bg-muted text-muted" }),
6946
+ /* @__PURE__ */ jsx22(Controls, { showInteractive: false }),
6947
+ /* @__PURE__ */ jsx22(MiniMap, { zoomable: true, pannable: true }),
6948
+ children
6949
+ ]
6950
+ }
6951
+ );
6952
+ };
6953
+ var GraphView = React15.forwardRef(({ defaultNodes = [], defaultEdges = [], nodeTypes, edgeTypes, children, viewportFocusNodeId }, ref) => {
6954
+ return /* @__PURE__ */ jsx22(ReactFlowProvider, { children: /* @__PURE__ */ jsx22(GraphActionsProvider, { ref, initialNodes: defaultNodes, initialEdges: defaultEdges, children: /* @__PURE__ */ jsx22(GraphViewInternal, { nodeTypes, edgeTypes, viewportFocusNodeId, children }) }) });
6955
+ });
6956
+ GraphView.displayName = "GraphView";
6957
+ function useViewportFocus(nodeMap, viewportFocusNodeId) {
6958
+ const flow = useReactFlow();
6959
+ React15.useEffect(() => {
6960
+ if (viewportFocusNodeId) {
6961
+ const focusNode = nodeMap.get(viewportFocusNodeId);
6962
+ if (focusNode) {
6963
+ flow.setCenter(focusNode.position.x, focusNode.position.y, { zoom: 1 });
6964
+ }
6965
+ }
6966
+ }, [viewportFocusNodeId, flow, nodeMap]);
6967
+ }
6968
+
6969
+ // src/graph/graph.tsx
6970
+ import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
6971
+ var defaultGraphErrorConfig = {
6972
+ icon: "triangle-exclamation",
6973
+ header: "An error occurred",
6974
+ subheader: "There was an error fetching the data for this graph. Please refresh the screen."
6975
+ };
6976
+ var defaultGraphEmptyConfig = {
6977
+ icon: "layer-group",
6978
+ header: "No resources found",
6979
+ subheader: "We couldn't find any resources to display in this graph. If you need help getting started you can learn more in the Upbound Documentation."
6980
+ };
6981
+ var defaultGraphNoFilterFoundConfig = {
6982
+ icon: "magnifying-glass",
6983
+ header: "No results found",
6984
+ subheader: "We couldn't find any results that match your search term or filtering criteria. Try using different keywords, checking for typos or adjusting your filters and try again."
6985
+ };
6986
+ function Graph({
6987
+ id,
6988
+ viewportFocusNodeId,
6989
+ config,
6990
+ columnDefinitions = [],
6991
+ title,
6992
+ emptyView,
6993
+ showError,
6994
+ className,
6995
+ loading = false,
6996
+ ActionsComponent: Actions,
6997
+ disableSearch = false,
6998
+ disableFilters = false,
6999
+ searchTerm: parentGlobalFilter,
7000
+ onSearchTermChange: parentSetGlobalFilter,
7001
+ filters: parentColumnFilters,
7002
+ onFiltersChange: parentSetColumnFilters,
7003
+ children
7004
+ }) {
7005
+ var _a, _b, _c;
7006
+ const graphRef = React16.useRef(null);
7007
+ const [innerGlobalFilter, setInnerGlobalFilter] = React16.useState("");
7008
+ const [innerColumnFilters, setInnerColumnFilters] = React16.useState([]);
7009
+ const globalFilter = parentGlobalFilter != null ? parentGlobalFilter : innerGlobalFilter;
7010
+ const setGlobalFilter = parentSetGlobalFilter != null ? parentSetGlobalFilter : setInnerGlobalFilter;
7011
+ React16.useEffect(() => {
7012
+ if (parentGlobalFilter !== void 0) {
7013
+ setInnerGlobalFilter(parentGlobalFilter);
7014
+ }
7015
+ }, [parentGlobalFilter]);
7016
+ const columnFilters = parentColumnFilters != null ? parentColumnFilters : innerColumnFilters;
7017
+ const setColumnFilters = parentSetColumnFilters != null ? parentSetColumnFilters : setInnerColumnFilters;
7018
+ const table = useReactTable2({
7019
+ data: config.data,
7020
+ columns: columnDefinitions,
7021
+ getCoreRowModel: getCoreRowModel2(),
7022
+ getFilteredRowModel: getFilteredRowModel2(),
7023
+ getFacetedRowModel: getFacetedRowModel2(),
7024
+ getFacetedUniqueValues: getFacetedUniqueValues2(),
7025
+ state: { columnFilters, globalFilter },
7026
+ onColumnFiltersChange: setColumnFilters,
7027
+ onGlobalFilterChange: setGlobalFilter,
7028
+ manualFiltering: false
7029
+ });
7030
+ const flatColumns = table.getAllFlatColumns();
7031
+ const filteredRows = table.getFilteredRowModel().rows;
7032
+ const filteredData = React16.useMemo(() => filteredRows.map((row) => row.original), [filteredRows]);
7033
+ const filterCount = columnFilters.map(
7034
+ ({ id: columnFilterId, value }) => {
7035
+ var _a2, _b2;
7036
+ return getColumnFilterCount(value, (_b2 = (_a2 = table.getColumn(columnFilterId)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b2.filter);
7037
+ }
7038
+ ).reduce((prev, curr) => prev + curr, 0);
7039
+ const graphState = getTableState({ error: !!showError, loading, rowCount: filteredData.length });
7040
+ const shouldDisable = graphState === "error";
7041
+ const shouldRenderGraphContent = graphState !== "error" && graphState !== "empty";
7042
+ const resetFilters = () => {
7043
+ setColumnFilters([]);
7044
+ setGlobalFilter("");
7045
+ };
7046
+ const memoizedNodeTypes = React16.useMemo(() => config.nodeTypes, [config.nodeTypes]);
7047
+ const memoizedEdgeTypes = React16.useMemo(() => config.edgeTypes, [config.edgeTypes]);
7048
+ const memoizedConfig = React16.useMemo(() => config, [config]);
7049
+ React16.useEffect(() => {
7050
+ if (!graphRef.current) {
7051
+ return;
7052
+ }
7053
+ const { setNodes, setEdges } = graphRef.current;
7054
+ const nodes = filteredData.map((item) => memoizedConfig.nodeTransform(item, filteredData)).flat() || [];
7055
+ const nodeIds = new Set(nodes.map((node) => node.id));
7056
+ const edges = (filteredData.map(memoizedConfig.edgeTransform).filter(Boolean).flat() || []).filter(
7057
+ (edge) => Boolean(edge && edge.hasOwnProperty("source") && edge.hasOwnProperty("target")) && nodeIds.has(edge.source) && nodeIds.has(edge.target)
7058
+ );
7059
+ setNodes(nodes);
7060
+ setEdges(edges);
7061
+ }, [memoizedConfig, filteredData]);
7062
+ const showFilters = !disableFilters && hasFilterableColumns(flatColumns);
7063
+ const showToolbar = !disableSearch || !!Actions;
7064
+ const resolvedEmptyView = {
7065
+ error: (_a = emptyView == null ? void 0 : emptyView.error) != null ? _a : defaultGraphErrorConfig,
7066
+ empty: (_b = emptyView == null ? void 0 : emptyView.empty) != null ? _b : defaultGraphEmptyConfig,
7067
+ filter: (_c = emptyView == null ? void 0 : emptyView.filter) != null ? _c : defaultGraphNoFilterFoundConfig
7068
+ };
7069
+ return /* @__PURE__ */ jsxs18("div", { id: `graph-${id}`, className: cn("flex size-full flex-1 flex-col", className), children: [
7070
+ !!title && /* @__PURE__ */ jsx23(SectionHeader, { className: "mb-4", children: /* @__PURE__ */ jsx23(SectionHeaderContent, { children: /* @__PURE__ */ jsx23(SectionHeaderTitle, { children: title }) }) }),
7071
+ showToolbar && /* @__PURE__ */ jsxs18("div", { className: "mb-4 flex flex-row gap-2", children: [
7072
+ !disableSearch && /* @__PURE__ */ jsxs18(InputGroup4, { className: "w-70", children: [
7073
+ /* @__PURE__ */ jsx23(InputGroupAddon4, { align: "inline-start", children: /* @__PURE__ */ jsx23(Icon14, { name: "magnifying-glass" }) }),
7074
+ /* @__PURE__ */ jsx23(
7075
+ InputGroupInput3,
7076
+ {
7077
+ "aria-label": "Search",
7078
+ placeholder: "Search\u2026",
7079
+ disabled: shouldDisable,
7080
+ value: globalFilter,
7081
+ onChange: (e) => setGlobalFilter(e.target.value)
7082
+ }
7083
+ )
7084
+ ] }),
7085
+ !!Actions && /* @__PURE__ */ jsx23("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ jsx23(Actions, { state: graphState }) })
7086
+ ] }),
7087
+ showFilters && /* @__PURE__ */ jsx23(
7088
+ ViewFilter,
7089
+ {
7090
+ columns: flatColumns,
7091
+ columnFilters,
7092
+ onColumnFiltersChange: setColumnFilters,
7093
+ className: "mb-4"
7094
+ }
7095
+ ),
7096
+ shouldRenderGraphContent ? /* @__PURE__ */ jsxs18("div", { className: "relative size-full flex-1", children: [
7097
+ graphState === "loading" && /* @__PURE__ */ jsx23(Icon14, { name: "circle-notch", className: "absolute top-4 left-4 z-10 animate-spin" }),
7098
+ /* @__PURE__ */ jsx23(
7099
+ GraphView,
7100
+ {
7101
+ viewportFocusNodeId,
7102
+ ref: graphRef,
7103
+ nodeTypes: memoizedNodeTypes,
7104
+ edgeTypes: memoizedEdgeTypes,
7105
+ children
7106
+ }
7107
+ )
7108
+ ] }) : /* @__PURE__ */ jsx23(
7109
+ DataTableEmptyView,
7110
+ {
7111
+ emptyView: resolvedEmptyView,
7112
+ tableState: graphState,
7113
+ filterCount: filterCount + (!!globalFilter.trim() ? 1 : 0),
7114
+ resetFilters
7115
+ }
7116
+ )
7117
+ ] });
7118
+ }
7119
+
7120
+ // src/graph/hooks/useGetViewportNodeIds.ts
7121
+ import { useEffect as useEffect9, useMemo as useMemo14, useRef as useRef9, useState as useState14 } from "react";
7122
+ import { useStore, useViewport } from "reactflow";
7123
+ var useGetDebouncedViewport = (debounceDelay = 1e3) => {
7124
+ const timerRef = useRef9(null);
7125
+ const [debouncedValues, setDebouncedValues] = useState14({ x: 0, y: 0, zoom: 1, width: 0, height: 0, nodes: [] });
7126
+ const { x, y, zoom } = useViewport();
7127
+ const { width, height, nodes } = useStore((state) => ({
7128
+ width: state.width,
7129
+ height: state.height,
7130
+ nodes: state.getNodes()
7131
+ }));
7132
+ const nodesHash = nodes.map((n) => n.id).sort().join(",");
7133
+ const memoizedNodes = useMemo14(() => nodes, [nodesHash]);
7134
+ useEffect9(() => {
7135
+ if (timerRef.current) {
7136
+ clearTimeout(timerRef.current);
7137
+ }
7138
+ timerRef.current = setTimeout(() => {
7139
+ setDebouncedValues({ x, y, zoom, width, height, nodes: memoizedNodes });
7140
+ timerRef.current = null;
7141
+ }, debounceDelay);
7142
+ return () => {
7143
+ if (timerRef.current) {
7144
+ clearTimeout(timerRef.current);
7145
+ timerRef.current = null;
7146
+ }
7147
+ };
7148
+ }, [x, y, zoom, width, height, memoizedNodes, debounceDelay]);
7149
+ return debouncedValues;
7150
+ };
7151
+ var useGetViewportNodeIds = (debounceDelay = 1e3) => {
7152
+ const { x, y, zoom, width, height, nodes } = useGetDebouncedViewport(debounceDelay);
7153
+ return useMemo14(() => {
7154
+ return nodes.filter((node) => {
7155
+ var _a, _b, _c, _d;
7156
+ if (node.hidden) {
7157
+ return false;
7158
+ }
7159
+ const nodeX = ((_b = (_a = node.positionAbsolute) == null ? void 0 : _a.x) != null ? _b : node.position.x) * zoom + x;
7160
+ const nodeY = ((_d = (_c = node.positionAbsolute) == null ? void 0 : _c.y) != null ? _d : node.position.y) * zoom + y;
7161
+ const nodeW = GRAPH_NODE_WIDTH * zoom;
7162
+ const nodeH = GRAPH_NODE_HEIGHT * zoom;
7163
+ return nodeX + nodeW >= 0 && nodeX <= width && nodeY + nodeH >= 0 && nodeY <= height;
7164
+ }).map((node) => node.id).sort((a, b) => a.localeCompare(b));
7165
+ }, [x, y, zoom, width, height, nodes]);
7166
+ };
7167
+
7168
+ // src/graph/utils.ts
7169
+ import { getOutgoers as getOutgoers2 } from "reactflow";
7170
+ var getGraphDescendants = (node, nodes, edges) => {
7171
+ const outgoers = getOutgoers2(node, nodes, edges);
7172
+ return outgoers.reduce(
7173
+ (acc, outgoer) => {
7174
+ const { nodes: outgoerNodes, edges: outgoerEdges } = getGraphDescendants(outgoer, nodes, edges);
7175
+ return {
7176
+ nodes: [...acc.nodes, ...outgoerNodes],
7177
+ edges: [...acc.edges, ...outgoerEdges.filter((edge) => edge.source === outgoer.id)]
7178
+ };
7179
+ },
7180
+ { nodes: [node], edges: edges.filter((edge) => edge.source === node.id) }
7181
+ );
7182
+ };
7183
+
6227
7184
  // src/page-header.tsx
6228
- import { jsx as jsx19 } from "react/jsx-runtime";
7185
+ import { jsx as jsx24 } from "react/jsx-runtime";
6229
7186
  function PageHeader(_a) {
6230
7187
  var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
6231
- return /* @__PURE__ */ jsx19("div", __spreadProps(__spreadValues({ "data-slot": "page-header", className: cn("flex w-full items-start justify-between gap-4", className) }, props), { children }));
7188
+ return /* @__PURE__ */ jsx24("div", __spreadProps(__spreadValues({ "data-slot": "page-header", className: cn("flex w-full items-start justify-between gap-4", className) }, props), { children }));
6232
7189
  }
6233
7190
  function PageHeaderAvatar(_a) {
6234
7191
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6235
- return /* @__PURE__ */ jsx19("div", __spreadValues({ "data-slot": "page-header-avatar", className: cn("shrink-0 self-center", className) }, props));
7192
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-avatar", className: cn("shrink-0 self-center", className) }, props));
6236
7193
  }
6237
7194
  function PageHeaderContent(_a) {
6238
7195
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6239
- return /* @__PURE__ */ jsx19("div", __spreadValues({ "data-slot": "page-header-content", className: cn("flex flex-1 flex-col gap-1", className) }, props));
7196
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-content", className: cn("flex flex-1 flex-col gap-1", className) }, props));
6240
7197
  }
6241
7198
  function PageHeaderTitle(_a) {
6242
7199
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6243
- return /* @__PURE__ */ jsx19("h1", __spreadValues({ "data-slot": "page-header-title", className: cn("text-h1 text-foreground", className) }, props));
7200
+ return /* @__PURE__ */ jsx24("h1", __spreadValues({ "data-slot": "page-header-title", className: cn("text-h1 text-foreground", className) }, props));
6244
7201
  }
6245
7202
  function PageHeaderDescription(_a) {
6246
7203
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6247
- return /* @__PURE__ */ jsx19("p", __spreadValues({ "data-slot": "page-header-description", className: cn("text-body text-muted-foreground", className) }, props));
7204
+ return /* @__PURE__ */ jsx24("p", __spreadValues({ "data-slot": "page-header-description", className: cn("text-body text-muted-foreground", className) }, props));
6248
7205
  }
6249
7206
  function PageHeaderMeta(_a) {
6250
7207
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6251
- return /* @__PURE__ */ jsx19(
7208
+ return /* @__PURE__ */ jsx24(
6252
7209
  "div",
6253
7210
  __spreadValues({
6254
7211
  "data-slot": "page-header-meta",
@@ -6262,27 +7219,27 @@ function PageHeaderMeta(_a) {
6262
7219
  }
6263
7220
  function PageHeaderActions(_a) {
6264
7221
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6265
- return /* @__PURE__ */ jsx19("div", __spreadValues({ "data-slot": "page-header-actions", className: cn("flex items-center gap-2", className) }, props));
7222
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-actions", className: cn("flex items-center gap-2", className) }, props));
6266
7223
  }
6267
7224
  function PageHeaderTabs(_a) {
6268
7225
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6269
- return /* @__PURE__ */ jsx19("div", __spreadValues({ "data-slot": "page-header-tabs", className: cn("border-b", className) }, props));
7226
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-tabs", className: cn("border-b", className) }, props));
6270
7227
  }
6271
7228
 
6272
7229
  // src/timeline.tsx
6273
- import { Icon as Icon13 } from "@upbound/monarch-core";
7230
+ import { Icon as Icon15 } from "@upbound/monarch-core";
6274
7231
  import { Item as Item2, ItemGroup as ItemGroup2 } from "@upbound/monarch-core";
6275
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
7232
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
6276
7233
  function Timeline(_a) {
6277
7234
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6278
- return /* @__PURE__ */ jsx20(ItemGroup2, __spreadValues({ "data-slot": "timeline", className: cn(className) }, props));
7235
+ return /* @__PURE__ */ jsx25(ItemGroup2, __spreadValues({ "data-slot": "timeline", className: cn(className) }, props));
6279
7236
  }
6280
7237
  function TimelineItem(_a) {
6281
7238
  var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
6282
- return /* @__PURE__ */ jsxs15(Item2, __spreadProps(__spreadValues({ "data-slot": "timeline-item", className: cn("group/timeline-item gap-3 py-4", className) }, props), { children: [
6283
- /* @__PURE__ */ jsxs15("div", { className: "relative flex flex-col items-center self-stretch", children: [
6284
- /* @__PURE__ */ jsx20(Icon13, { name: "circle-dot", size: "sm", className: "text-primary shrink-0" }),
6285
- /* @__PURE__ */ jsx20(
7239
+ return /* @__PURE__ */ jsxs19(Item2, __spreadProps(__spreadValues({ "data-slot": "timeline-item", className: cn("group/timeline-item gap-3 py-4", className) }, props), { children: [
7240
+ /* @__PURE__ */ jsxs19("div", { className: "relative flex flex-col items-center self-stretch", children: [
7241
+ /* @__PURE__ */ jsx25(Icon15, { name: "circle-dot", size: "sm", className: "text-primary shrink-0" }),
7242
+ /* @__PURE__ */ jsx25(
6286
7243
  "span",
6287
7244
  {
6288
7245
  "aria-hidden": "true",
@@ -6338,6 +7295,12 @@ export {
6338
7295
  FilterChip,
6339
7296
  FloatingWidget,
6340
7297
  FloatingWidgetProvider,
7298
+ Graph,
7299
+ GraphActionsProvider,
7300
+ GraphEdge,
7301
+ GraphNode,
7302
+ GraphNodeSkeleton,
7303
+ GraphView,
6341
7304
  PageHeader,
6342
7305
  PageHeaderActions,
6343
7306
  PageHeaderAvatar,
@@ -6383,6 +7346,9 @@ export {
6383
7346
  dateBoundaryForOperator,
6384
7347
  defaultEmptyConfig,
6385
7348
  defaultErrorConfig,
7349
+ defaultGraphEmptyConfig,
7350
+ defaultGraphErrorConfig,
7351
+ defaultGraphNoFilterFoundConfig,
6386
7352
  defaultNoFilterFoundConfig,
6387
7353
  denormalizeColumnIdWithReservedNames,
6388
7354
  denormalizeColumnsWithReservedNames,
@@ -6394,6 +7360,7 @@ export {
6394
7360
  getColumnEmitOn,
6395
7361
  getDefaultOperator,
6396
7362
  getExpandColumnDefinition,
7363
+ getGraphDescendants,
6397
7364
  getOperatorLabel,
6398
7365
  getQuantifierLabel,
6399
7366
  isCelFilterCondition,
@@ -6403,6 +7370,7 @@ export {
6403
7370
  isDateRangeOperator,
6404
7371
  isDateRelativeOperator,
6405
7372
  isDateWindowOperator,
7373
+ isDefaultNode,
6406
7374
  isEndOfDayTimestamp,
6407
7375
  isEndOfMinuteTimestamp,
6408
7376
  isMapKeyCelValue,
@@ -6426,7 +7394,12 @@ export {
6426
7394
  resolveFilterShape,
6427
7395
  startInstantFromEndOfDay,
6428
7396
  startInstantFromEndOfMinute,
7397
+ useAutoLayout,
6429
7398
  useFloatingWidget,
7399
+ useGetViewportNodeIds,
7400
+ useGraphActions,
7401
+ useGraphActionsContext,
7402
+ useNodeVisibility,
6430
7403
  validateCondition,
6431
7404
  withTimeOfDay
6432
7405
  };