@upbound/monarch-blocks 0.5.0 → 0.7.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
  {
@@ -1290,7 +1296,7 @@ function CelAddFilterButton({
1290
1296
  if (column) onSelect(column.id);
1291
1297
  },
1292
1298
  children: [
1293
- /* @__PURE__ */ jsxs(ComboboxTrigger, { "aria-label": "Add filter", render: /* @__PURE__ */ jsx(Button, { variant: "outline" }), children: [
1299
+ /* @__PURE__ */ jsxs(ComboboxTrigger, { "aria-label": "Add filter", showIndicator: false, render: /* @__PURE__ */ jsx(Button, { variant: "outline" }), children: [
1294
1300
  /* @__PURE__ */ jsx(Icon, { name: "plus", "data-icon": "inline-start" }),
1295
1301
  "Add filter"
1296
1302
  ] }),
@@ -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,
@@ -2886,7 +2892,7 @@ function ChatInterface(_a) {
2886
2892
  }
2887
2893
 
2888
2894
  // src/code-block.tsx
2889
- import { useState as useState5 } from "react";
2895
+ import { useEffect as useEffect3, useState as useState5 } from "react";
2890
2896
  import { Icon as Icon3 } from "@upbound/monarch-core";
2891
2897
  import {
2892
2898
  Card,
@@ -2897,6 +2903,36 @@ import {
2897
2903
  TooltipContent as TooltipContent2,
2898
2904
  TooltipTrigger as TooltipTrigger2
2899
2905
  } from "@upbound/monarch-core";
2906
+
2907
+ // src/lib/highlight.ts
2908
+ import { createHighlighter } from "shiki";
2909
+ var CODE_BLOCK_LANGUAGES = ["tsx", "typescript", "bash", "shell", "json", "css", "yaml"];
2910
+ var HIGHLIGHTER_KEY = "__monarch_shiki_highlighter__";
2911
+ function getHighlighter() {
2912
+ const g = globalThis;
2913
+ if (!g[HIGHLIGHTER_KEY]) {
2914
+ g[HIGHLIGHTER_KEY] = createHighlighter({
2915
+ themes: ["github-light-high-contrast", "github-dark-dimmed"],
2916
+ langs: [...CODE_BLOCK_LANGUAGES]
2917
+ }).catch((error) => {
2918
+ delete g[HIGHLIGHTER_KEY];
2919
+ throw error;
2920
+ });
2921
+ }
2922
+ return g[HIGHLIGHTER_KEY];
2923
+ }
2924
+ async function highlightCode(code, lang) {
2925
+ const hl = await getHighlighter();
2926
+ return hl.codeToHtml(code, {
2927
+ lang,
2928
+ themes: {
2929
+ light: "github-light-high-contrast",
2930
+ dark: "github-dark-dimmed"
2931
+ }
2932
+ });
2933
+ }
2934
+
2935
+ // src/code-block.tsx
2900
2936
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2901
2937
  function CodeBlock(_a) {
2902
2938
  var _b = _a, {
@@ -2937,24 +2973,48 @@ function CodeBlockHeader(_a) {
2937
2973
  }, props)
2938
2974
  );
2939
2975
  }
2976
+ var LINE_NUMBER_GUTTER = cn(
2977
+ "[&_code]:[counter-reset:line]",
2978
+ "[&_.line]:before:[counter-increment:line]",
2979
+ "[&_.line]:before:content-[counter(line)]",
2980
+ "[&_.line]:before:inline-block",
2981
+ "[&_.line]:before:w-6",
2982
+ "[&_.line]:before:mr-3",
2983
+ "[&_.line]:before:text-right",
2984
+ "[&_.line]:before:text-muted-foreground",
2985
+ "[&_.line]:before:text-[0.75rem]",
2986
+ "[&_.line]:before:select-none"
2987
+ );
2940
2988
  function CodeBlockBody(_a) {
2941
2989
  var _b = _a, {
2942
2990
  className,
2943
2991
  code,
2944
- html,
2945
- lineNumbers,
2946
2992
  maxHeight,
2947
2993
  copyButton,
2948
2994
  downloadButton
2949
2995
  } = _b, props = __objRest(_b, [
2950
2996
  "className",
2951
2997
  "code",
2952
- "html",
2953
- "lineNumbers",
2954
2998
  "maxHeight",
2955
2999
  "copyButton",
2956
3000
  "downloadButton"
2957
3001
  ]);
3002
+ const { content, lineNumbers } = code;
3003
+ const [html, setHtml] = useState5(null);
3004
+ const language = code.type === "parsed" ? code.language : null;
3005
+ useEffect3(() => {
3006
+ if (!language) {
3007
+ setHtml(null);
3008
+ return;
3009
+ }
3010
+ let cancelled = false;
3011
+ highlightCode(content, language).then((result) => {
3012
+ if (!cancelled) setHtml(result);
3013
+ });
3014
+ return () => {
3015
+ cancelled = true;
3016
+ };
3017
+ }, [content, language]);
2958
3018
  return /* @__PURE__ */ jsxs4(CardContent, __spreadProps(__spreadValues({ "data-line-numbers": lineNumbers || void 0, className: cn("relative p-0!", className) }, props), { children: [
2959
3019
  (copyButton || downloadButton) && /* @__PURE__ */ jsxs4("div", { className: "absolute top-2 right-2 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover/code-block:opacity-100", children: [
2960
3020
  copyButton,
@@ -2965,16 +3025,20 @@ function CodeBlockBody(_a) {
2965
3025
  {
2966
3026
  className: cn("overflow-x-auto", maxHeight && "overflow-y-auto"),
2967
3027
  style: maxHeight ? { maxHeight } : void 0,
2968
- children: html ? /* @__PURE__ */ jsx6(
3028
+ children: /* @__PURE__ */ jsx6(
2969
3029
  "div",
2970
3030
  {
2971
- className: "[&_code]:font-mono [&_pre]:m-0 [&_pre]:bg-transparent! [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3",
2972
- dangerouslySetInnerHTML: { __html: html }
3031
+ className: cn(
3032
+ "[&_code]:font-mono [&_pre]:m-0 [&_pre]:p-4 group-data-[size=sm]/code-block:[&_pre]:p-3",
3033
+ html && "[&_pre]:bg-transparent!",
3034
+ lineNumbers && LINE_NUMBER_GUTTER
3035
+ ),
3036
+ children: html ? /* @__PURE__ */ jsx6("div", { dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx6("pre", { children: /* @__PURE__ */ jsx6("code", { className: lineNumbers ? void 0 : "whitespace-pre", children: lineNumbers ? content.split("\n").map((line, i) => /* @__PURE__ */ jsxs4("span", { className: "line", children: [
3037
+ line,
3038
+ "\n"
3039
+ ] }, i)) : content }) })
2973
3040
  }
2974
- ) : lineNumbers ? /* @__PURE__ */ jsx6("pre", { className: "p-4 group-data-[size=sm]/code-block:p-3", children: /* @__PURE__ */ jsx6("code", { className: "font-mono", children: code.split("\n").map((line, i) => /* @__PURE__ */ jsxs4("span", { className: "line", children: [
2975
- line,
2976
- "\n"
2977
- ] }, i)) }) }) : /* @__PURE__ */ jsx6("pre", { className: "p-4 group-data-[size=sm]/code-block:p-3", children: /* @__PURE__ */ jsx6("code", { className: "font-mono whitespace-pre", children: code }) })
3041
+ )
2978
3042
  }
2979
3043
  )
2980
3044
  ] }));
@@ -3143,7 +3207,15 @@ function CellContextualFilter({
3143
3207
  );
3144
3208
  }
3145
3209
  return /* @__PURE__ */ jsxs5(ContextMenuContent, { children: [
3146
- /* @__PURE__ */ jsx7(ContextMenuItem, { disabled, onClick: (event) => event.stopPropagation(), onSelect: handleSelect, children: "Filter by this value" }),
3210
+ /* @__PURE__ */ jsx7(
3211
+ ContextMenuItem,
3212
+ {
3213
+ disabled,
3214
+ onClick: (event) => event.stopPropagation(),
3215
+ onSelect: handleSelect,
3216
+ children: "Filter by this value"
3217
+ }
3218
+ ),
3147
3219
  contextualMenuActions.length > 0 && /* @__PURE__ */ jsxs5(Fragment4, { children: [
3148
3220
  /* @__PURE__ */ jsx7(ContextMenuSeparator, {}),
3149
3221
  contextualMenuActions.map(renderAction)
@@ -3475,8 +3547,25 @@ function RowActions({
3475
3547
  contentClassName
3476
3548
  }) {
3477
3549
  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 })
3550
+ /* @__PURE__ */ jsx9(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx9(
3551
+ Button4,
3552
+ {
3553
+ variant: "ghost",
3554
+ size: "icon-xs",
3555
+ "aria-label": "Row actions",
3556
+ onClick: (e) => e.stopPropagation(),
3557
+ children: /* @__PURE__ */ jsx9(Icon5, { name: "ellipsis-vertical", size: "sm" })
3558
+ }
3559
+ ) }),
3560
+ /* @__PURE__ */ jsx9(
3561
+ DropdownMenuContent3,
3562
+ {
3563
+ align,
3564
+ className: contentClassName,
3565
+ onClick: (event) => event.stopPropagation(),
3566
+ children
3567
+ }
3568
+ )
3480
3569
  ] });
3481
3570
  }
3482
3571
  function RowActionItem({
@@ -3682,7 +3771,7 @@ function getColumnFilterCount(filterValue, filter) {
3682
3771
  }
3683
3772
 
3684
3773
  // src/hooks/use-table-column-resizing.ts
3685
- import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3, useState as useState7 } from "react";
3774
+ import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState7 } from "react";
3686
3775
  var RESIZE_MIN = 40;
3687
3776
  var RESIZE_MAX = 500;
3688
3777
  var RESIZE_MAX_UNBOUNDED = Number.MAX_SAFE_INTEGER;
@@ -3771,7 +3860,7 @@ function useTableColumnResizing({
3771
3860
  } = {}) {
3772
3861
  const [columnSizing, setColumnSizing] = useState7(() => clampSizing(initialSizing != null ? initialSizing : {}, maxSize));
3773
3862
  const persistTimerRef = useRef3(null);
3774
- useEffect3(() => {
3863
+ useEffect4(() => {
3775
3864
  if (!initialSizing) return;
3776
3865
  const next = clampSizing(initialSizing, maxSize);
3777
3866
  setColumnSizing((prev) => {
@@ -3780,7 +3869,7 @@ function useTableColumnResizing({
3780
3869
  return keys.every((k) => prev[k] === next[k]) ? prev : next;
3781
3870
  });
3782
3871
  }, [initialSizing, maxSize]);
3783
- useEffect3(() => {
3872
+ useEffect4(() => {
3784
3873
  return () => {
3785
3874
  if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
3786
3875
  };
@@ -4380,6 +4469,7 @@ function DataTablePagination({
4380
4469
  PaginationLink,
4381
4470
  {
4382
4471
  href: "#",
4472
+ size: "icon",
4383
4473
  isActive: page === currentPage,
4384
4474
  onClick: (e) => {
4385
4475
  e.preventDefault();
@@ -4491,9 +4581,9 @@ function DataTableSortIcon({ sortOrder }) {
4491
4581
  return /* @__PURE__ */ jsx13(
4492
4582
  Icon9,
4493
4583
  {
4494
- name: sortOrder === "asc" ? "arrow-up" : "arrow-down",
4495
4584
  size: "xs",
4496
- className: "text-primary group-hover/col-actions:text-foreground group-data-[state=open]/col-actions:text-foreground mr-0.5 shrink-0"
4585
+ name: sortOrder === "asc" ? "arrow-up" : "arrow-down",
4586
+ className: "text-foreground group-hover/col-actions:text-foreground group-data-[state=open]/col-actions:text-foreground mr-0.5 shrink-0"
4497
4587
  }
4498
4588
  );
4499
4589
  }
@@ -4585,7 +4675,7 @@ function HeaderCellContent({
4585
4675
  "aria-label": shouldShowActionsMenu ? headerTitle ? `${headerTitle} column actions` : "Column actions" : void 0,
4586
4676
  className: cn(
4587
4677
  "group/col-actions text-muted-foreground -mx-2 -my-1 flex min-w-0 items-center gap-1 truncate rounded-md px-2 py-1 text-left font-medium motion-safe:transition-colors",
4588
- sorted && "text-primary",
4678
+ sorted && "text-foreground",
4589
4679
  shouldShowActionsMenu ? "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50 cursor-pointer" : "cursor-default"
4590
4680
  ),
4591
4681
  children: [
@@ -5021,6 +5111,9 @@ function composeRefs(...refs) {
5021
5111
  }
5022
5112
  };
5023
5113
  }
5114
+ function hasOrder(filter) {
5115
+ return typeof filter.order === "number";
5116
+ }
5024
5117
  function FilterBar(_a) {
5025
5118
  var _b = _a, {
5026
5119
  filters,
@@ -5042,7 +5135,8 @@ function FilterBar(_a) {
5042
5135
  "ref"
5043
5136
  ]);
5044
5137
  const usedKeys = new Set(activeFilters.map((f) => f.key));
5045
- const availableFilters = filters.filter((f) => !usedKeys.has(f.key));
5138
+ const remainingFilters = filters.filter((f) => !usedKeys.has(f.key));
5139
+ const availableFilters = filters.some(hasOrder) ? remainingFilters : sortBy(remainingFilters, (f) => f.label);
5046
5140
  const shouldShowFilters = availableFilters.length > 0 || activeFilters.length > 0;
5047
5141
  const [pendingOpenKey, setPendingOpenKey] = React9.useState(null);
5048
5142
  function handleAddFilter(key) {
@@ -5069,7 +5163,7 @@ function FilterBar(_a) {
5069
5163
  if (filter) handleAddFilter(filter.key);
5070
5164
  },
5071
5165
  children: [
5072
- /* @__PURE__ */ jsxs12(ComboboxTrigger2, { "aria-label": "Add filter", render: /* @__PURE__ */ jsx14(Button7, { variant: "outline" }), children: [
5166
+ /* @__PURE__ */ jsxs12(ComboboxTrigger2, { "aria-label": "Add filter", showIndicator: false, render: /* @__PURE__ */ jsx14(Button7, { variant: "outline" }), children: [
5073
5167
  /* @__PURE__ */ jsx14(Icon10, { name: "plus", "data-icon": "inline-start" }),
5074
5168
  "Add filter"
5075
5169
  ] }),
@@ -5177,7 +5271,8 @@ function CheckboxFilterChip({
5177
5271
  onRemove
5178
5272
  }) {
5179
5273
  var _a, _b;
5180
- const { label, options, searchable = false } = definition;
5274
+ const { label, searchable = false } = definition;
5275
+ const options = sortBy(definition.options, (o) => o.label);
5181
5276
  const values = asCheckboxValue(value);
5182
5277
  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
5278
  function toggle(optionValue) {
@@ -5262,7 +5357,8 @@ function RadioFilterChip({
5262
5357
  onRemove
5263
5358
  }) {
5264
5359
  var _a, _b, _c;
5265
- const { label, options, searchable = false } = definition;
5360
+ const { label, searchable = false } = definition;
5361
+ const options = sortBy(definition.options, (o) => o.label);
5266
5362
  const selectedValue = asRadioValue(value);
5267
5363
  const displayLabel = selectedValue ? (_b = (_a = options.find((o) => o.value === selectedValue)) == null ? void 0 : _a.label) != null ? _b : selectedValue : "Any";
5268
5364
  const selected = (_c = options.find((o) => o.value === selectedValue)) != null ? _c : null;
@@ -5517,21 +5613,21 @@ function toFilterOption(opt) {
5517
5613
  return typeof opt === "string" ? { value: opt, label: opt } : { value: opt.value, label: opt.label };
5518
5614
  }
5519
5615
  function toFilterBarDefinition(key, filter) {
5520
- var _a, _b, _c;
5521
- const base = { key, label: filter.title, order: (_a = filter.order) != null ? _a : 0 };
5616
+ var _a, _b;
5617
+ const base = { key, label: filter.title, order: filter.order };
5522
5618
  if (isCheckboxColumnFilter(filter)) {
5523
5619
  const options = "options" in filter && filter.options ? filter.options : [];
5524
5620
  return __spreadProps(__spreadValues({}, base), {
5525
5621
  type: "checkbox",
5526
5622
  options: options.map(toFilterOption),
5527
- searchable: (_b = filter.searchable) != null ? _b : true
5623
+ searchable: (_a = filter.searchable) != null ? _a : true
5528
5624
  });
5529
5625
  }
5530
5626
  if (isRadioColumnFilter(filter)) {
5531
5627
  return __spreadProps(__spreadValues({}, base), {
5532
5628
  type: "radio",
5533
5629
  options: filter.options.map(toFilterOption),
5534
- searchable: (_c = filter.searchable) != null ? _c : true
5630
+ searchable: (_b = filter.searchable) != null ? _b : true
5535
5631
  });
5536
5632
  }
5537
5633
  if (isDateRangeColumnFilter(filter)) {
@@ -5564,7 +5660,12 @@ function ViewFilter({
5564
5660
  [columns]
5565
5661
  );
5566
5662
  const filterDefinitions = React10.useMemo(
5567
- () => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) => a.order - b.order),
5663
+ () => filterableColumns.map(({ key, filter }) => toFilterBarDefinition(key, filter)).sort((a, b) => {
5664
+ if (a.order == null && b.order == null) return 0;
5665
+ if (a.order == null) return 1;
5666
+ if (b.order == null) return -1;
5667
+ return a.order - b.order;
5668
+ }),
5568
5669
  [filterableColumns]
5569
5670
  );
5570
5671
  const emptyValueByKey = React10.useMemo(
@@ -6224,31 +6325,952 @@ function FloatingWidget({ title = "Ask AI", subtitle, menuItems, children, class
6224
6325
  );
6225
6326
  }
6226
6327
 
6328
+ // src/graph/graph-actions-provider.tsx
6329
+ import * as React14 from "react";
6330
+
6331
+ // src/graph/hooks/useGraphActionsContext.ts
6332
+ import { createContext as createContext3, useContext as useContext3 } from "react";
6333
+ var GraphActionsContext = createContext3(null);
6334
+ var useGraphActionsContext = () => {
6335
+ const context = useContext3(GraphActionsContext);
6336
+ if (!context) {
6337
+ throw new Error("useGraphActionsContext must be used within GraphActionsProvider");
6338
+ }
6339
+ return context;
6340
+ };
6341
+
6342
+ // src/graph/hooks/useGraphActions.ts
6343
+ import { useCallback as useCallback9, useState as useState12 } from "react";
6344
+
6345
+ // src/graph/graph-node.tsx
6346
+ import * as React13 from "react";
6347
+ import { getIncomers, getOutgoers, Handle, Position as Position2 } from "reactflow";
6348
+ import { Badge as Badge4, Card as Card2, Icon as Icon13, Spinner, Tooltip as Tooltip8, TooltipContent as TooltipContent7, TooltipTrigger as TooltipTrigger7 } from "@upbound/monarch-core";
6349
+
6350
+ // src/graph/consts.ts
6351
+ var GRAPH_NODE_WIDTH = 260;
6352
+ var GRAPH_NODE_HEIGHT = 106;
6353
+ var GRAPH_NODE_COLLAPSED_HEIGHT = 47;
6354
+ var GRAPH_NODE_SEP = 22;
6355
+ var GRAPH_RANK_SEP = 54;
6356
+
6357
+ // src/graph/graph-edge.tsx
6358
+ import { getSmoothStepPath, getStraightPath, Position } from "reactflow";
6359
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
6360
+ var GraphEdge = ({
6361
+ id,
6362
+ sourceX,
6363
+ sourceY,
6364
+ targetX,
6365
+ targetY,
6366
+ targetPosition
6367
+ }) => {
6368
+ const halfDistanceWidth = (targetX - sourceX) / 2;
6369
+ const [straightEdgePath] = getStraightPath({
6370
+ sourceX: sourceX - 4,
6371
+ sourceY,
6372
+ targetX: Math.max(sourceX + halfDistanceWidth, GRAPH_NODE_WIDTH / 2),
6373
+ targetY: sourceY
6374
+ });
6375
+ const [edgePath] = getSmoothStepPath({
6376
+ sourceX: Math.max(sourceX + halfDistanceWidth, GRAPH_NODE_WIDTH / 2),
6377
+ sourceY,
6378
+ sourcePosition: Position.Bottom,
6379
+ targetX: targetX + 4,
6380
+ targetY,
6381
+ targetPosition,
6382
+ borderRadius: 8,
6383
+ offset: 0
6384
+ });
6385
+ return /* @__PURE__ */ jsxs15("g", { id, className: "react-flow__edge-path", children: [
6386
+ /* @__PURE__ */ jsx19("path", { d: straightEdgePath, className: "stroke-border fill-transparent stroke-2" }),
6387
+ /* @__PURE__ */ jsx19("path", { d: edgePath, className: "stroke-border fill-transparent stroke-2" })
6388
+ ] });
6389
+ };
6390
+
6391
+ // src/graph/graph-node.tsx
6392
+ import { Fragment as Fragment10, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
6393
+ function isDefaultNode(node) {
6394
+ return node.type !== "loading";
6395
+ }
6396
+ function GraphNode(_a) {
6397
+ var _b = _a, { id, data } = _b, props = __objRest(_b, ["id", "data"]);
6398
+ var _a2, _b2;
6399
+ const { nodes: originalNodes, edges: originalEdges } = useGraphActionsContext();
6400
+ const nodes = originalNodes;
6401
+ const edges = originalEdges;
6402
+ const handleClick = React13.useCallback(() => {
6403
+ var _a3;
6404
+ (_a3 = data == null ? void 0 : data.onClick) == null ? void 0 : _a3.call(data, id, data);
6405
+ }, [data, id]);
6406
+ const compact = (_a2 = data == null ? void 0 : data.compact) != null ? _a2 : false;
6407
+ const state = (_b2 = data == null ? void 0 : data.state) != null ? _b2 : "default";
6408
+ const compactBadges = React13.useMemo(() => {
6409
+ const badges = data.badges.compact || [];
6410
+ if (state === "paused") {
6411
+ return [
6412
+ { children: /* @__PURE__ */ jsx20(Icon13, { name: "pause", size: "xs" }), variant: "secondary", tooltipContent: "Resource is paused" },
6413
+ ...badges
6414
+ ];
6415
+ }
6416
+ return badges;
6417
+ }, [data.badges.compact, state]);
6418
+ const defaultBadges = React13.useMemo(() => {
6419
+ const badges = data.badges.default || [];
6420
+ if (state === "paused") {
6421
+ return [
6422
+ {
6423
+ children: /* @__PURE__ */ jsxs16(Fragment10, { children: [
6424
+ /* @__PURE__ */ jsx20(Icon13, { name: "pause", size: "xs", className: "mr-1" }),
6425
+ " Paused"
6426
+ ] }),
6427
+ variant: "secondary",
6428
+ tooltipContent: "Resource is paused"
6429
+ },
6430
+ ...badges
6431
+ ];
6432
+ }
6433
+ return badges;
6434
+ }, [data.badges.default, state]);
6435
+ const currentNode = React13.useMemo(
6436
+ () => ({
6437
+ id,
6438
+ position: { x: 0, y: 0 },
6439
+ // Position not needed for edge calculations
6440
+ data,
6441
+ type: props.type
6442
+ }),
6443
+ [id, data, props.type]
6444
+ );
6445
+ const _hasIncomingEdge = React13.useMemo(() => {
6446
+ return getIncomers(currentNode, nodes, edges).length > 0;
6447
+ }, [currentNode, nodes, edges]);
6448
+ const hasOutgoingEdge = React13.useMemo(() => {
6449
+ return getOutgoers(currentNode, nodes, edges).length > 0;
6450
+ }, [currentNode, nodes, edges]);
6451
+ const targetX = GRAPH_NODE_WIDTH / 2 - 4;
6452
+ const sourceX = 4;
6453
+ return /* @__PURE__ */ jsxs16(
6454
+ Card2,
6455
+ {
6456
+ className: cn(
6457
+ "relative gap-1.5 overflow-visible rounded-lg py-0",
6458
+ `flex h-[106px]! w-[260px]! flex-col pt-2.5! pb-0!`,
6459
+ `hover:shadow-md motion-safe:transition-shadow`,
6460
+ compact && `h-[47px]!`
6461
+ ),
6462
+ style: { height: compact ? GRAPH_NODE_COLLAPSED_HEIGHT : GRAPH_NODE_HEIGHT, width: GRAPH_NODE_WIDTH },
6463
+ children: [
6464
+ /* @__PURE__ */ jsx20(
6465
+ Handle,
6466
+ {
6467
+ type: "target",
6468
+ position: Position2.Left,
6469
+ style: {
6470
+ visibility: "hidden",
6471
+ width: 0
6472
+ },
6473
+ isConnectable: false
6474
+ }
6475
+ ),
6476
+ /* @__PURE__ */ jsxs16("div", { className: "flex w-full flex-1 cursor-pointer flex-col", onClick: handleClick, children: [
6477
+ /* @__PURE__ */ jsxs16("div", { className: cn("flex w-full justify-between gap-1 px-2.5", compact && "flex-row-reverse items-start"), children: [
6478
+ !!compact && /* @__PURE__ */ jsxs16(Fragment10, { children: [
6479
+ compactBadges.length > 0 && /* @__PURE__ */ jsx20("div", { className: "flex shrink-0 flex-row items-center gap-1.5 overflow-hidden", children: compactBadges.map((_c, index) => {
6480
+ var _d = _c, { tooltipContent, variant } = _d, badge = __objRest(_d, ["tooltipContent", "variant"]);
6481
+ return /* @__PURE__ */ jsxs16(Tooltip8, { children: [
6482
+ /* @__PURE__ */ jsx20(TooltipTrigger7, { children: /* @__PURE__ */ jsx20(
6483
+ Badge4,
6484
+ __spreadProps(__spreadValues({
6485
+ variant
6486
+ }, badge), {
6487
+ className: "flex size-[20px]! cursor-default! items-center justify-center p-0!",
6488
+ children: badge.children
6489
+ })
6490
+ ) }),
6491
+ tooltipContent && /* @__PURE__ */ jsx20(TooltipContent7, { children: tooltipContent })
6492
+ ] }, index);
6493
+ }) }),
6494
+ 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" }) }) })
6495
+ ] }),
6496
+ /* @__PURE__ */ jsxs16("div", { className: "mr-auto grow-0 overflow-hidden", children: [
6497
+ /* @__PURE__ */ jsx20("h5", { className: "text-body-sm/tight truncate font-bold", children: data.title }),
6498
+ /* @__PURE__ */ jsx20("p", { className: "text-body-sm truncate leading-none", children: data.subtitle }),
6499
+ !compact && /* @__PURE__ */ jsx20("p", { className: "text-body-sm text-muted-foreground mt-1 truncate", children: data.name })
6500
+ ] }),
6501
+ /* @__PURE__ */ jsx20(
6502
+ "span",
6503
+ {
6504
+ className: cn(
6505
+ "bg-foreground text-background inline-flex h-[26px] w-auto shrink-0 items-center justify-center rounded-md px-[7px] text-[10px] font-semibold",
6506
+ ["progressing", "paused"].includes(state) && "opacity-30",
6507
+ data.typeDescriptors.className
6508
+ ),
6509
+ children: data.typeDescriptors.default
6510
+ }
6511
+ )
6512
+ ] }),
6513
+ !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: [
6514
+ /* @__PURE__ */ jsx20("div", { className: "flex gap-1.5 overflow-hidden overflow-x-auto", children: defaultBadges.map((_e, index) => {
6515
+ var _f = _e, { tooltipContent, variant } = _f, badge = __objRest(_f, ["tooltipContent", "variant"]);
6516
+ return /* @__PURE__ */ jsxs16(Tooltip8, { children: [
6517
+ /* @__PURE__ */ jsx20(TooltipTrigger7, { children: /* @__PURE__ */ jsx20(Badge4, __spreadProps(__spreadValues({ variant }, badge), { className: "cursor-default! py-px! whitespace-nowrap", children: badge.children })) }),
6518
+ tooltipContent && /* @__PURE__ */ jsx20(TooltipContent7, { children: tooltipContent })
6519
+ ] }, index);
6520
+ }) }),
6521
+ state === "progressing" && /* @__PURE__ */ jsx20("div", { className: "ml-auto flex size-[20px]! items-center justify-center", children: /* @__PURE__ */ jsx20(Spinner, { size: "sm" }) })
6522
+ ] }) })
6523
+ ] }),
6524
+ !!hasOutgoingEdge && /* @__PURE__ */ jsxs16(
6525
+ "div",
6526
+ {
6527
+ className: "absolute top-0 right-0 h-full w-auto translate-x-full",
6528
+ style: {
6529
+ width: GRAPH_RANK_SEP
6530
+ },
6531
+ children: [
6532
+ /* @__PURE__ */ jsx20("svg", { height: 20, width: GRAPH_NODE_SEP, className: "absolute top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsx20(
6533
+ GraphEdge,
6534
+ {
6535
+ id: `${id}-expadable`,
6536
+ sourceX,
6537
+ sourceY: 10,
6538
+ targetX,
6539
+ targetY: 10,
6540
+ sourcePosition: Position2.Right,
6541
+ targetPosition: Position2.Left,
6542
+ source: id,
6543
+ target: id,
6544
+ stopOpacity: 0
6545
+ }
6546
+ ) }),
6547
+ /* @__PURE__ */ jsxs16(Tooltip8, { children: [
6548
+ /* @__PURE__ */ jsx20(TooltipTrigger7, { asChild: true, children: /* @__PURE__ */ jsx20(
6549
+ "button",
6550
+ {
6551
+ type: "button",
6552
+ "aria-label": data.expanded ? "Collapse" : "Expand",
6553
+ 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",
6554
+ onClick: (e) => {
6555
+ var _a3;
6556
+ e.stopPropagation();
6557
+ (_a3 = data.onExpandToggle) == null ? void 0 : _a3.call(data, id);
6558
+ },
6559
+ children: /* @__PURE__ */ jsx20(Icon13, { name: data.expanded ? "minus" : "plus", size: "xs" })
6560
+ }
6561
+ ) }),
6562
+ /* @__PURE__ */ jsx20(TooltipContent7, { children: data.expanded ? "Collapse" : "Expand" })
6563
+ ] })
6564
+ ]
6565
+ }
6566
+ ),
6567
+ /* @__PURE__ */ jsx20(
6568
+ Handle,
6569
+ {
6570
+ type: "source",
6571
+ position: Position2.Right,
6572
+ style: {
6573
+ visibility: "hidden",
6574
+ width: 0
6575
+ },
6576
+ isConnectable: false
6577
+ }
6578
+ )
6579
+ ]
6580
+ }
6581
+ );
6582
+ }
6583
+ function GraphNodeSkeleton(_props) {
6584
+ const compact = false;
6585
+ return /* @__PURE__ */ jsxs16(
6586
+ Card2,
6587
+ {
6588
+ className: cn(
6589
+ `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`,
6590
+ compact && `h-[47px]!`
6591
+ ),
6592
+ children: [
6593
+ /* @__PURE__ */ jsx20(
6594
+ Handle,
6595
+ {
6596
+ type: "target",
6597
+ position: Position2.Left,
6598
+ style: {
6599
+ visibility: "hidden",
6600
+ width: 0
6601
+ },
6602
+ isConnectable: false
6603
+ }
6604
+ ),
6605
+ /* @__PURE__ */ jsxs16("div", { className: cn("flex w-full gap-1 px-2.5", compact && "flex-row-reverse"), children: [
6606
+ /* @__PURE__ */ jsxs16("div", { className: cn("grow-0 overflow-hidden", compact && "mr-auto"), children: [
6607
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted mb-1 h-3 w-16 animate-pulse rounded-sm" }),
6608
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted h-3 w-40 animate-pulse rounded-sm" }),
6609
+ !compact && /* @__PURE__ */ jsx20("div", { className: "bg-muted mt-2 h-3 w-48 animate-pulse rounded-sm" })
6610
+ ] }),
6611
+ /* @__PURE__ */ jsx20("div", { className: cn("bg-muted size-[26px] shrink-0 animate-pulse rounded-md", !compact && "ml-auto") })
6612
+ ] }),
6613
+ !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: [
6614
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted h-4 w-12 animate-pulse rounded-sm" }),
6615
+ /* @__PURE__ */ jsx20("div", { className: "bg-muted h-4 w-12 animate-pulse rounded-sm" })
6616
+ ] }) }),
6617
+ /* @__PURE__ */ jsx20(
6618
+ Handle,
6619
+ {
6620
+ type: "source",
6621
+ position: Position2.Right,
6622
+ style: {
6623
+ visibility: "hidden",
6624
+ width: 0
6625
+ },
6626
+ isConnectable: false
6627
+ }
6628
+ )
6629
+ ]
6630
+ }
6631
+ );
6632
+ }
6633
+
6634
+ // src/graph/hooks/useGraphActions.ts
6635
+ var useGraphActions = (initialNodes = [], initialEdges = []) => {
6636
+ const [nodes, setNodes] = useState12(initialNodes);
6637
+ const [edges, setEdges] = useState12(initialEdges);
6638
+ const addNodes = useCallback9((newNodes) => {
6639
+ setNodes((prevNodes) => {
6640
+ const existingIds = new Set(prevNodes.map((node) => node.id));
6641
+ const uniqueNewNodes = newNodes.filter((node) => !existingIds.has(node.id));
6642
+ return [...prevNodes, ...uniqueNewNodes];
6643
+ });
6644
+ }, []);
6645
+ const addEdges = useCallback9((newEdges) => {
6646
+ setEdges((prevEdges) => {
6647
+ const existingIds = new Set(prevEdges.map((edge) => edge.id));
6648
+ const uniqueNewEdges = newEdges.filter((edge) => !existingIds.has(edge.id));
6649
+ return [...prevEdges, ...uniqueNewEdges];
6650
+ });
6651
+ }, []);
6652
+ const removeNodes = useCallback9((nodeIds) => {
6653
+ const nodeIdSet = new Set(nodeIds);
6654
+ setNodes((prevNodes) => prevNodes.filter((node) => !nodeIdSet.has(node.id)));
6655
+ setEdges((prevEdges) => prevEdges.filter((edge) => !nodeIdSet.has(edge.source) && !nodeIdSet.has(edge.target)));
6656
+ }, []);
6657
+ const removeEdges = useCallback9((edgeIds) => {
6658
+ const edgeIdSet = new Set(edgeIds);
6659
+ setEdges((prevEdges) => prevEdges.filter((edge) => !edgeIdSet.has(edge.id)));
6660
+ }, []);
6661
+ const resetGraph = useCallback9(() => {
6662
+ setNodes(initialNodes);
6663
+ setEdges(initialEdges);
6664
+ }, [initialNodes, initialEdges]);
6665
+ const updateNode = useCallback9((nodeId, node) => {
6666
+ setNodes((prevNodes) => prevNodes.map((n) => n.id === nodeId ? node : n));
6667
+ }, []);
6668
+ const toggleNodeExpansion = useCallback9((nodeId) => {
6669
+ setNodes(
6670
+ (prevNodes) => prevNodes.map((node) => {
6671
+ if (node.id === nodeId && isDefaultNode(node)) {
6672
+ return __spreadProps(__spreadValues({}, node), {
6673
+ data: __spreadProps(__spreadValues({}, node.data), {
6674
+ expanded: !node.data.expanded
6675
+ })
6676
+ });
6677
+ }
6678
+ return node;
6679
+ })
6680
+ );
6681
+ }, []);
6682
+ return {
6683
+ nodes,
6684
+ edges,
6685
+ addNodes,
6686
+ addEdges,
6687
+ removeNodes,
6688
+ removeEdges,
6689
+ setNodes,
6690
+ setEdges,
6691
+ resetGraph,
6692
+ updateNode,
6693
+ toggleNodeExpansion
6694
+ };
6695
+ };
6696
+
6697
+ // src/graph/graph-actions-provider.tsx
6698
+ import { jsx as jsx21 } from "react/jsx-runtime";
6699
+ var GraphActionsProvider = React14.forwardRef(
6700
+ ({ initialNodes = [], initialEdges = [], children }, ref) => {
6701
+ const graphActions = useGraphActions(initialNodes, initialEdges);
6702
+ React14.useImperativeHandle(
6703
+ ref,
6704
+ () => ({
6705
+ addNodes: graphActions.addNodes,
6706
+ addEdges: graphActions.addEdges,
6707
+ setNodes: graphActions.setNodes,
6708
+ setEdges: graphActions.setEdges,
6709
+ toggleNodeExpansion: graphActions.toggleNodeExpansion,
6710
+ updateNode: graphActions.updateNode,
6711
+ reset: graphActions.resetGraph
6712
+ }),
6713
+ [graphActions]
6714
+ );
6715
+ return /* @__PURE__ */ jsx21(GraphActionsContext.Provider, { value: graphActions, children });
6716
+ }
6717
+ );
6718
+ GraphActionsProvider.displayName = "GraphActionsProvider";
6719
+
6720
+ // src/graph/graph.tsx
6721
+ import * as React17 from "react";
6722
+ import {
6723
+ getCoreRowModel as getCoreRowModel2,
6724
+ getFacetedRowModel as getFacetedRowModel2,
6725
+ getFacetedUniqueValues as getFacetedUniqueValues2,
6726
+ getFilteredRowModel as getFilteredRowModel2,
6727
+ useReactTable as useReactTable2
6728
+ } from "@tanstack/react-table";
6729
+ import { Icon as Icon14, InputGroup as InputGroup4, InputGroupAddon as InputGroupAddon4, InputGroupInput as InputGroupInput3 } from "@upbound/monarch-core";
6730
+
6731
+ // src/graph/graph-view.tsx
6732
+ import * as React16 from "react";
6733
+ import { Background, Controls, MiniMap, ReactFlow, ReactFlowProvider } from "reactflow";
6734
+
6735
+ // src/graph/hooks/useAutoLayout.ts
6736
+ import { useMemo as useMemo10 } from "react";
6737
+ import { Position as Position3 } from "reactflow";
6738
+ var TILE_HORIZONTAL_DISTANCE = GRAPH_RANK_SEP;
6739
+ var TILE_VERTICAL_DISTANCE = GRAPH_NODE_SEP;
6740
+ var TILE_HEIGHT = GRAPH_NODE_HEIGHT;
6741
+ var TILE_WIDTH = GRAPH_NODE_WIDTH;
6742
+ var getNodeDepth = (nodeId, edges, visited = /* @__PURE__ */ new Set(), maxDepth = 100) => {
6743
+ if (visited.has(nodeId)) {
6744
+ console.warn(`Cycle detected in graph at node: ${nodeId}. Returning depth 0 to prevent infinite recursion.`);
6745
+ return 0;
6746
+ }
6747
+ if (visited.size >= maxDepth) {
6748
+ console.warn(`Maximum depth limit (${maxDepth}) reached for node: ${nodeId}.`);
6749
+ return visited.size;
6750
+ }
6751
+ const parentEdge = edges.find((edge) => edge.target === nodeId);
6752
+ if (!parentEdge) {
6753
+ return 0;
6754
+ }
6755
+ const newVisited = /* @__PURE__ */ new Set([...visited, nodeId]);
6756
+ return 1 + getNodeDepth(parentEdge.source, edges, newVisited, maxDepth);
6757
+ };
6758
+ var flatNodeTree = (nodeTree) => {
6759
+ const { node, children } = nodeTree;
6760
+ if (!children) {
6761
+ return [node];
6762
+ }
6763
+ return [node, ...children.flatMap(flatNodeTree)];
6764
+ };
6765
+ var getChildren = (nodeId, nodes, edges) => {
6766
+ const nodeEdges = edges.filter((edge) => edge.source === nodeId);
6767
+ return nodeEdges.map((edge) => nodes.find((node) => node.id === edge.target)).filter((node) => node !== void 0).map((node) => ({
6768
+ node,
6769
+ children: getChildren(node.id, nodes, edges)
6770
+ }));
6771
+ };
6772
+ var getTrees = (nodes, edges) => nodes.filter((node) => !edges.some((edge) => edge.target === node.id)).map((node) => ({
6773
+ node,
6774
+ children: getChildren(node.id, nodes, edges)
6775
+ }));
6776
+ var getLowestPositionYInSubtree = (nodeTree) => {
6777
+ const { node, children } = nodeTree;
6778
+ const lowestY = node.position.y;
6779
+ if (!(children == null ? void 0 : children.length)) {
6780
+ return lowestY;
6781
+ }
6782
+ const visibleChildren = children.filter(({ node: { hidden } }) => !hidden);
6783
+ if (visibleChildren.length === 0) {
6784
+ return lowestY;
6785
+ }
6786
+ const childLowestYPositions = visibleChildren.map((child) => getLowestPositionYInSubtree(child));
6787
+ const lowestChildY = Math.max(...childLowestYPositions);
6788
+ return Math.max(lowestY, lowestChildY);
6789
+ };
6790
+ var positionNodes = (treeNodes, rootFlattenTree, allEdges, parentY) => {
6791
+ const flattenTree = rootFlattenTree || treeNodes.flatMap(flatNodeTree);
6792
+ return treeNodes.reduce((actualTreeNodes, nodeTree, treeNodeIndex) => {
6793
+ const { node, children } = nodeTree;
6794
+ const depth = allEdges ? getNodeDepth(node.id, allEdges) : 0;
6795
+ const getPositionY = () => {
6796
+ if (treeNodeIndex > 0) {
6797
+ const previousSibling = actualTreeNodes[treeNodeIndex - 1];
6798
+ const lowestYInPreviousSubtree = getLowestPositionYInSubtree(previousSibling);
6799
+ return lowestYInPreviousSubtree + TILE_HEIGHT + TILE_VERTICAL_DISTANCE;
6800
+ }
6801
+ if (parentY !== void 0) {
6802
+ return parentY;
6803
+ }
6804
+ return (TILE_HEIGHT + TILE_VERTICAL_DISTANCE) * treeNodeIndex;
6805
+ };
6806
+ const position = {
6807
+ x: depth * (TILE_WIDTH + TILE_HORIZONTAL_DISTANCE),
6808
+ y: getPositionY()
6809
+ };
6810
+ const positionedNode = __spreadProps(__spreadValues({}, node), {
6811
+ targetPosition: Position3.Left,
6812
+ sourcePosition: Position3.Right,
6813
+ position
6814
+ });
6815
+ if (!(children == null ? void 0 : children.length)) {
6816
+ return [
6817
+ ...actualTreeNodes,
6818
+ __spreadProps(__spreadValues({}, nodeTree), {
6819
+ node: positionedNode
6820
+ })
6821
+ ];
6822
+ }
6823
+ const nodeWithChildren = __spreadProps(__spreadValues({}, nodeTree), {
6824
+ node: positionedNode,
6825
+ children: positionNodes(
6826
+ children.sort((a, b) => {
6827
+ return a.node.id.localeCompare(b.node.id);
6828
+ }),
6829
+ flattenTree,
6830
+ allEdges,
6831
+ position.y
6832
+ // Pass parent's Y position to children
6833
+ )
6834
+ });
6835
+ return [...actualTreeNodes, nodeWithChildren];
6836
+ }, []);
6837
+ };
6838
+ var getLaidOutElements = (nodes, edges) => {
6839
+ const nodeTrees = getTrees(nodes, edges);
6840
+ const positionedNodes = positionNodes(nodeTrees, void 0, edges).flatMap(flatNodeTree);
6841
+ return { nodes: positionedNodes, edges };
6842
+ };
6843
+ var useAutoLayout = (nodes, edges, { viewportFocusNodeId }) => {
6844
+ const laidOutElements = useMemo10(() => {
6845
+ if (nodes.length === 0) {
6846
+ return { nodes, edges, nodeMap: /* @__PURE__ */ new Map() };
6847
+ }
6848
+ const visibleNodes = nodes.filter((node) => !node.hidden);
6849
+ const visibleNodeIds = new Set(visibleNodes.map((node) => node.id));
6850
+ const visibleEdges = edges.filter((edge) => visibleNodeIds.has(edge.source) && visibleNodeIds.has(edge.target));
6851
+ const { nodes: laidOutNodes, edges: laidOutEdges } = getLaidOutElements(visibleNodes, visibleEdges);
6852
+ const laidOutNodeMap = new Map(laidOutNodes.map((node) => [node.id, node]));
6853
+ if (viewportFocusNodeId) {
6854
+ const highlightedNode = laidOutNodeMap.get(viewportFocusNodeId);
6855
+ if (highlightedNode) {
6856
+ laidOutNodeMap.set(viewportFocusNodeId, __spreadProps(__spreadValues({}, highlightedNode), {
6857
+ data: __spreadProps(__spreadValues({}, highlightedNode.data), { isHighlighted: true })
6858
+ }));
6859
+ }
6860
+ }
6861
+ const finalNodes = nodes.filter((node) => !node.hidden).map((node) => laidOutNodeMap.get(node.id) || node);
6862
+ return {
6863
+ nodes: finalNodes,
6864
+ edges: laidOutEdges,
6865
+ nodeMap: laidOutNodeMap
6866
+ };
6867
+ }, [nodes, edges, viewportFocusNodeId]);
6868
+ return laidOutElements;
6869
+ };
6870
+
6871
+ // src/graph/hooks/useNodeVisibility.ts
6872
+ import { useCallback as useCallback10, useMemo as useMemo11 } from "react";
6873
+ var useNodeVisibility = (nodes, edges) => {
6874
+ const hasRealChildren = useCallback10(
6875
+ (nodeId) => {
6876
+ const childEdges = edges.filter((edge) => edge.source === nodeId);
6877
+ const childNodes = childEdges.map((edge) => nodes.find((node) => node.id === edge.target)).filter(Boolean);
6878
+ return childNodes.some((child) => child && child.type !== "loading");
6879
+ },
6880
+ [nodes, edges]
6881
+ );
6882
+ const areAllAncestorsExpanded = useCallback10(
6883
+ (nodeId) => {
6884
+ const parentEdges = edges.filter((edge) => edge.target === nodeId);
6885
+ if (parentEdges.length === 0) {
6886
+ return true;
6887
+ }
6888
+ for (const parentEdge of parentEdges) {
6889
+ const parentNode = nodes.find((node) => node.id === parentEdge.source);
6890
+ if (!parentNode) {
6891
+ return false;
6892
+ }
6893
+ const isParentExpanded = isDefaultNode(parentNode) ? Boolean(parentNode.data.expanded) : true;
6894
+ if (!isParentExpanded) {
6895
+ return false;
6896
+ }
6897
+ }
6898
+ return parentEdges.every((parentEdge) => areAllAncestorsExpanded(parentEdge.source));
6899
+ },
6900
+ [nodes, edges]
6901
+ );
6902
+ const visibleNodes = useMemo11(() => {
6903
+ return nodes.map((node) => {
6904
+ const shouldBeVisible = areAllAncestorsExpanded(node.id);
6905
+ if (node.type === "loading") {
6906
+ const loadingNode = {
6907
+ id: node.id,
6908
+ position: node.position,
6909
+ type: "loading",
6910
+ hidden: !shouldBeVisible,
6911
+ data: node.data
6912
+ };
6913
+ return loadingNode;
6914
+ }
6915
+ if (isDefaultNode(node)) {
6916
+ const expandedNode = {
6917
+ id: node.id,
6918
+ position: node.position,
6919
+ type: node.type,
6920
+ hidden: !shouldBeVisible,
6921
+ data: __spreadProps(__spreadValues({}, node.data), {
6922
+ expanded: Boolean(node.data.expanded),
6923
+ isExpandable: hasRealChildren(node.id)
6924
+ // onExpandToggle will be added later in GraphView
6925
+ })
6926
+ };
6927
+ return expandedNode;
6928
+ }
6929
+ return node;
6930
+ });
6931
+ }, [nodes, areAllAncestorsExpanded, hasRealChildren]);
6932
+ const visibleEdges = useMemo11(() => {
6933
+ const visibleNodeIds = new Set(visibleNodes.filter((node) => !node.hidden).map((node) => node.id));
6934
+ return edges.filter((edge) => visibleNodeIds.has(edge.source) && visibleNodeIds.has(edge.target));
6935
+ }, [visibleNodes, edges]);
6936
+ return { nodes: visibleNodes, edges: visibleEdges };
6937
+ };
6938
+
6939
+ // src/graph/hooks/useViewportFocus.ts
6940
+ import * as React15 from "react";
6941
+ import { useReactFlow, useStore } from "reactflow";
6942
+ function getViewportFocusCenter(node) {
6943
+ var _a;
6944
+ const compact = node.type !== "loading" && Boolean((_a = node.data) == null ? void 0 : _a.compact);
6945
+ const height = compact ? GRAPH_NODE_COLLAPSED_HEIGHT : GRAPH_NODE_HEIGHT;
6946
+ return {
6947
+ x: node.position.x + GRAPH_NODE_WIDTH / 2,
6948
+ y: node.position.y + height / 2
6949
+ };
6950
+ }
6951
+ function useViewportFocus(nodeMap, viewportFocusNodeId) {
6952
+ const { setCenter } = useReactFlow();
6953
+ const viewportReady = useStore((state) => state.width > 0 && state.height > 0);
6954
+ const node = viewportFocusNodeId ? nodeMap.get(viewportFocusNodeId) : void 0;
6955
+ React15.useEffect(() => {
6956
+ if (!node || !viewportReady) {
6957
+ return;
6958
+ }
6959
+ const { x, y } = getViewportFocusCenter(node);
6960
+ setCenter(x, y, { zoom: 1 });
6961
+ }, [node == null ? void 0 : node.id, viewportReady, setCenter]);
6962
+ }
6963
+
6964
+ // src/graph/graph-view.tsx
6965
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
6966
+ var GraphViewInternal = ({ nodeTypes: parentNodeTypes, edgeTypes: parentEdgeTypes, children, viewportFocusNodeId }) => {
6967
+ const { nodes, edges, toggleNodeExpansion } = useGraphActionsContext();
6968
+ const nodeTypes = React16.useMemo(
6969
+ () => __spreadValues({
6970
+ default: GraphNode,
6971
+ loading: GraphNodeSkeleton
6972
+ }, parentNodeTypes),
6973
+ [parentNodeTypes]
6974
+ );
6975
+ const edgeTypes = React16.useMemo(
6976
+ () => __spreadValues({
6977
+ default: GraphEdge
6978
+ }, parentEdgeTypes),
6979
+ [parentEdgeTypes]
6980
+ );
6981
+ const { nodes: visibleNodes, edges: visibleEdges } = useNodeVisibility(nodes, edges);
6982
+ const nodesWithExpansion = React16.useMemo(() => {
6983
+ return visibleNodes.map((node) => {
6984
+ if (isDefaultNode(node) && !node.data.onExpandToggle) {
6985
+ return __spreadProps(__spreadValues({}, node), {
6986
+ data: __spreadProps(__spreadValues({}, node.data), {
6987
+ onExpandToggle: toggleNodeExpansion
6988
+ })
6989
+ });
6990
+ }
6991
+ return node;
6992
+ });
6993
+ }, [visibleNodes, toggleNodeExpansion]);
6994
+ const {
6995
+ nodes: layoutedNodes,
6996
+ edges: layoutedEdges,
6997
+ nodeMap
6998
+ } = useAutoLayout(nodesWithExpansion, visibleEdges, {
6999
+ viewportFocusNodeId
7000
+ });
7001
+ useViewportFocus(nodeMap, viewportFocusNodeId);
7002
+ return /* @__PURE__ */ jsxs17(
7003
+ ReactFlow,
7004
+ {
7005
+ nodeTypes,
7006
+ edgeTypes,
7007
+ nodes: layoutedNodes,
7008
+ edges: layoutedEdges,
7009
+ nodesConnectable: false,
7010
+ nodesDraggable: false,
7011
+ fitView: viewportFocusNodeId ? false : true,
7012
+ fitViewOptions: {
7013
+ maxZoom: 1
7014
+ },
7015
+ proOptions: {
7016
+ hideAttribution: true
7017
+ },
7018
+ panOnScroll: true,
7019
+ selectionOnDrag: true,
7020
+ children: [
7021
+ /* @__PURE__ */ jsx22(Background, { className: "bg-muted text-muted" }),
7022
+ /* @__PURE__ */ jsx22(Controls, { showInteractive: false }),
7023
+ /* @__PURE__ */ jsx22(MiniMap, { zoomable: true, pannable: true }),
7024
+ children
7025
+ ]
7026
+ }
7027
+ );
7028
+ };
7029
+ var GraphView = React16.forwardRef(({ defaultNodes = [], defaultEdges = [], nodeTypes, edgeTypes, children, viewportFocusNodeId }, ref) => {
7030
+ return /* @__PURE__ */ jsx22(ReactFlowProvider, { children: /* @__PURE__ */ jsx22(GraphActionsProvider, { ref, initialNodes: defaultNodes, initialEdges: defaultEdges, children: /* @__PURE__ */ jsx22(GraphViewInternal, { nodeTypes, edgeTypes, viewportFocusNodeId, children }) }) });
7031
+ });
7032
+ GraphView.displayName = "GraphView";
7033
+
7034
+ // src/graph/graph.tsx
7035
+ import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
7036
+ var defaultGraphErrorConfig = {
7037
+ icon: "triangle-exclamation",
7038
+ header: "An error occurred",
7039
+ subheader: "There was an error fetching the data for this graph. Please refresh the screen."
7040
+ };
7041
+ var defaultGraphEmptyConfig = {
7042
+ icon: "layer-group",
7043
+ header: "No resources found",
7044
+ 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."
7045
+ };
7046
+ var defaultGraphNoFilterFoundConfig = {
7047
+ icon: "magnifying-glass",
7048
+ header: "No results found",
7049
+ 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."
7050
+ };
7051
+ function Graph({
7052
+ id,
7053
+ viewportFocusNodeId,
7054
+ config,
7055
+ columnDefinitions = [],
7056
+ title,
7057
+ emptyView,
7058
+ showError,
7059
+ className,
7060
+ loading = false,
7061
+ ActionsComponent: Actions,
7062
+ disableSearch = false,
7063
+ disableFilters = false,
7064
+ searchTerm: parentGlobalFilter,
7065
+ onSearchTermChange: parentSetGlobalFilter,
7066
+ filters: parentColumnFilters,
7067
+ onFiltersChange: parentSetColumnFilters,
7068
+ children
7069
+ }) {
7070
+ var _a, _b, _c;
7071
+ const graphRef = React17.useRef(null);
7072
+ const [innerGlobalFilter, setInnerGlobalFilter] = React17.useState("");
7073
+ const [innerColumnFilters, setInnerColumnFilters] = React17.useState([]);
7074
+ const globalFilter = parentGlobalFilter != null ? parentGlobalFilter : innerGlobalFilter;
7075
+ const setGlobalFilter = parentSetGlobalFilter != null ? parentSetGlobalFilter : setInnerGlobalFilter;
7076
+ React17.useEffect(() => {
7077
+ if (parentGlobalFilter !== void 0) {
7078
+ setInnerGlobalFilter(parentGlobalFilter);
7079
+ }
7080
+ }, [parentGlobalFilter]);
7081
+ const columnFilters = parentColumnFilters != null ? parentColumnFilters : innerColumnFilters;
7082
+ const setColumnFilters = parentSetColumnFilters != null ? parentSetColumnFilters : setInnerColumnFilters;
7083
+ const table = useReactTable2({
7084
+ data: config.data,
7085
+ columns: columnDefinitions,
7086
+ getCoreRowModel: getCoreRowModel2(),
7087
+ getFilteredRowModel: getFilteredRowModel2(),
7088
+ getFacetedRowModel: getFacetedRowModel2(),
7089
+ getFacetedUniqueValues: getFacetedUniqueValues2(),
7090
+ state: { columnFilters, globalFilter },
7091
+ onColumnFiltersChange: setColumnFilters,
7092
+ onGlobalFilterChange: setGlobalFilter,
7093
+ manualFiltering: false
7094
+ });
7095
+ const flatColumns = table.getAllFlatColumns();
7096
+ const filteredRows = table.getFilteredRowModel().rows;
7097
+ const filteredData = React17.useMemo(() => filteredRows.map((row) => row.original), [filteredRows]);
7098
+ const filterCount = columnFilters.map(
7099
+ ({ id: columnFilterId, value }) => {
7100
+ var _a2, _b2;
7101
+ return getColumnFilterCount(value, (_b2 = (_a2 = table.getColumn(columnFilterId)) == null ? void 0 : _a2.columnDef.meta) == null ? void 0 : _b2.filter);
7102
+ }
7103
+ ).reduce((prev, curr) => prev + curr, 0);
7104
+ const graphState = getTableState({ error: !!showError, loading, rowCount: filteredData.length });
7105
+ const shouldDisable = graphState === "error";
7106
+ const shouldRenderGraphContent = graphState !== "error" && graphState !== "empty";
7107
+ const resetFilters = () => {
7108
+ setColumnFilters([]);
7109
+ setGlobalFilter("");
7110
+ };
7111
+ const memoizedNodeTypes = React17.useMemo(() => config.nodeTypes, [config.nodeTypes]);
7112
+ const memoizedEdgeTypes = React17.useMemo(() => config.edgeTypes, [config.edgeTypes]);
7113
+ const memoizedConfig = React17.useMemo(() => config, [config]);
7114
+ React17.useEffect(() => {
7115
+ if (!graphRef.current) {
7116
+ return;
7117
+ }
7118
+ const { setNodes, setEdges } = graphRef.current;
7119
+ const nodes = filteredData.map((item) => memoizedConfig.nodeTransform(item, filteredData)).flat() || [];
7120
+ const nodeIds = new Set(nodes.map((node) => node.id));
7121
+ const edges = (filteredData.map(memoizedConfig.edgeTransform).filter(Boolean).flat() || []).filter(
7122
+ (edge) => Boolean(edge && edge.hasOwnProperty("source") && edge.hasOwnProperty("target")) && nodeIds.has(edge.source) && nodeIds.has(edge.target)
7123
+ );
7124
+ setNodes(nodes);
7125
+ setEdges(edges);
7126
+ }, [memoizedConfig, filteredData]);
7127
+ const showFilters = !disableFilters && hasFilterableColumns(flatColumns);
7128
+ const showToolbar = !disableSearch || !!Actions;
7129
+ const resolvedEmptyView = {
7130
+ error: (_a = emptyView == null ? void 0 : emptyView.error) != null ? _a : defaultGraphErrorConfig,
7131
+ empty: (_b = emptyView == null ? void 0 : emptyView.empty) != null ? _b : defaultGraphEmptyConfig,
7132
+ filter: (_c = emptyView == null ? void 0 : emptyView.filter) != null ? _c : defaultGraphNoFilterFoundConfig
7133
+ };
7134
+ return /* @__PURE__ */ jsxs18("div", { id: `graph-${id}`, className: cn("flex size-full flex-1 flex-col", className), children: [
7135
+ !!title && /* @__PURE__ */ jsx23(SectionHeader, { className: "mb-4", children: /* @__PURE__ */ jsx23(SectionHeaderContent, { children: /* @__PURE__ */ jsx23(SectionHeaderTitle, { children: title }) }) }),
7136
+ showToolbar && /* @__PURE__ */ jsxs18("div", { className: "mb-4 flex flex-row gap-2", children: [
7137
+ !disableSearch && /* @__PURE__ */ jsxs18(InputGroup4, { className: "w-70", children: [
7138
+ /* @__PURE__ */ jsx23(InputGroupAddon4, { align: "inline-start", children: /* @__PURE__ */ jsx23(Icon14, { name: "magnifying-glass" }) }),
7139
+ /* @__PURE__ */ jsx23(
7140
+ InputGroupInput3,
7141
+ {
7142
+ "aria-label": "Search",
7143
+ placeholder: "Search\u2026",
7144
+ disabled: shouldDisable,
7145
+ value: globalFilter,
7146
+ onChange: (e) => setGlobalFilter(e.target.value)
7147
+ }
7148
+ )
7149
+ ] }),
7150
+ !!Actions && /* @__PURE__ */ jsx23("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ jsx23(Actions, { state: graphState }) })
7151
+ ] }),
7152
+ showFilters && /* @__PURE__ */ jsx23(
7153
+ ViewFilter,
7154
+ {
7155
+ columns: flatColumns,
7156
+ columnFilters,
7157
+ onColumnFiltersChange: setColumnFilters,
7158
+ className: "mb-4"
7159
+ }
7160
+ ),
7161
+ shouldRenderGraphContent ? /* @__PURE__ */ jsxs18("div", { className: "relative size-full flex-1", children: [
7162
+ graphState === "loading" && /* @__PURE__ */ jsx23(Icon14, { name: "circle-notch", className: "absolute top-4 left-4 z-10 animate-spin" }),
7163
+ /* @__PURE__ */ jsx23(
7164
+ GraphView,
7165
+ {
7166
+ viewportFocusNodeId,
7167
+ ref: graphRef,
7168
+ nodeTypes: memoizedNodeTypes,
7169
+ edgeTypes: memoizedEdgeTypes,
7170
+ children
7171
+ }
7172
+ )
7173
+ ] }) : /* @__PURE__ */ jsx23(
7174
+ DataTableEmptyView,
7175
+ {
7176
+ emptyView: resolvedEmptyView,
7177
+ tableState: graphState,
7178
+ filterCount: filterCount + (!!globalFilter.trim() ? 1 : 0),
7179
+ resetFilters
7180
+ }
7181
+ )
7182
+ ] });
7183
+ }
7184
+
7185
+ // src/graph/hooks/useGetViewportNodeIds.ts
7186
+ import { useEffect as useEffect10, useMemo as useMemo14, useRef as useRef9, useState as useState14 } from "react";
7187
+ import { useStore as useStore2, useViewport } from "reactflow";
7188
+ var useGetDebouncedViewport = (debounceDelay = 1e3) => {
7189
+ const timerRef = useRef9(null);
7190
+ const [debouncedValues, setDebouncedValues] = useState14({ x: 0, y: 0, zoom: 1, width: 0, height: 0, nodes: [] });
7191
+ const { x, y, zoom } = useViewport();
7192
+ const { width, height, nodes } = useStore2((state) => ({
7193
+ width: state.width,
7194
+ height: state.height,
7195
+ nodes: state.getNodes()
7196
+ }));
7197
+ const nodesHash = nodes.map((n) => n.id).sort().join(",");
7198
+ const memoizedNodes = useMemo14(() => nodes, [nodesHash]);
7199
+ useEffect10(() => {
7200
+ if (timerRef.current) {
7201
+ clearTimeout(timerRef.current);
7202
+ }
7203
+ timerRef.current = setTimeout(() => {
7204
+ setDebouncedValues({ x, y, zoom, width, height, nodes: memoizedNodes });
7205
+ timerRef.current = null;
7206
+ }, debounceDelay);
7207
+ return () => {
7208
+ if (timerRef.current) {
7209
+ clearTimeout(timerRef.current);
7210
+ timerRef.current = null;
7211
+ }
7212
+ };
7213
+ }, [x, y, zoom, width, height, memoizedNodes, debounceDelay]);
7214
+ return debouncedValues;
7215
+ };
7216
+ var useGetViewportNodeIds = (debounceDelay = 1e3) => {
7217
+ const { x, y, zoom, width, height, nodes } = useGetDebouncedViewport(debounceDelay);
7218
+ return useMemo14(() => {
7219
+ return nodes.filter((node) => {
7220
+ var _a, _b, _c, _d;
7221
+ if (node.hidden) {
7222
+ return false;
7223
+ }
7224
+ const nodeX = ((_b = (_a = node.positionAbsolute) == null ? void 0 : _a.x) != null ? _b : node.position.x) * zoom + x;
7225
+ const nodeY = ((_d = (_c = node.positionAbsolute) == null ? void 0 : _c.y) != null ? _d : node.position.y) * zoom + y;
7226
+ const nodeW = GRAPH_NODE_WIDTH * zoom;
7227
+ const nodeH = GRAPH_NODE_HEIGHT * zoom;
7228
+ return nodeX + nodeW >= 0 && nodeX <= width && nodeY + nodeH >= 0 && nodeY <= height;
7229
+ }).map((node) => node.id).sort((a, b) => a.localeCompare(b));
7230
+ }, [x, y, zoom, width, height, nodes]);
7231
+ };
7232
+
7233
+ // src/graph/utils.ts
7234
+ import { getOutgoers as getOutgoers2 } from "reactflow";
7235
+ var getGraphDescendants = (node, nodes, edges) => {
7236
+ const outgoers = getOutgoers2(node, nodes, edges);
7237
+ return outgoers.reduce(
7238
+ (acc, outgoer) => {
7239
+ const { nodes: outgoerNodes, edges: outgoerEdges } = getGraphDescendants(outgoer, nodes, edges);
7240
+ return {
7241
+ nodes: [...acc.nodes, ...outgoerNodes],
7242
+ edges: [...acc.edges, ...outgoerEdges.filter((edge) => edge.source === outgoer.id)]
7243
+ };
7244
+ },
7245
+ { nodes: [node], edges: edges.filter((edge) => edge.source === node.id) }
7246
+ );
7247
+ };
7248
+
6227
7249
  // src/page-header.tsx
6228
- import { jsx as jsx19 } from "react/jsx-runtime";
7250
+ import { jsx as jsx24 } from "react/jsx-runtime";
6229
7251
  function PageHeader(_a) {
6230
7252
  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 }));
7253
+ 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
7254
  }
6233
7255
  function PageHeaderAvatar(_a) {
6234
7256
  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));
7257
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-avatar", className: cn("shrink-0 self-center", className) }, props));
6236
7258
  }
6237
7259
  function PageHeaderContent(_a) {
6238
7260
  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));
7261
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-content", className: cn("flex flex-1 flex-col gap-1", className) }, props));
6240
7262
  }
6241
7263
  function PageHeaderTitle(_a) {
6242
7264
  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));
7265
+ return /* @__PURE__ */ jsx24("h1", __spreadValues({ "data-slot": "page-header-title", className: cn("text-h1 text-foreground", className) }, props));
6244
7266
  }
6245
7267
  function PageHeaderDescription(_a) {
6246
7268
  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));
7269
+ return /* @__PURE__ */ jsx24("p", __spreadValues({ "data-slot": "page-header-description", className: cn("text-body text-muted-foreground", className) }, props));
6248
7270
  }
6249
7271
  function PageHeaderMeta(_a) {
6250
7272
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6251
- return /* @__PURE__ */ jsx19(
7273
+ return /* @__PURE__ */ jsx24(
6252
7274
  "div",
6253
7275
  __spreadValues({
6254
7276
  "data-slot": "page-header-meta",
@@ -6262,27 +7284,27 @@ function PageHeaderMeta(_a) {
6262
7284
  }
6263
7285
  function PageHeaderActions(_a) {
6264
7286
  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));
7287
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-actions", className: cn("flex items-center gap-2", className) }, props));
6266
7288
  }
6267
7289
  function PageHeaderTabs(_a) {
6268
7290
  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));
7291
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ "data-slot": "page-header-tabs", className: cn("border-b", className) }, props));
6270
7292
  }
6271
7293
 
6272
7294
  // src/timeline.tsx
6273
- import { Icon as Icon13 } from "@upbound/monarch-core";
7295
+ import { Icon as Icon15 } from "@upbound/monarch-core";
6274
7296
  import { Item as Item2, ItemGroup as ItemGroup2 } from "@upbound/monarch-core";
6275
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
7297
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
6276
7298
  function Timeline(_a) {
6277
7299
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6278
- return /* @__PURE__ */ jsx20(ItemGroup2, __spreadValues({ "data-slot": "timeline", className: cn(className) }, props));
7300
+ return /* @__PURE__ */ jsx25(ItemGroup2, __spreadValues({ "data-slot": "timeline", className: cn(className) }, props));
6279
7301
  }
6280
7302
  function TimelineItem(_a) {
6281
7303
  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(
7304
+ return /* @__PURE__ */ jsxs19(Item2, __spreadProps(__spreadValues({ "data-slot": "timeline-item", className: cn("group/timeline-item gap-3 py-4", className) }, props), { children: [
7305
+ /* @__PURE__ */ jsxs19("div", { className: "relative flex flex-col items-center self-stretch", children: [
7306
+ /* @__PURE__ */ jsx25(Icon15, { name: "circle-dot", size: "sm", className: "text-primary shrink-0" }),
7307
+ /* @__PURE__ */ jsx25(
6286
7308
  "span",
6287
7309
  {
6288
7310
  "aria-hidden": "true",
@@ -6338,6 +7360,12 @@ export {
6338
7360
  FilterChip,
6339
7361
  FloatingWidget,
6340
7362
  FloatingWidgetProvider,
7363
+ Graph,
7364
+ GraphActionsProvider,
7365
+ GraphEdge,
7366
+ GraphNode,
7367
+ GraphNodeSkeleton,
7368
+ GraphView,
6341
7369
  PageHeader,
6342
7370
  PageHeaderActions,
6343
7371
  PageHeaderAvatar,
@@ -6383,6 +7411,9 @@ export {
6383
7411
  dateBoundaryForOperator,
6384
7412
  defaultEmptyConfig,
6385
7413
  defaultErrorConfig,
7414
+ defaultGraphEmptyConfig,
7415
+ defaultGraphErrorConfig,
7416
+ defaultGraphNoFilterFoundConfig,
6386
7417
  defaultNoFilterFoundConfig,
6387
7418
  denormalizeColumnIdWithReservedNames,
6388
7419
  denormalizeColumnsWithReservedNames,
@@ -6394,6 +7425,7 @@ export {
6394
7425
  getColumnEmitOn,
6395
7426
  getDefaultOperator,
6396
7427
  getExpandColumnDefinition,
7428
+ getGraphDescendants,
6397
7429
  getOperatorLabel,
6398
7430
  getQuantifierLabel,
6399
7431
  isCelFilterCondition,
@@ -6403,6 +7435,7 @@ export {
6403
7435
  isDateRangeOperator,
6404
7436
  isDateRelativeOperator,
6405
7437
  isDateWindowOperator,
7438
+ isDefaultNode,
6406
7439
  isEndOfDayTimestamp,
6407
7440
  isEndOfMinuteTimestamp,
6408
7441
  isMapKeyCelValue,
@@ -6426,7 +7459,12 @@ export {
6426
7459
  resolveFilterShape,
6427
7460
  startInstantFromEndOfDay,
6428
7461
  startInstantFromEndOfMinute,
7462
+ useAutoLayout,
6429
7463
  useFloatingWidget,
7464
+ useGetViewportNodeIds,
7465
+ useGraphActions,
7466
+ useGraphActionsContext,
7467
+ useNodeVisibility,
6430
7468
  validateCondition,
6431
7469
  withTimeOfDay
6432
7470
  };