@timeax/service-builder 0.0.5 → 0.0.7

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
@@ -2934,11 +2934,6 @@ function deriveCanvasPresentation(args) {
2934
2934
  };
2935
2935
  }
2936
2936
 
2937
- // src/panels/canvas/index.tsx
2938
- import { useCanvas as useCanvas4, useWorkspace as useWorkspace5 } from "@timeax/digital-service-engine/workspace";
2939
- import { useEffect as useEffect8, useMemo as useMemo8, useRef as useRef5, useState as useState8 } from "react";
2940
- import { FiAlertCircle as FiAlertCircle3 } from "react-icons/fi";
2941
-
2942
2937
  // src/workspace/boot.ts
2943
2938
  var WORKSPACE_BOOT_SECTIONS = [
2944
2939
  "authors",
@@ -2992,7 +2987,7 @@ function getBootSectionTone(sectionState) {
2992
2987
  }
2993
2988
  function getWorkspaceBootHeadline(boot) {
2994
2989
  if (boot.isReady && boot.hasPartialFailure) return "Workspace loaded with issues";
2995
- if (boot.isReady) return "Workspace ready";
2990
+ if (boot.isReady) return "ready";
2996
2991
  if (boot.hasErrors && !boot.isBooting) return "Workspace load needs attention";
2997
2992
  if (boot.isSeededView) return "Syncing live workspace data";
2998
2993
  return "Loading workspace";
@@ -3029,6 +3024,11 @@ function getActiveBootSections(boot) {
3029
3024
  return WORKSPACE_BOOT_SECTIONS.filter((section) => boot.sections[section].status === "loading");
3030
3025
  }
3031
3026
 
3027
+ // src/panels/canvas/index.tsx
3028
+ import { useCanvas as useCanvas4, useWorkspace as useWorkspace5 } from "@timeax/digital-service-engine/workspace";
3029
+ import { useEffect as useEffect8, useMemo as useMemo8, useRef as useRef5, useState as useState8 } from "react";
3030
+ import { FiAlertCircle as FiAlertCircle3 } from "react-icons/fi";
3031
+
3032
3032
  // src/panels/canvas/app-toolbar.tsx
3033
3033
  import { FiAlertCircle, FiEye, FiEyeOff, FiSave, FiTerminal } from "react-icons/fi";
3034
3034
  import { LuGitCommitHorizontal, LuHistory, LuRedo2, LuUndo2 } from "react-icons/lu";
@@ -5043,16 +5043,20 @@ function CanvasPanel({
5043
5043
  offGraph();
5044
5044
  };
5045
5045
  }, [canvas.api]);
5046
+ function setSnapshot(event) {
5047
+ const nextSnapshot = event?.snapshot;
5048
+ if (!nextSnapshot) return;
5049
+ const nextHash = hashSnapshot(nextSnapshot);
5050
+ setCurrentSnapshotHash((current) => current === nextHash ? current : nextHash);
5051
+ if (nextHash !== lastSyncedSnapshotHashRef.current) {
5052
+ lastSyncedSnapshotHashRef.current = nextHash;
5053
+ ws.snapshot.set(() => nextSnapshot);
5054
+ }
5055
+ }
5046
5056
  useEffect8(() => {
5057
+ const catalogChange = canvas.api.on("catalog:change", setSnapshot);
5047
5058
  const offEditorChange = canvas.api.on("editor:change", (event) => {
5048
- const nextSnapshot = event?.snapshot;
5049
- if (!nextSnapshot) return;
5050
- const nextHash = hashSnapshot(nextSnapshot);
5051
- setCurrentSnapshotHash((current) => current === nextHash ? current : nextHash);
5052
- if (nextHash !== lastSyncedSnapshotHashRef.current) {
5053
- lastSyncedSnapshotHashRef.current = nextHash;
5054
- ws.snapshot.set(() => nextSnapshot);
5055
- }
5059
+ setSnapshot(event);
5056
5060
  if (event?.reason === "mutation" || event?.reason === "transaction") {
5057
5061
  setHistoryState({ canUndo: true, canRedo: false });
5058
5062
  }
@@ -5077,11 +5081,12 @@ function CanvasPanel({
5077
5081
  offEditorChange?.();
5078
5082
  offUndo?.();
5079
5083
  offRedo?.();
5084
+ catalogChange?.();
5080
5085
  };
5081
5086
  }, [canvas.api, ws.snapshot]);
5082
5087
  const hasChanges = currentSnapshotHash !== persistedBaselineHash;
5083
- const canSave = hasChanges || !!ws.snapshot.draft;
5084
- const canPublish = hasChanges || !!ws.snapshot.draft;
5088
+ const canSave = hasChanges;
5089
+ const canPublish = !!ws.snapshot.draft && !hasChanges;
5085
5090
  const bootActionReason = getBootActionReason(ws.boot);
5086
5091
  const failedBlockingSections = getFailedBlockingSections(ws.boot);
5087
5092
  const resolvedCurrentTagId = useMemo8(() => {
@@ -6590,19 +6595,61 @@ var drafts_default = Drafts;
6590
6595
 
6591
6596
  // src/panels/left/components/header.tsx
6592
6597
  import { useWorkspace as useWorkspace7 } from "@timeax/digital-service-engine/workspace";
6593
- import { GoChevronDown } from "react-icons/go";
6598
+ import { useState as useState11 } from "react";
6599
+ import { BsChevronDown, BsChevronRight } from "react-icons/bs";
6594
6600
  import { MdMenuOpen, MdOutlineSpaceDashboard } from "react-icons/md";
6595
6601
  import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
6596
- var Header = () => {
6602
+ var MenuRenderer = ({ items, depth = 0 }) => {
6603
+ const [openSubmenus, setOpenSubmenus] = useState11({});
6604
+ const toggleSubmenu = (name) => {
6605
+ setOpenSubmenus((prev) => ({ ...prev, [name]: !prev[name] }));
6606
+ };
6607
+ return /* @__PURE__ */ jsx26("ul", { className: "flex flex-col gap-1", children: items.map((item, index) => {
6608
+ const hasChildren = item.children && item.children.length > 0;
6609
+ const isOpen = openSubmenus[item.name];
6610
+ if (item.render) {
6611
+ return /* @__PURE__ */ jsx26("li", { children: item.render() }, index);
6612
+ }
6613
+ return /* @__PURE__ */ jsxs19("li", { className: "flex flex-col", children: [
6614
+ /* @__PURE__ */ jsxs19(
6615
+ "button",
6616
+ {
6617
+ type: "button",
6618
+ onClick: () => {
6619
+ if (hasChildren) {
6620
+ toggleSubmenu(item.name);
6621
+ } else if (item.command) {
6622
+ item.command();
6623
+ }
6624
+ },
6625
+ className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-slate-700 transition hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800",
6626
+ children: [
6627
+ item.icon && /* @__PURE__ */ jsx26("span", { className: "flex h-4 w-4 items-center justify-center text-slate-500", children: item.icon }),
6628
+ /* @__PURE__ */ jsx26("span", { className: "flex-1 text-left", children: item.name }),
6629
+ hasChildren && /* @__PURE__ */ jsx26("span", { className: `transition-transform ${isOpen ? "rotate-90" : ""}`, children: /* @__PURE__ */ jsx26(BsChevronRight, { className: "h-3 w-3" }) })
6630
+ ]
6631
+ }
6632
+ ),
6633
+ hasChildren && isOpen && /* @__PURE__ */ jsx26("div", { className: "mt-1 ml-4 border-l border-slate-200 pl-2 dark:border-slate-800", children: /* @__PURE__ */ jsx26(MenuRenderer, { items: item.children, depth: depth + 1 }) })
6634
+ ] }, index);
6635
+ }) });
6636
+ };
6637
+ var Header = ({ menu = [] }) => {
6597
6638
  const ws = useWorkspace7();
6598
6639
  const currentBranch = ws.branches.data?.find((branch) => branch.id === ws.branches.currentId);
6599
6640
  const workspaceStatus = getWorkspaceBootHeadline(ws.boot);
6641
+ const fullMenu = [
6642
+ {
6643
+ name: "Status",
6644
+ render: () => /* @__PURE__ */ jsx26("div", { className: "px-2 py-1.5 text-xs font-medium tracking-wider text-slate-500 uppercase", children: workspaceStatus })
6645
+ },
6646
+ ...menu
6647
+ ];
6600
6648
  return /* @__PURE__ */ jsx26("div", { className: "border-b border-slate-200 px-4 py-3 dark:border-slate-800", children: /* @__PURE__ */ jsxs19("div", { className: "flex items-start justify-between gap-3", children: [
6601
6649
  /* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-3", children: [
6602
6650
  /* @__PURE__ */ jsx26("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl bg-blue-600 text-white shadow-sm", children: /* @__PURE__ */ jsx26(MdOutlineSpaceDashboard, { className: "text-base" }) }),
6603
- /* @__PURE__ */ jsxs19("div", { children: [
6604
- /* @__PURE__ */ jsx26("div", { className: "text-[10px] uppercase tracking-[0.24em] text-slate-400 dark:text-slate-500", children: "Workspace" }),
6605
- /* @__PURE__ */ jsx26("h1", { className: "text-base font-semibold text-slate-900 dark:text-slate-100", children: "Service Builder" }),
6651
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col justify-center gap-0", children: [
6652
+ /* @__PURE__ */ jsx26("h1", { className: "text-base leading-tight font-semibold text-slate-900 dark:text-slate-100", children: "Service Builder" }),
6606
6653
  /* @__PURE__ */ jsx26(
6607
6654
  drafts_default,
6608
6655
  {
@@ -6610,14 +6657,13 @@ var Header = () => {
6610
6657
  "button",
6611
6658
  {
6612
6659
  type: "button",
6613
- className: "mt-0.5 inline-flex items-center gap-1 rounded-md px-1 text-xs text-slate-500 transition hover:bg-slate-100 hover:text-slate-700 dark:text-slate-400 dark:hover:bg-slate-900 dark:hover:text-slate-200",
6660
+ className: "inline-flex cursor-pointer items-center gap-1 rounded-md text-xs text-slate-500 transition hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200",
6614
6661
  children: [
6615
6662
  /* @__PURE__ */ jsxs19("span", { children: [
6616
- currentBranch?.name ?? "Main branch",
6617
- " \xB7 ",
6618
- workspaceStatus
6663
+ "Active branch - ",
6664
+ /* @__PURE__ */ jsx26("b", { children: currentBranch?.name ?? "Main branch" })
6619
6665
  ] }),
6620
- /* @__PURE__ */ jsx26(GoChevronDown, { className: "text-sm" })
6666
+ /* @__PURE__ */ jsx26(BsChevronDown, {})
6621
6667
  ]
6622
6668
  }
6623
6669
  )
@@ -6625,7 +6671,10 @@ var Header = () => {
6625
6671
  )
6626
6672
  ] })
6627
6673
  ] }),
6628
- /* @__PURE__ */ jsx26(BuilderIconButton, { title: "Collapse left panel", children: /* @__PURE__ */ jsx26(MdMenuOpen, {}) })
6674
+ /* @__PURE__ */ jsxs19(Popover, { children: [
6675
+ /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx26("span", { children: /* @__PURE__ */ jsx26(BuilderIconButton, { title: "Menu", children: /* @__PURE__ */ jsx26(MdMenuOpen, {}) }) }) }),
6676
+ /* @__PURE__ */ jsx26(PopoverContent, { className: "w-56 p-2", align: "end", children: /* @__PURE__ */ jsx26(MenuRenderer, { items: fullMenu }) })
6677
+ ] })
6629
6678
  ] }) });
6630
6679
  };
6631
6680
  var header_default = Header;
@@ -6691,7 +6740,7 @@ function ScrollBar({
6691
6740
  // src/panels/left/assets/index.tsx
6692
6741
  import { useInputs } from "@timeax/digital-service-engine/react";
6693
6742
  import { useWorkspace as useWorkspace8 } from "@timeax/digital-service-engine/workspace";
6694
- import { useMemo as useMemo11, useState as useState11 } from "react";
6743
+ import { useMemo as useMemo11, useState as useState12 } from "react";
6695
6744
  import { CiSearch } from "react-icons/ci";
6696
6745
  import { LuBox, LuShapes } from "react-icons/lu";
6697
6746
  import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
@@ -6701,7 +6750,7 @@ function toTitle(value) {
6701
6750
  function AssetsPanel() {
6702
6751
  const ws = useWorkspace8();
6703
6752
  const { registry } = useInputs();
6704
- const [query, setQuery] = useState11("");
6753
+ const [query, setQuery] = useState12("");
6705
6754
  const normalizedBuiltins = useMemo11(() => {
6706
6755
  const items = [];
6707
6756
  for (const [kind, variants] of registry._store.entries()) {
@@ -8931,7 +8980,7 @@ Panel.displayName = "Panel";
8931
8980
 
8932
8981
  // src/panels/left/layers/index.tsx
8933
8982
  import { useCanvas as useCanvas5 } from "@timeax/digital-service-engine/workspace";
8934
- import { useMemo as useMemo17, useRef as useRef10, useState as useState19 } from "react";
8983
+ import { useMemo as useMemo17, useRef as useRef10, useState as useState20 } from "react";
8935
8984
  import { BsXDiamondFill } from "react-icons/bs";
8936
8985
  import { CiSearch as CiSearch2 } from "react-icons/ci";
8937
8986
  import { LuTags as LuTags3 } from "react-icons/lu";
@@ -8961,10 +9010,10 @@ var Layers = () => {
8961
9010
  const fieldsRef = useRef10(null);
8962
9011
  const tagSearchInputRef = useRef10(null);
8963
9012
  const fieldSearchInputRef = useRef10(null);
8964
- const [tagSearch, setTagSearch] = useState19("");
8965
- const [fieldSearch, setFieldSearch] = useState19("");
8966
- const [isTagSearchOpen, setIsTagSearchOpen] = useState19(false);
8967
- const [isFieldSearchOpen, setIsFieldSearchOpen] = useState19(false);
9013
+ const [tagSearch, setTagSearch] = useState20("");
9014
+ const [fieldSearch, setFieldSearch] = useState20("");
9015
+ const [isTagSearchOpen, setIsTagSearchOpen] = useState20(false);
9016
+ const [isFieldSearchOpen, setIsFieldSearchOpen] = useState20(false);
8968
9017
  const handleSelection = (ids, meta) => {
8969
9018
  if (meta?.via === "api") return;
8970
9019
  const primary = ids[0];
@@ -9298,7 +9347,7 @@ function TabsContent({
9298
9347
  import { CiGrid32 } from "react-icons/ci";
9299
9348
  import { MdOutlineLayers } from "react-icons/md";
9300
9349
  import { jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
9301
- var Left = () => {
9350
+ var Left = ({ menu }) => {
9302
9351
  const tabClassName = cn(
9303
9352
  "rounded-xl! py-2! shadow-none!",
9304
9353
  "text-slate-500 data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm",
@@ -9312,7 +9361,7 @@ var Left = () => {
9312
9361
  maxWidth: 420,
9313
9362
  minWidth: 320,
9314
9363
  children: /* @__PURE__ */ jsxs27("div", { className: "flex h-full flex-col", children: [
9315
- /* @__PURE__ */ jsx40(header_default, {}),
9364
+ /* @__PURE__ */ jsx40(header_default, { menu }),
9316
9365
  /* @__PURE__ */ jsx40("div", { className: "flex min-h-0 flex-1 flex-col gap-2 py-2", children: /* @__PURE__ */ jsxs27(Tabs, { defaultValue: "layers", className: "flex min-h-0 flex-1 flex-col px-3", children: [
9317
9366
  /* @__PURE__ */ jsxs27(TabsList, { className: "grid h-auto grid-cols-2 rounded-2xl bg-slate-100 p-1 dark:bg-slate-900", children: [
9318
9367
  /* @__PURE__ */ jsx40(TabsTrigger, { className: tabClassName, value: "layers", children: /* @__PURE__ */ jsxs27("span", { className: "flex items-center gap-2", children: [
@@ -9336,7 +9385,7 @@ var left_default = Left;
9336
9385
  // src/panels/right/components/users.tsx
9337
9386
  import "@timeax/digital-service-engine/workspace";
9338
9387
  import { useMemo as useMemo18 } from "react";
9339
- import { GoChevronDown as GoChevronDown2 } from "react-icons/go";
9388
+ import { GoChevronDown } from "react-icons/go";
9340
9389
  import { HiOutlineDotsHorizontal } from "react-icons/hi";
9341
9390
  import { PiUserPlusThin } from "react-icons/pi";
9342
9391
  import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
@@ -9421,7 +9470,7 @@ var Users = ({ users, onViewUser, onSetMain, onToggleAdmin, onRemoveUser, onInvi
9421
9470
  extra
9422
9471
  ] }) : null
9423
9472
  ] }),
9424
- /* @__PURE__ */ jsx41(GoChevronDown2, { className: "shrink-0 text-slate-500" })
9473
+ /* @__PURE__ */ jsx41(GoChevronDown, { className: "shrink-0 text-slate-500" })
9425
9474
  ]
9426
9475
  }
9427
9476
  ) }),
@@ -9789,13 +9838,13 @@ function ActiveDot() {
9789
9838
  // src/panels/right/tabs/comments.tsx
9790
9839
  import { useWorkspace as useWorkspace10 } from "@timeax/digital-service-engine/workspace";
9791
9840
  import { InputField as InputField4 } from "@timeax/form-palette";
9792
- import { useMemo as useMemo21, useState as useState21 } from "react";
9841
+ import { useMemo as useMemo21, useState as useState22 } from "react";
9793
9842
  import { MdOutlineSend } from "react-icons/md";
9794
9843
  import { jsx as jsx45, jsxs as jsxs31 } from "react/jsx-runtime";
9795
9844
  var Comments = () => {
9796
9845
  const ws = useWorkspace10();
9797
- const [value, setValue] = useState21("");
9798
- const [query, setQuery] = useState21("");
9846
+ const [value, setValue] = useState22("");
9847
+ const [query, setQuery] = useState22("");
9799
9848
  const threads = useMemo21(() => {
9800
9849
  const items = ws.comments.threads.data ?? [];
9801
9850
  const lower = query.trim().toLowerCase();
@@ -10088,7 +10137,7 @@ function RenderIf({ data, emptyMessage = null, children, when }) {
10088
10137
  // src/panels/right/partials/global/add-service.tsx
10089
10138
  import { useCanvas as useCanvas7, useWorkspace as useWorkspace11 } from "@timeax/digital-service-engine/workspace";
10090
10139
  import { InputField as InputField5 } from "@timeax/form-palette";
10091
- import { useMemo as useMemo23, useState as useState23 } from "react";
10140
+ import { useMemo as useMemo23, useState as useState24 } from "react";
10092
10141
  import { BsPlus } from "react-icons/bs";
10093
10142
  import { Fragment as Fragment9, jsx as jsx50, jsxs as jsxs33 } from "react/jsx-runtime";
10094
10143
  function AddService({ className, data, disabled, disabledMessage, readOnly, readOnlyMessage, emptyMessage }) {
@@ -10162,9 +10211,9 @@ function ServiceSummary({ service, nodeId, disabled }) {
10162
10211
  }
10163
10212
  function AddServicePopover({ data, services: services2 }) {
10164
10213
  const canvas = useCanvas7();
10165
- const [open, setOpen] = useState23(false);
10166
- const [query, setQuery] = useState23("");
10167
- const [selected, setSelected] = useState23("");
10214
+ const [open, setOpen] = useState24(false);
10215
+ const [query, setQuery] = useState24("");
10216
+ const [selected, setSelected] = useState24("");
10168
10217
  const options = useMemo23(() => {
10169
10218
  const lower = query.trim().toLowerCase();
10170
10219
  return services2.filter((service) => {
@@ -10222,11 +10271,11 @@ var add_service_default = AddService;
10222
10271
  import { resolveInputDescriptor, useInputs as useInputs2 } from "@timeax/digital-service-engine/react";
10223
10272
  import { useCanvas as useCanvas12 } from "@timeax/digital-service-engine/workspace";
10224
10273
  import { InputField as InputField11 } from "@timeax/form-palette";
10225
- import { useEffect as useEffect17, useMemo as useMemo28, useState as useState27 } from "react";
10274
+ import { useEffect as useEffect17, useMemo as useMemo28, useState as useState28 } from "react";
10226
10275
 
10227
10276
  // src/panels/right/partials/properties/components/descriptor-settings.tsx
10228
10277
  import { InputField as InputField6 } from "@timeax/form-palette";
10229
- import { useMemo as useMemo24, useState as useState24 } from "react";
10278
+ import { useMemo as useMemo24, useState as useState25 } from "react";
10230
10279
 
10231
10280
  // src/panels/right/partials/properties/components/meta.ts
10232
10281
  function mergeNodeMeta(meta, patch) {
@@ -10524,9 +10573,9 @@ function DescriptorPrimitiveField({ schema, value, hasOverride, onSet, onClear,
10524
10573
  function DescriptorObjectField({ schema, value, hasOverride, onSet, onClear, path, allowClear = true }) {
10525
10574
  const objectValue = asRecord(value);
10526
10575
  const shapeEntries = useMemo24(() => Object.entries(schema.shape ?? {}), [schema.shape]);
10527
- const [draftKey, setDraftKey] = useState24("");
10528
- const [draftShape, setDraftShape] = useState24(shapeEntries[0]?.[0] ?? "");
10529
- const [activeShapes, setActiveShapes] = useState24({});
10576
+ const [draftKey, setDraftKey] = useState25("");
10577
+ const [draftShape, setDraftShape] = useState25(shapeEntries[0]?.[0] ?? "");
10578
+ const [activeShapes, setActiveShapes] = useState25({});
10530
10579
  const orderedEntries = useMemo24(() => getOrderedObjectEntries(schema), [schema]);
10531
10580
  const dynamicKeys = Object.keys(objectValue).filter((key) => !hasOwn(schema.fields, key));
10532
10581
  const commitObject = (nextObject) => {
@@ -10684,8 +10733,8 @@ function DescriptorObjectField({ schema, value, hasOverride, onSet, onClear, pat
10684
10733
  function DescriptorArrayField({ schema, value, hasOverride, onSet, onClear, path, allowClear = true }) {
10685
10734
  const arrayValue = asArray(value);
10686
10735
  const shapeEntries = useMemo24(() => Object.entries(schema.shape ?? {}), [schema.shape]);
10687
- const [draftShape, setDraftShape] = useState24(shapeEntries[0]?.[0] ?? "");
10688
- const [activeShapes, setActiveShapes] = useState24({});
10736
+ const [draftShape, setDraftShape] = useState25(shapeEntries[0]?.[0] ?? "");
10737
+ const [activeShapes, setActiveShapes] = useState25({});
10689
10738
  const commitArray = (nextArray) => {
10690
10739
  if (!nextArray.length) {
10691
10740
  onClear(path);
@@ -11660,15 +11709,15 @@ function ValidationSection({ node }) {
11660
11709
  import "@timeax/digital-service-engine/core";
11661
11710
  import { useCanvas as useCanvas11 } from "@timeax/digital-service-engine/workspace";
11662
11711
  import { keyBy } from "lodash";
11663
- import { useMemo as useMemo27, useState as useState26 } from "react";
11712
+ import { useMemo as useMemo27, useState as useState27 } from "react";
11664
11713
 
11665
11714
  // src/panels/right/partials/properties/components/AddIncludesPopover.tsx
11666
11715
  import { InputField as InputField10 } from "@timeax/form-palette";
11667
- import { useState as useState25 } from "react";
11716
+ import { useState as useState26 } from "react";
11668
11717
  import { BsPlus as BsPlus5 } from "react-icons/bs";
11669
11718
  import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
11670
11719
  function AddIncludesPopover({ open, onOpenChange, onSelect, options }) {
11671
- const [value, setValue] = useState25();
11720
+ const [value, setValue] = useState26();
11672
11721
  return /* @__PURE__ */ jsxs38(Popover, { open, onOpenChange, children: [
11673
11722
  /* @__PURE__ */ jsx55(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx55(SectionActionTriggerButton, { icon: /* @__PURE__ */ jsx55(BsPlus5, {}), children: "Add" }) }),
11674
11723
  /* @__PURE__ */ jsx55(PopoverContent, { children: /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-2", children: [
@@ -11705,7 +11754,7 @@ function AddIncludesPopover({ open, onOpenChange, onSelect, options }) {
11705
11754
  import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
11706
11755
  function IncExcludeSection({ node, mode, capability }) {
11707
11756
  const canvas = useCanvas11();
11708
- const [open, setOpen] = useState26(false);
11757
+ const [open, setOpen] = useState27(false);
11709
11758
  const canEdit = capability?.canEdit ?? true;
11710
11759
  const helperMessage = capability?.message;
11711
11760
  const fields = useMemo27(() => keyBy(canvas.props.fields, "id"), [canvas.props]);
@@ -11806,9 +11855,9 @@ function FieldProperties({ className, node }) {
11806
11855
  const nameValue = node.raw.name ?? "";
11807
11856
  const placeholderValue = defaults.placeholder ?? "";
11808
11857
  const helpTextValue = defaults.helpText ?? "";
11809
- const [nameDraft, setNameDraft] = useState27(nameValue);
11810
- const [placeholderDraft, setPlaceholderDraft] = useState27(placeholderValue);
11811
- const [helpTextDraft, setHelpTextDraft] = useState27(helpTextValue);
11858
+ const [nameDraft, setNameDraft] = useState28(nameValue);
11859
+ const [placeholderDraft, setPlaceholderDraft] = useState28(placeholderValue);
11860
+ const [helpTextDraft, setHelpTextDraft] = useState28(helpTextValue);
11812
11861
  const descriptor = useMemo28(() => resolveInputDescriptor(registry, currentType, currentVariant), [currentType, currentVariant, registry]);
11813
11862
  const descriptorUi = descriptor?.ui ?? {};
11814
11863
  const descriptorKeySet = useMemo28(() => new Set(getDescriptorUiKeys(descriptorUi)), [descriptorUi]);
@@ -12128,7 +12177,7 @@ import "@timeax/digital-service-engine/core";
12128
12177
  import { useCanvas as useCanvas14 } from "@timeax/digital-service-engine/workspace";
12129
12178
  import { InputField as InputField14 } from "@timeax/form-palette";
12130
12179
  import { ArrowUpRight } from "lucide-react";
12131
- import { useMemo as useMemo29, useState as useState28 } from "react";
12180
+ import { useMemo as useMemo29, useState as useState29 } from "react";
12132
12181
  import { TiDelete } from "react-icons/ti";
12133
12182
 
12134
12183
  // src/panels/right/partials/properties/tag/AddConstraintsPopover.tsx
@@ -12254,7 +12303,7 @@ import { Fragment as Fragment12, jsx as jsx62, jsxs as jsxs45 } from "react/jsx-
12254
12303
  function TagConstraintsSection({ node }) {
12255
12304
  const constraints = Object.keys(node.raw.constraints ?? {});
12256
12305
  const canvas = useCanvas14();
12257
- const [open, setOpen] = useState28(false);
12306
+ const [open, setOpen] = useState29(false);
12258
12307
  const allConstraints = useMemo29(() => canvas.api.getConstraints() ?? [], [canvas.props]);
12259
12308
  return /* @__PURE__ */ jsx62(Fragment12, { children: /* @__PURE__ */ jsxs45(Section, { children: [
12260
12309
  /* @__PURE__ */ jsxs45(Section.Header, { children: [
@@ -12371,7 +12420,7 @@ function TagProperties({ node }) {
12371
12420
  // src/panels/right/tabs/properties.tsx
12372
12421
  import { useCanvas as useCanvas15, useWorkspace as useWorkspace12 } from "@timeax/digital-service-engine/workspace";
12373
12422
  import { InputField as InputField15 } from "@timeax/form-palette";
12374
- import { useMemo as useMemo30, useState as useState29 } from "react";
12423
+ import { useMemo as useMemo30, useState as useState30 } from "react";
12375
12424
  import { AiOutlineLoading3Quarters } from "react-icons/ai";
12376
12425
  import { MdOutlineContentCopy } from "react-icons/md";
12377
12426
  import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
@@ -12387,7 +12436,7 @@ var Properties = () => {
12387
12436
  if (!canvas.activeId) return { kind: "none" };
12388
12437
  return canvas.selector.getNode(canvas.activeId);
12389
12438
  }, [canvas.activeId, canvas.props, canvas.selection]);
12390
- const [copying, setCopying] = useState29(false);
12439
+ const [copying, setCopying] = useState30(false);
12391
12440
  const Kind = kinds[node.kind];
12392
12441
  if (!Kind) {
12393
12442
  return /* @__PURE__ */ jsx66("div", { className: "p-4", children: /* @__PURE__ */ jsx66(EmptyState, { title: "No active node selected", description: "Pick a tag, field, or option from the layers panel or canvas to inspect its core settings." }) });
@@ -12960,7 +13009,7 @@ function describeCheck(check, state) {
12960
13009
  // src/workspace/fallback-editor-modal.tsx
12961
13010
  import { useCanvas as useCanvas18, useWorkspace as useWorkspace14 } from "@timeax/digital-service-engine/workspace";
12962
13011
  import cloneDeep2 from "lodash/cloneDeep";
12963
- import { Suspense, lazy, createContext as createContext4, useCallback as useCallback17, useContext as useContext4, useEffect as useEffect18, useMemo as useMemo32, useState as useState30 } from "react";
13012
+ import { Suspense, lazy, createContext as createContext4, useCallback as useCallback17, useContext as useContext4, useEffect as useEffect18, useMemo as useMemo32, useState as useState31 } from "react";
12964
13013
  import { createPortal as createPortal3 } from "react-dom";
12965
13014
  import { FiX as FiX3 } from "react-icons/fi";
12966
13015
  import { jsx as jsx70, jsxs as jsxs51 } from "react/jsx-runtime";
@@ -12980,9 +13029,9 @@ var FallbackEditorModalContext = createContext4(defaultContextValue2);
12980
13029
  function FallbackEditorModalProvider({ children }) {
12981
13030
  const canvas = useCanvas18();
12982
13031
  const ws = useWorkspace14();
12983
- const [launch, setLaunch] = useState30(null);
12984
- const [sessionId, setSessionId] = useState30(0);
12985
- const [surfaceError, setSurfaceError] = useState30(null);
13032
+ const [launch, setLaunch] = useState31(null);
13033
+ const [sessionId, setSessionId] = useState31(0);
13034
+ const [surfaceError, setSurfaceError] = useState31(null);
12986
13035
  const close = useCallback17(() => {
12987
13036
  setLaunch(null);
12988
13037
  setSurfaceError(null);
@@ -13151,7 +13200,7 @@ function useFallbackEditorModal() {
13151
13200
 
13152
13201
  // src/workspace/bottom-panel/index.tsx
13153
13202
  import { useCanvas as useCanvas21, useWorkspace as useWorkspace15 } from "@timeax/digital-service-engine/workspace";
13154
- import { useCallback as useCallback18, useEffect as useEffect21, useMemo as useMemo34, useRef as useRef11, useState as useState33 } from "react";
13203
+ import { useCallback as useCallback18, useEffect as useEffect21, useMemo as useMemo34, useRef as useRef11, useState as useState34 } from "react";
13155
13204
  import { FiEye as FiEye3, FiEyeOff as FiEyeOff2, FiSearch, FiTerminal as FiTerminal2, FiX as FiX5 } from "react-icons/fi";
13156
13205
  import { LuGripHorizontal, LuLayers3 } from "react-icons/lu";
13157
13206
  import { MdOutlineSync } from "react-icons/md";
@@ -13606,7 +13655,7 @@ function LogCard({ row, onRemove }) {
13606
13655
 
13607
13656
  // src/workspace/bottom-panel/service-picker-dialog.tsx
13608
13657
  import { InputField as InputField16 } from "@timeax/form-palette";
13609
- import { useEffect as useEffect19, useMemo as useMemo33, useState as useState31 } from "react";
13658
+ import { useEffect as useEffect19, useMemo as useMemo33, useState as useState32 } from "react";
13610
13659
  import { createPortal as createPortal4 } from "react-dom";
13611
13660
 
13612
13661
  // src/workspace/bottom-panel/service-picker.ts
@@ -13735,8 +13784,8 @@ function ServicePickerDialog({
13735
13784
  onOpenChange,
13736
13785
  onConfirm
13737
13786
  }) {
13738
- const [filters, setFilters] = useState31(() => createDefaultServicePickerFilters());
13739
- const [selectedIds, setSelectedIds] = useState31(/* @__PURE__ */ new Set());
13787
+ const [filters, setFilters] = useState32(() => createDefaultServicePickerFilters());
13788
+ const [selectedIds, setSelectedIds] = useState32(/* @__PURE__ */ new Set());
13740
13789
  useEffect19(() => {
13741
13790
  if (!open) return;
13742
13791
  setFilters(createDefaultServicePickerFilters());
@@ -14077,7 +14126,7 @@ function ResizableHandle({
14077
14126
 
14078
14127
  // src/workspace/bottom-panel/services-split-pane.tsx
14079
14128
  import { InputField as InputField17 } from "@timeax/form-palette";
14080
- import { useEffect as useEffect20, useState as useState32 } from "react";
14129
+ import { useEffect as useEffect20, useState as useState33 } from "react";
14081
14130
  import { FaFolderOpen } from "react-icons/fa";
14082
14131
  import { FiEdit2, FiFilter, FiFolderPlus, FiPlus as FiPlus2, FiTrash2 as FiTrash22 } from "react-icons/fi";
14083
14132
 
@@ -14562,7 +14611,6 @@ function CatalogToolbar({
14562
14611
  {
14563
14612
  variant: "treeselect",
14564
14613
  mode: "button",
14565
- label: "Catalog group selector",
14566
14614
  className: "w-fit!",
14567
14615
  multiple: false,
14568
14616
  value: treeValue,
@@ -14587,8 +14635,8 @@ function GroupInputPopoverButton({
14587
14635
  disabled = false,
14588
14636
  onSubmit
14589
14637
  }) {
14590
- const [open, setOpen] = useState32(false);
14591
- const [value, setValue] = useState32(initialValue);
14638
+ const [open, setOpen] = useState33(false);
14639
+ const [value, setValue] = useState33(initialValue);
14592
14640
  useEffect20(() => {
14593
14641
  if (open) setValue(initialValue);
14594
14642
  }, [initialValue, open]);
@@ -14654,7 +14702,7 @@ function ConfirmPopoverButton({
14654
14702
  disabled = false,
14655
14703
  onConfirm
14656
14704
  }) {
14657
- const [open, setOpen] = useState32(false);
14705
+ const [open, setOpen] = useState33(false);
14658
14706
  return /* @__PURE__ */ jsxs55(Popover, { open, onOpenChange: setOpen, children: [
14659
14707
  /* @__PURE__ */ jsx76(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx76(
14660
14708
  "button",
@@ -14745,26 +14793,26 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
14745
14793
  const policies2 = ws.policies.policies.data ?? [];
14746
14794
  const currentTagId = canvas.api.selection.currentTag?.();
14747
14795
  const preferredTagId = currentTagId != null ? String(currentTagId) : canvas.layers.tags[0]?.id != null ? String(canvas.layers.tags[0]?.id) : null;
14748
- const [activeSearch, setActiveSearch] = useState33("");
14749
- const [allSearch, setAllSearch] = useState33("");
14750
- const [compatibleOnly, setCompatibleOnly] = useState33(false);
14751
- const [hideActiveServices, setHideActiveServices] = useState33(false);
14752
- const [filterOpen, setFilterOpen] = useState33(false);
14753
- const [searchOpen, setSearchOpen] = useState33(false);
14754
- const [contextLinked, setContextLinked] = useState33(false);
14755
- const [servicePickerOpen, setServicePickerOpen] = useState33(false);
14756
- const [selectedActiveServiceId, setSelectedActiveServiceId] = useState33(null);
14757
- const [selectedAllServiceId, setSelectedAllServiceId] = useState33(null);
14758
- const [catalogContextDraft, setCatalogContextDraft] = useState33(
14796
+ const [activeSearch, setActiveSearch] = useState34("");
14797
+ const [allSearch, setAllSearch] = useState34("");
14798
+ const [compatibleOnly, setCompatibleOnly] = useState34(false);
14799
+ const [hideActiveServices, setHideActiveServices] = useState34(false);
14800
+ const [filterOpen, setFilterOpen] = useState34(false);
14801
+ const [searchOpen, setSearchOpen] = useState34(false);
14802
+ const [contextLinked, setContextLinked] = useState34(false);
14803
+ const [servicePickerOpen, setServicePickerOpen] = useState34(false);
14804
+ const [selectedActiveServiceId, setSelectedActiveServiceId] = useState34(null);
14805
+ const [selectedAllServiceId, setSelectedAllServiceId] = useState34(null);
14806
+ const [catalogContextDraft, setCatalogContextDraft] = useState34(
14759
14807
  () => createDefaultServiceContext(canvas.props, preferredTagId)
14760
14808
  );
14761
- const [catalogState, setCatalogState] = useState33(null);
14762
- const [panelPosition, setPanelPosition] = useState33(() => readStoredPanelPosition());
14763
- const [draggingPanel, setDraggingPanel] = useState33(false);
14764
- const [consoleSubTab, setConsoleSubTab] = useState33("validation");
14765
- const [consoleScopeFilter, setConsoleScopeFilter] = useState33("all");
14766
- const [consoleSeverityFilter, setConsoleSeverityFilter] = useState33("all");
14767
- const [consoleIntroState, setConsoleIntroState] = useState33({
14809
+ const [catalogState, setCatalogState] = useState34(null);
14810
+ const [panelPosition, setPanelPosition] = useState34(() => readStoredPanelPosition());
14811
+ const [draggingPanel, setDraggingPanel] = useState34(false);
14812
+ const [consoleSubTab, setConsoleSubTab] = useState34("validation");
14813
+ const [consoleScopeFilter, setConsoleScopeFilter] = useState34("all");
14814
+ const [consoleSeverityFilter, setConsoleSeverityFilter] = useState34("all");
14815
+ const [consoleIntroState, setConsoleIntroState] = useState34({
14768
14816
  validation: { minimized: false, closed: false },
14769
14817
  logs: { minimized: false, closed: false },
14770
14818
  notices: { minimized: false, closed: false }
@@ -15366,7 +15414,7 @@ function CatalogModeSwitch({ mode, onChange }) {
15366
15414
  // src/index.tsx
15367
15415
  import { createInputRegistry, Provider as InputsProvider, registerEntries } from "@timeax/digital-service-engine/react";
15368
15416
  import { useCanvas as useCanvas22, useErrors, useWorkspace as useWorkspace16, Workspace } from "@timeax/digital-service-engine/workspace";
15369
- import { useMemo as useMemo35, useState as useState34 } from "react";
15417
+ import { useMemo as useMemo35, useState as useState35 } from "react";
15370
15418
 
15371
15419
  // backend/memory/create-backend.ts
15372
15420
  import { createMemoryWorkspaceBackend } from "@timeax/digital-service-engine/workspace";
@@ -15994,17 +16042,17 @@ var workspaceBackend = createMemoryWorkspaceBackend({
15994
16042
  import { jsx as jsx78, jsxs as jsxs57 } from "react/jsx-runtime";
15995
16043
  var inputRegistry = createInputRegistry();
15996
16044
  registerEntries(inputRegistry);
15997
- function WorkspaceLayout({ onShare, onPlay }) {
16045
+ function WorkspaceLayout({ onShare, onPlay, menu }) {
15998
16046
  const canvas = useCanvas22();
15999
16047
  const ws = useWorkspace16();
16000
16048
  const errors = useErrors();
16001
16049
  const bottomPanel = useBottomConsolePanel();
16002
- const [draggingServiceId, setDraggingServiceId] = useState34(null);
16050
+ const [draggingServiceId, setDraggingServiceId] = useState35(null);
16003
16051
  const serviceSummary = useMemo35(() => buildServiceSummaries(canvas, ws), [canvas.props, canvas.selectionInfo, canvas.activeId, ws.services.data]);
16004
16052
  return /* @__PURE__ */ jsx78(FallbackQuickAddProvider, { children: /* @__PURE__ */ jsx78(NodeContextMenuProvider, { children: /* @__PURE__ */ jsx78(FallbackEditorModalProvider, { children: /* @__PURE__ */ jsxs57("div", { className: "relative flex h-screen flex-col overflow-hidden *:font-display", children: [
16005
16053
  /* @__PURE__ */ jsx78("div", { className: "pointer-events-none absolute top-4 left-1/2 z-30 w-full max-w-2xl -translate-x-1/2 px-4", children: /* @__PURE__ */ jsx78("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx78(WorkspaceBootStatusSurface, { boot: ws.boot }) }) }),
16006
16054
  /* @__PURE__ */ jsxs57("div", { className: "flex grow overflow-hidden", children: [
16007
- /* @__PURE__ */ jsx78(left_default, {}),
16055
+ /* @__PURE__ */ jsx78(left_default, { menu }),
16008
16056
  /* @__PURE__ */ jsx78(
16009
16057
  CanvasPanel,
16010
16058
  {
@@ -16028,11 +16076,11 @@ function WorkspaceLayout({ onShare, onPlay }) {
16028
16076
  ) })
16029
16077
  ] }) }) }) });
16030
16078
  }
16031
- function ServiceBuilder({ backend, actor, onShare, onPlay }) {
16032
- return /* @__PURE__ */ jsx78(InputsProvider, { initialRegistry: inputRegistry, children: /* @__PURE__ */ jsx78(Workspace, { backend, actor, children: () => /* @__PURE__ */ jsx78(WorkspaceLayout, { onShare, onPlay }) }) });
16079
+ function ServiceBuilder({ backend, actor, onShare, onPlay, menu }) {
16080
+ return /* @__PURE__ */ jsx78(InputsProvider, { initialRegistry: inputRegistry, children: /* @__PURE__ */ jsx78(Workspace, { backend, actor, children: () => /* @__PURE__ */ jsx78(WorkspaceLayout, { onShare, onPlay, menu }) }) });
16033
16081
  }
16034
- function ServiceBuilderWorkspace({ onShare, onPlay }) {
16035
- return /* @__PURE__ */ jsx78(ServiceBuilder, { backend: workspaceBackend, actor: workspaceActor, onShare, onPlay });
16082
+ function ServiceBuilderWorkspace({ onShare, onPlay, menu }) {
16083
+ return /* @__PURE__ */ jsx78(ServiceBuilder, { backend: workspaceBackend, actor: workspaceActor, onShare, onPlay, menu });
16036
16084
  }
16037
16085
  export {
16038
16086
  ServiceBuilder,