@timeax/service-builder 0.1.6 → 0.1.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
@@ -4750,7 +4750,8 @@ import { LuTags as LuTags2 } from "react-icons/lu";
4750
4750
  import { MdOutlineRadioButtonChecked as MdOutlineRadioButtonChecked2 } from "react-icons/md";
4751
4751
  import { RxInput as RxInput2 } from "react-icons/rx";
4752
4752
  import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
4753
- var ACTIVE_NODE_RING_CLASS = "ring-2 ring-sky-300 shadow-lg shadow-sky-300/20 dark:ring-sky-400";
4753
+ var SELECTED_NODE_RING_CLASS = "ring-2 ring-sky-300 shadow-lg shadow-sky-300/20 dark:ring-sky-400";
4754
+ var ACTIVE_NODE_OUTLINE_CLASS = "outline-2 outline-solid outline-emerald-500 dark:outline-emerald-400";
4754
4755
  var HIGHLIGHT_NODE_OUTLINE_CLASS = "outline-2 outline-solid outline-amber-300 dark:outline-amber-200";
4755
4756
  function NodeShell({
4756
4757
  label,
@@ -4782,7 +4783,7 @@ function NodeShell({
4782
4783
  isManualHighlighted ? "manual-highlighted" : "",
4783
4784
  focusDimLevel && focusDimLevel !== "none" ? `dim-${focusDimLevel}` : ""
4784
4785
  ].filter(Boolean).join(" "),
4785
- className: "group relative min-w-44 rounded-lg bg-white p-3 ring-1 ring-slate-200 shadow-[0_4px_12px_rgba(0,0,0,0.05)] transition-all duration-200 dark:bg-slate-900 dark:ring-slate-700 " + (selected ? `${ACTIVE_NODE_RING_CLASS} ` : "hover:shadow-lg ") + (isActiveNode ? `${ACTIVE_NODE_RING_CLASS} ` : "") + (isCurrentTag ? "ring-2 ring-emerald-500 bg-emerald-50/70 shadow-lg shadow-emerald-500/25 dark:bg-emerald-500/10 " : "") + (isVisibleGroupField ? "ring-2 ring-emerald-300 bg-emerald-50/35 dark:bg-emerald-500/5 " : "") + (isRelatedTag ? "ring-1 ring-teal-300 bg-teal-50/25 dark:bg-teal-500/8 " : "") + (isManualHighlighted ? `${HIGHLIGHT_NODE_OUTLINE_CLASS} ` : "") + (draggingService && canAssignService2 ? "border border-dashed border-emerald-400 " : "") + (!canAssignService2 && draggingService ? "opacity-70 " : "") + dimClass,
4786
+ className: "group relative min-w-44 rounded-lg bg-white p-3 ring-1 ring-slate-200 shadow-[0_4px_12px_rgba(0,0,0,0.05)] transition-all duration-200 dark:bg-slate-900 dark:ring-slate-700 " + (selected ? `${SELECTED_NODE_RING_CLASS} ` : "hover:shadow-lg ") + (isActiveNode ? `${ACTIVE_NODE_OUTLINE_CLASS} ` : "") + (isCurrentTag ? "ring-2 ring-emerald-500 bg-emerald-50/70 shadow-lg shadow-emerald-500/25 dark:bg-emerald-500/10 " : "") + (isVisibleGroupField ? "ring-2 ring-emerald-300 bg-emerald-50/35 dark:bg-emerald-500/5 " : "") + (isRelatedTag ? "ring-1 ring-teal-300 bg-teal-50/25 dark:bg-teal-500/8 " : "") + (isManualHighlighted ? `${HIGHLIGHT_NODE_OUTLINE_CLASS} ` : "") + (draggingService && canAssignService2 ? "border border-dashed border-emerald-400 " : "") + (!canAssignService2 && draggingService ? "opacity-70 " : "") + dimClass,
4786
4787
  onDragOver: (event) => {
4787
4788
  if (!canAcceptDropPayload?.(event.dataTransfer)) return;
4788
4789
  event.preventDefault();
@@ -4879,7 +4880,7 @@ function OptionNode(props) {
4879
4880
  props.data.isManualHighlighted ? "manual-highlighted" : "",
4880
4881
  props.data.focusDimLevel && props.data.focusDimLevel !== "none" ? `dim-${props.data.focusDimLevel}` : ""
4881
4882
  ].filter(Boolean).join(" "),
4882
- className: "relative rounded-full border px-4 py-1.5 text-sm bg-white text-slate-800 transition dark:bg-slate-900 dark:text-slate-200 " + (props.selected ? "border-sky-300 bg-sky-50 text-sky-700 dark:bg-sky-500/15 dark:border-sky-400 " : "border-slate-300 dark:border-slate-700 ") + (props.data.isActiveNode ? `${ACTIVE_NODE_RING_CLASS} ` : "") + (props.data.isCurrentTag ? "ring-2 ring-emerald-500 bg-emerald-50/70 dark:bg-emerald-500/10 " : "") + (props.data.isVisibleGroupField ? "ring-2 ring-emerald-300 bg-emerald-50/35 dark:bg-emerald-500/5 " : "") + (props.data.isRelatedTag ? "ring-1 ring-teal-300 bg-teal-50/25 dark:bg-teal-500/8 " : "") + (props.data.isManualHighlighted ? `${HIGHLIGHT_NODE_OUTLINE_CLASS} ` : "") + (props.data.focusDimLevel === "soft" ? "opacity-80 " : props.data.focusDimLevel === "medium" ? "opacity-[0.55] " : props.data.focusDimLevel === "strong" ? "opacity-35 " : ""),
4883
+ className: "relative rounded-full border px-4 py-1.5 text-sm bg-white text-slate-800 transition dark:bg-slate-900 dark:text-slate-200 " + (props.selected ? `border-sky-300 bg-sky-50 text-sky-700 dark:bg-sky-500/15 dark:border-sky-400 ${SELECTED_NODE_RING_CLASS} ` : "border-slate-300 dark:border-slate-700 ") + (props.data.isActiveNode ? `${ACTIVE_NODE_OUTLINE_CLASS} ` : "") + (props.data.isCurrentTag ? "ring-2 ring-emerald-500 bg-emerald-50/70 dark:bg-emerald-500/10 " : "") + (props.data.isVisibleGroupField ? "ring-2 ring-emerald-300 bg-emerald-50/35 dark:bg-emerald-500/5 " : "") + (props.data.isRelatedTag ? "ring-1 ring-teal-300 bg-teal-50/25 dark:bg-teal-500/8 " : "") + (props.data.isManualHighlighted ? `${HIGHLIGHT_NODE_OUTLINE_CLASS} ` : "") + (props.data.focusDimLevel === "soft" ? "opacity-80 " : props.data.focusDimLevel === "medium" ? "opacity-[0.55] " : props.data.focusDimLevel === "strong" ? "opacity-35 " : ""),
4883
4884
  onDragOver: (event) => {
4884
4885
  if (!props.data.canAcceptDropPayload?.(event.dataTransfer)) return;
4885
4886
  event.preventDefault();
@@ -4909,7 +4910,7 @@ function CommentNode(props) {
4909
4910
  return /* @__PURE__ */ jsxs12(
4910
4911
  "div",
4911
4912
  {
4912
- className: "h-48 w-64 rounded-lg border border-[#E0E0E0] bg-[#FEFBEA] shadow-md transition-all hover:shadow-lg dark:border-[#555] dark:bg-[#4a4a38] " + (props.selected ? `${ACTIVE_NODE_RING_CLASS} ` : ""),
4913
+ className: "h-48 w-64 rounded-lg border border-[#E0E0E0] bg-[#FEFBEA] shadow-md transition-all hover:shadow-lg dark:border-[#555] dark:bg-[#4a4a38] " + (props.selected ? `${SELECTED_NODE_RING_CLASS} ` : ""),
4913
4914
  children: [
4914
4915
  /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 border-b border-[#E0E0E0]/70 px-3 py-2 text-xs font-medium text-slate-600 dark:border-[#555] dark:text-slate-300", children: [
4915
4916
  /* @__PURE__ */ jsx16(BsChatSquareQuote2, {}),
@@ -14395,9 +14396,14 @@ var wireframe_tags_widget_default = WireframeTagsWidget;
14395
14396
  // src/panels/right/tabs/wireframe.tsx
14396
14397
  import { useOrderFlow, Wrapper } from "@timeax/digital-service-engine/react";
14397
14398
  import { useCanvas as useCanvas16, useWorkspace as useWorkspace14 } from "@timeax/digital-service-engine/workspace";
14398
- import { useCallback as useCallback19, useMemo as useMemo33 } from "react";
14399
+ import { useCallback as useCallback19, useMemo as useMemo33, useState as useState33 } from "react";
14400
+ import { BsChevronDown as BsChevronDown2 } from "react-icons/bs";
14399
14401
  import { jsx as jsx71, jsxs as jsxs51 } from "react/jsx-runtime";
14400
14402
  var CHECKBOX_SINGLE_EXTRA_PROPS = Object.freeze({ single: true });
14403
+ function formatMetricNumber(value) {
14404
+ if (typeof value !== "number" || !Number.isFinite(value)) return "--";
14405
+ return new Intl.NumberFormat("en-US", { maximumFractionDigits: 4 }).format(value);
14406
+ }
14401
14407
  function Wireframe() {
14402
14408
  const canvas = useCanvas16();
14403
14409
  const ws = useWorkspace14();
@@ -14406,7 +14412,109 @@ function Wireframe() {
14406
14412
  const previewFields = useMemo33(() => getVisiblePreviewFields(canvas, currentTag?.id), [canvas.props, canvas.selectionInfo, canvas.activeId]);
14407
14413
  const selectedOptionsCount = canvas.selectionInfo.optionIds.length;
14408
14414
  const flow = useOrderFlow();
14409
- const footerLine = currentTag ? `Tag: ${currentTag.raw.label} \xB7 Visible fields: ${previewFields.length} \xB7 Selected options: ${selectedOptionsCount}` : `No active tag \xB7 Visible fields: 0 \xB7 Selected options: ${selectedOptionsCount}`;
14415
+ const [isFooterOpen, setIsFooterOpen] = useState33(true);
14416
+ const footerSummary = useMemo33(() => {
14417
+ const minText = formatMetricNumber(flow.min);
14418
+ const maxText = formatMetricNumber(flow.max);
14419
+ const rangeText = minText === "--" && maxText === "--" ? "--" : `${minText} - ${maxText}`;
14420
+ return [
14421
+ { label: "Tag", value: currentTag?.raw.label ?? "No active tag" },
14422
+ { label: "Visible fields", value: String(previewFields.length) },
14423
+ { label: "Selected options", value: String(selectedOptionsCount) },
14424
+ { label: "Quantity", value: formatMetricNumber(flow.quantityPreview) },
14425
+ { label: "Min/Max", value: rangeText },
14426
+ { label: "Services", value: String(flow.services.length), detailsKind: "services" },
14427
+ { label: "Base", value: formatMetricNumber(flow.pricingPreview?.base), detailsKind: "pricing" },
14428
+ { label: "Utilities", value: formatMetricNumber(flow.pricingPreview?.utilities), detailsKind: "pricing" },
14429
+ { label: "Total", value: formatMetricNumber(flow.pricingPreview?.total), detailsKind: "pricing" },
14430
+ { label: "Utility lines", value: String(flow.pricingPreview?.utilityBreakdown?.length ?? 0), detailsKind: "utility_lines" }
14431
+ ];
14432
+ }, [
14433
+ currentTag?.raw.label,
14434
+ flow.max,
14435
+ flow.min,
14436
+ flow.pricingPreview?.base,
14437
+ flow.pricingPreview?.total,
14438
+ flow.pricingPreview?.utilities,
14439
+ flow.pricingPreview?.utilityBreakdown?.length,
14440
+ flow.quantityPreview,
14441
+ flow.services.length,
14442
+ previewFields.length,
14443
+ selectedOptionsCount
14444
+ ]);
14445
+ const serviceDetails = useMemo33(() => {
14446
+ const servicesMap = ws.services.data ?? {};
14447
+ return flow.services.map((serviceId) => {
14448
+ const service = servicesMap[String(serviceId)];
14449
+ return {
14450
+ id: serviceId,
14451
+ name: service?.name ?? `Service ${String(serviceId)}`,
14452
+ rate: service?.rate,
14453
+ min: service?.min,
14454
+ max: service?.max
14455
+ };
14456
+ });
14457
+ }, [flow.services, ws.services.data]);
14458
+ const renderPillDetails = useCallback19(
14459
+ (kind) => {
14460
+ if (kind === "services") {
14461
+ return /* @__PURE__ */ jsxs51("div", { className: "space-y-2", children: [
14462
+ /* @__PURE__ */ jsx71("p", { className: "text-xs font-semibold text-slate-700 dark:text-slate-200", children: "Visible Services" }),
14463
+ serviceDetails.length ? /* @__PURE__ */ jsx71("div", { className: "max-h-56 space-y-2 overflow-auto pr-1", children: serviceDetails.map((service) => /* @__PURE__ */ jsxs51("div", { className: "rounded-md border border-slate-200 bg-slate-50 px-2 py-1.5 text-xs dark:border-slate-700 dark:bg-slate-900", children: [
14464
+ /* @__PURE__ */ jsx71("p", { className: "font-medium text-slate-700 dark:text-slate-200", children: service.name }),
14465
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14466
+ "ID: ",
14467
+ String(service.id)
14468
+ ] }),
14469
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14470
+ "Rate: ",
14471
+ formatMetricNumber(service.rate),
14472
+ " \xB7 Min/Max: ",
14473
+ formatMetricNumber(service.min),
14474
+ " - ",
14475
+ formatMetricNumber(service.max)
14476
+ ] })
14477
+ ] }, String(service.id))) }) : /* @__PURE__ */ jsx71("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: "No services are currently active for this selection." })
14478
+ ] });
14479
+ }
14480
+ if (kind === "utility_lines") {
14481
+ const lines = flow.pricingPreview?.utilityBreakdown ?? [];
14482
+ return /* @__PURE__ */ jsxs51("div", { className: "space-y-2", children: [
14483
+ /* @__PURE__ */ jsx71("p", { className: "text-xs font-semibold text-slate-700 dark:text-slate-200", children: "Utility Breakdown" }),
14484
+ lines.length ? /* @__PURE__ */ jsx71("div", { className: "max-h-56 space-y-2 overflow-auto pr-1", children: lines.map((line, index) => /* @__PURE__ */ jsxs51("div", { className: "rounded-md border border-slate-200 bg-slate-50 px-2 py-1.5 text-xs dark:border-slate-700 dark:bg-slate-900", children: [
14485
+ /* @__PURE__ */ jsxs51("p", { className: "font-medium text-slate-700 dark:text-slate-200", children: [
14486
+ "Node: ",
14487
+ line.nodeId
14488
+ ] }),
14489
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14490
+ "Mode: ",
14491
+ line.mode
14492
+ ] }),
14493
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14494
+ "Amount: ",
14495
+ formatMetricNumber(line.amount)
14496
+ ] })
14497
+ ] }, `${line.nodeId}:${index}`)) }) : /* @__PURE__ */ jsx71("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: "No utility line items in the current preview." })
14498
+ ] });
14499
+ }
14500
+ return /* @__PURE__ */ jsxs51("div", { className: "space-y-1 text-xs", children: [
14501
+ /* @__PURE__ */ jsx71("p", { className: "font-semibold text-slate-700 dark:text-slate-200", children: "Pricing Summary" }),
14502
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14503
+ "Base: ",
14504
+ formatMetricNumber(flow.pricingPreview?.base)
14505
+ ] }),
14506
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14507
+ "Utilities: ",
14508
+ formatMetricNumber(flow.pricingPreview?.utilities)
14509
+ ] }),
14510
+ /* @__PURE__ */ jsxs51("p", { className: "text-slate-500 dark:text-slate-400", children: [
14511
+ "Total: ",
14512
+ formatMetricNumber(flow.pricingPreview?.total)
14513
+ ] })
14514
+ ] });
14515
+ },
14516
+ [flow.pricingPreview?.base, flow.pricingPreview?.total, flow.pricingPreview?.utilities, flow.pricingPreview?.utilityBreakdown, serviceDetails]
14517
+ );
14410
14518
  const { visibleTag, parents, children, visibleFields } = useMemo33(() => {
14411
14519
  const result = canvas.api.selection.visibleGroup();
14412
14520
  const notices = canvas.api.builder.getProps().notices;
@@ -14552,7 +14660,44 @@ function Wireframe() {
14552
14660
  }
14553
14661
  ) })
14554
14662
  ] }) }) }),
14555
- /* @__PURE__ */ jsx71("div", { className: "border-t border-slate-200 px-4 py-2 text-xs text-slate-600 dark:border-slate-800 dark:text-slate-300", children: /* @__PURE__ */ jsx71("p", { className: "truncate", children: footerLine }) })
14663
+ /* @__PURE__ */ jsxs51("div", { className: "mt-auto border-t border-slate-200 px-4 py-2 text-xs text-slate-600 dark:border-slate-800 dark:text-slate-300", children: [
14664
+ /* @__PURE__ */ jsxs51(
14665
+ "button",
14666
+ {
14667
+ type: "button",
14668
+ className: "flex w-full items-center justify-between rounded-md px-1 py-1 text-left hover:bg-slate-100/70 dark:hover:bg-slate-900/80",
14669
+ onClick: () => setIsFooterOpen((prev) => !prev),
14670
+ "aria-expanded": isFooterOpen,
14671
+ "aria-controls": "wireframe-footer-summary",
14672
+ children: [
14673
+ /* @__PURE__ */ jsx71("span", { className: "font-medium", children: "Order preview summary" }),
14674
+ /* @__PURE__ */ jsx71(BsChevronDown2, { className: `transition-transform ${isFooterOpen ? "rotate-180" : "rotate-0"}` })
14675
+ ]
14676
+ }
14677
+ ),
14678
+ isFooterOpen ? /* @__PURE__ */ jsx71("div", { id: "wireframe-footer-summary", className: "mt-2 flex flex-wrap gap-2", children: footerSummary.map((item) => {
14679
+ const chip = /* @__PURE__ */ jsxs51("span", { className: "inline-flex items-center gap-1 rounded-md border border-slate-200 bg-slate-50 px-2 py-1 dark:border-slate-700 dark:bg-slate-900", children: [
14680
+ /* @__PURE__ */ jsxs51("span", { className: "text-slate-500 dark:text-slate-400", children: [
14681
+ item.label,
14682
+ ":"
14683
+ ] }),
14684
+ /* @__PURE__ */ jsx71("span", { className: "font-medium text-slate-700 dark:text-slate-200", children: item.value })
14685
+ ] });
14686
+ if (!item.detailsKind) return /* @__PURE__ */ jsx71("div", { children: chip }, item.label);
14687
+ return /* @__PURE__ */ jsxs51(Popover, { children: [
14688
+ /* @__PURE__ */ jsx71(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx71(
14689
+ "button",
14690
+ {
14691
+ type: "button",
14692
+ className: "rounded-md transition-transform hover:scale-[1.01] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500/50",
14693
+ "aria-label": `${item.label} details`,
14694
+ children: chip
14695
+ }
14696
+ ) }),
14697
+ /* @__PURE__ */ jsx71(PopoverContent, { align: "start", side: "top", sideOffset: 8, collisionPadding: 12, className: "w-80 rounded-xl p-3", children: renderPillDetails(item.detailsKind) })
14698
+ ] }, item.label);
14699
+ }) }) : null
14700
+ ] })
14556
14701
  ] });
14557
14702
  }
14558
14703
  var wireframe_default = Wireframe;
@@ -14595,17 +14740,1172 @@ var RightPanel = ({ onShare, onPlay }) => {
14595
14740
  };
14596
14741
  var right_default = RightPanel;
14597
14742
 
14743
+ // src/components/ui/resizable.tsx
14744
+ import { GripVertical } from "lucide-react";
14745
+ import "react";
14746
+ import { Group as Group2, Panel as Panel3, Separator as Separator3 } from "react-resizable-panels";
14747
+ import { jsx as jsx73 } from "react/jsx-runtime";
14748
+ function ResizablePanelGroup({
14749
+ className,
14750
+ direction = "horizontal",
14751
+ ...props
14752
+ }) {
14753
+ return /* @__PURE__ */ jsx73(Group2, { className: cn("flex h-full w-full data-[group-orientation=vertical]:flex-col", className), orientation: direction, ...props });
14754
+ }
14755
+ function ResizablePanel({
14756
+ className,
14757
+ ...props
14758
+ }) {
14759
+ return /* @__PURE__ */ jsx73(Panel3, { className: cn("min-h-0 min-w-0", className), ...props });
14760
+ }
14761
+ function ResizableHandle({
14762
+ withHandle,
14763
+ className,
14764
+ ...props
14765
+ }) {
14766
+ return /* @__PURE__ */ jsx73(
14767
+ Separator3,
14768
+ {
14769
+ className: cn(
14770
+ "relative flex w-3 shrink-0 items-center justify-center bg-transparent outline-none transition-colors after:absolute after:inset-y-3 after:left-1/2 after:w-px after:-translate-x-1/2 after:rounded-full after:bg-slate-200 dark:after:bg-slate-800",
14771
+ "hover:after:bg-slate-300 dark:hover:after:bg-slate-700",
14772
+ className
14773
+ ),
14774
+ ...props,
14775
+ children: withHandle ? /* @__PURE__ */ jsx73("div", { className: "z-10 flex h-10 w-3 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-400 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-500", children: /* @__PURE__ */ jsx73(GripVertical, { className: "h-3.5 w-3.5" }) }) : null
14776
+ }
14777
+ );
14778
+ }
14779
+
14780
+ // src/workspace/fallback-editor/native-fallback-editor.tsx
14781
+ import { FallbackEditorProvider, useActiveFallbackRegistrations as useActiveFallbackRegistrations4, useFallbackEditor as useFallbackEditor6, usePrimaryServiceList as usePrimaryServiceList3 } from "@timeax/digital-service-engine/react";
14782
+ import { useMemo as useMemo37 } from "react";
14783
+
14784
+ // src/workspace/fallback-editor/fallback-details-panel.tsx
14785
+ import { useActiveFallbackRegistrations, useFallbackEditor, usePrimaryServiceList } from "@timeax/digital-service-engine/react";
14786
+ import { useMemo as useMemo34 } from "react";
14787
+
14788
+ // src/workspace/fallback-editor/shared.tsx
14789
+ import { X } from "lucide-react";
14790
+ import { jsx as jsx74, jsxs as jsxs53 } from "react/jsx-runtime";
14791
+ var surfaceClassName = "rounded-md border border-slate-200/80 bg-white/95 shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-950/85";
14792
+ function SectionCard({
14793
+ className,
14794
+ children
14795
+ }) {
14796
+ return /* @__PURE__ */ jsx74("section", { className: cn(surfaceClassName, className), children });
14797
+ }
14798
+ function SectionHeader2({
14799
+ title,
14800
+ description,
14801
+ action,
14802
+ className
14803
+ }) {
14804
+ return /* @__PURE__ */ jsxs53("div", { className: cn("flex items-start justify-between gap-3", className), children: [
14805
+ /* @__PURE__ */ jsxs53("div", { className: "min-w-0", children: [
14806
+ /* @__PURE__ */ jsx74("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
14807
+ description ? /* @__PURE__ */ jsx74("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: description }) : null
14808
+ ] }),
14809
+ action ? /* @__PURE__ */ jsx74("div", { className: "shrink-0", children: action }) : null
14810
+ ] });
14811
+ }
14812
+ function EmptyState2({
14813
+ title,
14814
+ description,
14815
+ className
14816
+ }) {
14817
+ return /* @__PURE__ */ jsxs53(
14818
+ "div",
14819
+ {
14820
+ className: cn(
14821
+ "flex min-h-40 flex-col items-center justify-center rounded-md border border-dashed border-slate-300 bg-slate-50/80 px-5 py-8 text-center dark:border-slate-700 dark:bg-slate-900/40",
14822
+ className
14823
+ ),
14824
+ children: [
14825
+ /* @__PURE__ */ jsx74("h4", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
14826
+ /* @__PURE__ */ jsx74("p", { className: "mt-2 max-w-sm text-sm text-slate-500 dark:text-slate-400", children: description })
14827
+ ]
14828
+ }
14829
+ );
14830
+ }
14831
+ function DetailRow({
14832
+ label,
14833
+ value,
14834
+ className
14835
+ }) {
14836
+ return /* @__PURE__ */ jsxs53("div", { className: cn("flex items-start justify-between gap-3 rounded-md bg-slate-50 px-3 py-2 dark:bg-slate-900/70", className), children: [
14837
+ /* @__PURE__ */ jsx74("span", { className: "text-sm text-slate-500 dark:text-slate-400", children: label }),
14838
+ /* @__PURE__ */ jsx74("span", { className: "text-right text-sm font-medium text-slate-900 dark:text-slate-100", children: value })
14839
+ ] });
14840
+ }
14841
+ function ToneBadge({
14842
+ label,
14843
+ tone = "neutral",
14844
+ className
14845
+ }) {
14846
+ const palette = tone === "info" ? "border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-500/30 dark:bg-sky-500/10 dark:text-sky-200" : tone === "success" ? "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-500/30 dark:bg-emerald-500/10 dark:text-emerald-200" : tone === "warning" ? "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200" : tone === "danger" ? "border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-200" : "border-slate-200 bg-white text-slate-600 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-300";
14847
+ return /* @__PURE__ */ jsx74("span", { className: cn("inline-flex rounded-md border px-2.5 py-1 text-[11px] font-medium", palette, className), children: label });
14848
+ }
14849
+ function ModalShell({
14850
+ open,
14851
+ title,
14852
+ description,
14853
+ onClose,
14854
+ children,
14855
+ footer,
14856
+ size = "default"
14857
+ }) {
14858
+ if (!open) return null;
14859
+ return /* @__PURE__ */ jsx74(
14860
+ "div",
14861
+ {
14862
+ className: "fixed inset-0 z-[60] flex items-center justify-center bg-slate-950/65 p-4 backdrop-blur-sm",
14863
+ onMouseDown: (event) => {
14864
+ if (event.target === event.currentTarget) onClose();
14865
+ },
14866
+ children: /* @__PURE__ */ jsxs53(
14867
+ "div",
14868
+ {
14869
+ className: cn(
14870
+ "flex max-h-[85vh] w-full flex-col overflow-hidden rounded-md border border-slate-200 bg-white shadow-2xl dark:border-slate-800 dark:bg-slate-950",
14871
+ size === "wide" ? "max-w-4xl" : "max-w-xl"
14872
+ ),
14873
+ onMouseDown: (event) => event.stopPropagation(),
14874
+ children: [
14875
+ /* @__PURE__ */ jsxs53("div", { className: "flex items-start justify-between gap-4 border-b border-slate-200 px-6 py-4 dark:border-slate-800", children: [
14876
+ /* @__PURE__ */ jsxs53("div", { className: "min-w-0", children: [
14877
+ /* @__PURE__ */ jsx74("h3", { className: "text-base font-semibold text-slate-900 dark:text-slate-100", children: title }),
14878
+ description ? /* @__PURE__ */ jsx74("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: description }) : null
14879
+ ] }),
14880
+ /* @__PURE__ */ jsx74(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: onClose, className: "rounded-md", children: /* @__PURE__ */ jsx74(X, { className: "size-4" }) })
14881
+ ] }),
14882
+ /* @__PURE__ */ jsx74(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx74("div", { className: "p-6", children }) }),
14883
+ footer ? /* @__PURE__ */ jsx74("div", { className: "border-t border-slate-200 px-6 py-4 dark:border-slate-800", children: footer }) : null
14884
+ ]
14885
+ }
14886
+ )
14887
+ }
14888
+ );
14889
+ }
14890
+
14891
+ // src/workspace/fallback-editor/fallback-details-panel.tsx
14892
+ import { jsx as jsx75, jsxs as jsxs54 } from "react/jsx-runtime";
14893
+ function FallbackDetailsPanel() {
14894
+ const { activeServiceId, state, settings, check } = useFallbackEditor();
14895
+ const services2 = usePrimaryServiceList();
14896
+ const registrations = useActiveFallbackRegistrations();
14897
+ const service = useMemo34(() => services2.find((entry) => String(entry.id) === String(activeServiceId)), [services2, activeServiceId]);
14898
+ const diagnostics = useMemo34(() => {
14899
+ return registrations.flatMap((registration) => {
14900
+ const context = toScopeRef(registration);
14901
+ const result = check(context, registration.services);
14902
+ const rejected = result.rejected.map((item) => ({
14903
+ scope: registration.scope,
14904
+ scopeId: registration.scopeId,
14905
+ candidate: item.candidate,
14906
+ reasons: item.reasons
14907
+ }));
14908
+ if (result.warnings.length === 0 && rejected.length === 0) {
14909
+ return [
14910
+ {
14911
+ scope: registration.scope,
14912
+ scopeId: registration.scopeId,
14913
+ candidate: null,
14914
+ reasons: ["valid"]
14915
+ }
14916
+ ];
14917
+ }
14918
+ return [...rejected, ...result.warnings.map((reason) => ({ scope: registration.scope, scopeId: registration.scopeId, candidate: null, reasons: [reason] }))];
14919
+ });
14920
+ }, [check, registrations]);
14921
+ return /* @__PURE__ */ jsx75(ScrollArea, { className: "min-h-0 flex-1 overflow-y-auto pr-1", "data-testid": "fallback-editor-details-scroll", children: /* @__PURE__ */ jsxs54("aside", { className: "flex flex-col gap-4", children: [
14922
+ /* @__PURE__ */ jsxs54(SectionCard, { className: "p-4", children: [
14923
+ /* @__PURE__ */ jsx75(SectionHeader2, { title: "Primary service", description: "Current editor target and change state." }),
14924
+ /* @__PURE__ */ jsxs54("div", { className: "mt-4 space-y-2", children: [
14925
+ /* @__PURE__ */ jsx75(
14926
+ DetailRow,
14927
+ {
14928
+ label: "Service",
14929
+ value: service ? `${service.name ?? "Unnamed"} (#${String(service.id)})` : "No service selected"
14930
+ }
14931
+ ),
14932
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Platform", value: service?.platform ?? "-" }),
14933
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Rate", value: typeof service?.rate === "number" ? String(service.rate) : "-" }),
14934
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Changed", value: state.changed ? "Yes" : "No" })
14935
+ ] })
14936
+ ] }),
14937
+ /* @__PURE__ */ jsxs54(SectionCard, { className: "p-4", children: [
14938
+ /* @__PURE__ */ jsx75(SectionHeader2, { title: "Policy", description: "Effective fallback rules applied by the provider." }),
14939
+ /* @__PURE__ */ jsxs54("div", { className: "mt-4 space-y-2", children: [
14940
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Constraint fit", value: settings.requireConstraintFit ? "Enabled" : "Disabled" }),
14941
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Rate policy", value: formatRatePolicy(settings) }),
14942
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Strategy", value: settings.selectionStrategy ?? "priority" }),
14943
+ /* @__PURE__ */ jsx75(DetailRow, { label: "Mode", value: settings.mode ?? "strict" })
14944
+ ] })
14945
+ ] }),
14946
+ /* @__PURE__ */ jsxs54(SectionCard, { className: "flex min-h-0 flex-col overflow-hidden", children: [
14947
+ /* @__PURE__ */ jsx75("div", { className: "border-b border-slate-200 px-4 py-4 dark:border-slate-800", children: /* @__PURE__ */ jsx75(SectionHeader2, { title: "Diagnostics", description: "Live validation hints for the selected service registrations." }) }),
14948
+ /* @__PURE__ */ jsx75(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx75("div", { className: "space-y-2 p-3", children: diagnostics.length ? diagnostics.map((entry, index) => {
14949
+ const tone = entry.reasons[0] === "valid" ? "success" : entry.reasons.includes("rate_violation") || entry.reasons.includes("constraint_mismatch") ? "danger" : "warning";
14950
+ return /* @__PURE__ */ jsx75(
14951
+ "div",
14952
+ {
14953
+ className: "rounded-md border border-slate-200 bg-slate-50/80 p-3 dark:border-slate-800 dark:bg-slate-900/60",
14954
+ children: /* @__PURE__ */ jsxs54("div", { className: "flex flex-wrap items-center gap-2", children: [
14955
+ /* @__PURE__ */ jsx75(ToneBadge, { label: entry.scope === "global" ? "Global" : `Node ${entry.scopeId ?? ""}`.trim() }),
14956
+ entry.candidate != null ? /* @__PURE__ */ jsx75(ToneBadge, { label: `Candidate #${String(entry.candidate)}`, tone: "info" }) : null,
14957
+ /* @__PURE__ */ jsx75(ToneBadge, { label: entry.reasons.join(", "), tone })
14958
+ ] })
14959
+ },
14960
+ `${entry.scope}:${String(entry.scopeId ?? "global")}:${String(entry.candidate ?? "none")}:${index}`
14961
+ );
14962
+ }) : /* @__PURE__ */ jsx75("div", { className: "rounded-md border border-dashed border-slate-300 bg-slate-50/80 px-4 py-8 text-center text-sm text-slate-500 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-400", children: "No registrations selected yet." }) }) })
14963
+ ] }),
14964
+ /* @__PURE__ */ jsxs54(SectionCard, { className: "flex min-h-0 flex-col overflow-hidden", children: [
14965
+ /* @__PURE__ */ jsx75("div", { className: "border-b border-slate-200 px-4 py-4 dark:border-slate-800", children: /* @__PURE__ */ jsx75(SectionHeader2, { title: "Current payload", description: "Serialized fallback state from the provider." }) }),
14966
+ /* @__PURE__ */ jsx75(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx75("pre", { className: "p-4 text-xs text-slate-700 dark:text-slate-200", children: JSON.stringify(state.current, null, 2) }) })
14967
+ ] })
14968
+ ] }) });
14969
+ }
14970
+ function toScopeRef(registration) {
14971
+ if (registration.scope === "global") {
14972
+ return {
14973
+ scope: "global",
14974
+ primary: registration.primary
14975
+ };
14976
+ }
14977
+ return {
14978
+ scope: "node",
14979
+ nodeId: registration.scopeId
14980
+ };
14981
+ }
14982
+ function formatRatePolicy(settings) {
14983
+ if (settings.ratePolicy?.kind === "eq_primary") return "eq_primary";
14984
+ if (settings.ratePolicy?.kind === "within_pct") return `within_pct (${settings.ratePolicy.pct}%)`;
14985
+ if (settings.ratePolicy?.kind === "at_least_pct_lower") return `at_least_pct_lower (${settings.ratePolicy.pct}%)`;
14986
+ if (settings.ratePolicy?.kind === "lte_primary") return `lte_primary (${settings.ratePolicy.pct}%)`;
14987
+ return "lte_primary (5%)";
14988
+ }
14989
+
14990
+ // src/workspace/fallback-editor/fallback-editor-header.tsx
14991
+ import { RotateCcw, Save, ShieldCheck } from "lucide-react";
14992
+ import { jsx as jsx76, jsxs as jsxs55 } from "react/jsx-runtime";
14993
+ function FallbackEditorHeader({
14994
+ activeServiceLabel,
14995
+ registrationCount,
14996
+ changed,
14997
+ onReset,
14998
+ onValidate,
14999
+ onSave,
15000
+ resetting = false,
15001
+ validating = false,
15002
+ saving = false
15003
+ }) {
15004
+ return /* @__PURE__ */ jsx76(SectionCard, { className: "px-5 py-4", children: /* @__PURE__ */ jsxs55("div", { className: "flex flex-col gap-4 xl:flex-row xl:items-center xl:justify-between", children: [
15005
+ /* @__PURE__ */ jsxs55("div", { className: "space-y-3", children: [
15006
+ /* @__PURE__ */ jsx76(
15007
+ SectionHeader2,
15008
+ {
15009
+ title: "Fallback editor",
15010
+ description: "Manage global and node-scoped fallback registrations with the workspace design system."
15011
+ }
15012
+ ),
15013
+ /* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: [
15014
+ /* @__PURE__ */ jsx76(ToneBadge, { label: activeServiceLabel ?? "No service selected", tone: "info" }),
15015
+ /* @__PURE__ */ jsx76(ToneBadge, { label: `${registrationCount} registration${registrationCount === 1 ? "" : "s"}` }),
15016
+ /* @__PURE__ */ jsx76(ToneBadge, { label: changed ? "Unsaved changes" : "Synced", tone: changed ? "warning" : "success" })
15017
+ ] })
15018
+ ] }),
15019
+ /* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-center gap-2", children: [
15020
+ /* @__PURE__ */ jsxs55(Button, { type: "button", variant: "outline", onClick: onReset, disabled: resetting, children: [
15021
+ /* @__PURE__ */ jsx76(RotateCcw, { className: "size-4" }),
15022
+ resetting ? "Resetting..." : "Reset"
15023
+ ] }),
15024
+ /* @__PURE__ */ jsxs55(Button, { type: "button", variant: "outline", onClick: onValidate, disabled: validating, children: [
15025
+ /* @__PURE__ */ jsx76(ShieldCheck, { className: "size-4" }),
15026
+ validating ? "Validating..." : "Validate"
15027
+ ] }),
15028
+ /* @__PURE__ */ jsx76(Separator2, { orientation: "vertical", className: "hidden h-8 xl:block" }),
15029
+ /* @__PURE__ */ jsxs55(Button, { type: "button", onClick: onSave, disabled: saving, children: [
15030
+ /* @__PURE__ */ jsx76(Save, { className: "size-4" }),
15031
+ saving ? "Saving..." : "Save changes"
15032
+ ] })
15033
+ ] })
15034
+ ] }) });
15035
+ }
15036
+
15037
+ // src/workspace/fallback-editor/fallback-registrations-panel.tsx
15038
+ import { useActiveFallbackRegistrations as useActiveFallbackRegistrations3, useEligibleServiceList as useEligibleServiceList2, useFallbackEditor as useFallbackEditor3 } from "@timeax/digital-service-engine/react";
15039
+ import { Plus, Trash2, X as X2 } from "lucide-react";
15040
+ import { useCallback as useCallback20, useState as useState35 } from "react";
15041
+
15042
+ // src/workspace/fallback-editor/fallback-dialogs.tsx
15043
+ import { InputField as InputField16 } from "@timeax/form-palette";
15044
+ import { useActiveFallbackRegistrations as useActiveFallbackRegistrations2, useEligibleServiceList, useFallbackEditor as useFallbackEditor2 } from "@timeax/digital-service-engine/react";
15045
+ import { Check, Search } from "lucide-react";
15046
+ import { useEffect as useEffect21, useMemo as useMemo35, useState as useState34 } from "react";
15047
+ import { jsx as jsx77, jsxs as jsxs56 } from "react/jsx-runtime";
15048
+ function FallbackAddRegistrationDialog({
15049
+ open,
15050
+ onClose,
15051
+ onSelect
15052
+ }) {
15053
+ const { activeServiceId, serviceProps, snapshot } = useFallbackEditor2();
15054
+ const registrations = useActiveFallbackRegistrations2();
15055
+ const [scope, setScope] = useState34("global");
15056
+ const [nodeId, setNodeId] = useState34("");
15057
+ const mode = useMemo35(() => {
15058
+ if (snapshot) return "snapshot";
15059
+ if (serviceProps) return "props";
15060
+ return "none";
15061
+ }, [snapshot, serviceProps]);
15062
+ useEffect21(() => {
15063
+ if (open) {
15064
+ setScope("global");
15065
+ setNodeId("");
15066
+ }
15067
+ }, [open]);
15068
+ const hasGlobal = useMemo35(() => registrations.some((registration) => registration.scope === "global"), [registrations]);
15069
+ const nodeTargets = useMemo35(() => {
15070
+ if (activeServiceId === void 0 || activeServiceId === null) return [];
15071
+ if (mode === "snapshot" && snapshot?.serviceMap) {
15072
+ const entries = [];
15073
+ for (const [id, primaryIds] of Object.entries(snapshot.serviceMap)) {
15074
+ const matchesPrimary = (primaryIds ?? []).some((serviceId) => String(serviceId) === String(activeServiceId));
15075
+ if (!matchesPrimary) continue;
15076
+ const meta = resolveNodeMeta(serviceProps, id);
15077
+ entries.push({
15078
+ id,
15079
+ kind: meta.kind,
15080
+ label: meta.label,
15081
+ serviceId: activeServiceId
15082
+ });
15083
+ }
15084
+ return dedupeNodeTargets(entries);
15085
+ }
15086
+ if (mode === "props" && serviceProps) {
15087
+ const entries = [];
15088
+ for (const tag of serviceProps.filters ?? []) {
15089
+ if (tag.service_id == null || String(tag.service_id) !== String(activeServiceId)) continue;
15090
+ entries.push({
15091
+ id: tag.id,
15092
+ kind: "tag",
15093
+ label: tag.label ?? tag.title ?? tag.id,
15094
+ serviceId: tag.service_id
15095
+ });
15096
+ }
15097
+ for (const field of serviceProps.fields ?? []) {
15098
+ if (field.service_id != null && String(field.service_id) === String(activeServiceId)) {
15099
+ entries.push({
15100
+ id: field.id,
15101
+ kind: "field",
15102
+ label: field.label ?? field.title ?? field.id,
15103
+ serviceId: field.service_id
15104
+ });
15105
+ }
15106
+ for (const option of field.options ?? []) {
15107
+ if (option.service_id == null || String(option.service_id) !== String(activeServiceId)) continue;
15108
+ entries.push({
15109
+ id: option.id,
15110
+ kind: "option",
15111
+ label: option.label ?? option.title ?? String(option.value ?? option.id),
15112
+ serviceId: option.service_id
15113
+ });
15114
+ }
15115
+ }
15116
+ return dedupeNodeTargets(entries);
15117
+ }
15118
+ return [];
15119
+ }, [activeServiceId, mode, serviceProps, snapshot]);
15120
+ useEffect21(() => {
15121
+ if (hasGlobal && scope === "global") {
15122
+ setScope("node");
15123
+ }
15124
+ }, [hasGlobal, scope]);
15125
+ useEffect21(() => {
15126
+ if (!nodeId) return;
15127
+ if (nodeTargets.some((entry) => entry.id === nodeId)) return;
15128
+ setNodeId("");
15129
+ }, [nodeId, nodeTargets]);
15130
+ function handleContinue() {
15131
+ if (activeServiceId === void 0 || activeServiceId === null) return;
15132
+ if (scope === "global") {
15133
+ onSelect(
15134
+ {
15135
+ scope: "global",
15136
+ primary: activeServiceId
15137
+ },
15138
+ activeServiceId
15139
+ );
15140
+ return;
15141
+ }
15142
+ if (!nodeId) return;
15143
+ const node = nodeTargets.find((entry) => entry.id === nodeId);
15144
+ onSelect(
15145
+ {
15146
+ scope: "node",
15147
+ nodeId
15148
+ },
15149
+ node?.serviceId ?? activeServiceId
15150
+ );
15151
+ }
15152
+ const nodeScopeDisabled = nodeTargets.length === 0;
15153
+ return /* @__PURE__ */ jsx77(
15154
+ ModalShell,
15155
+ {
15156
+ open,
15157
+ onClose,
15158
+ title: "Add registration",
15159
+ description: "Choose the registration scope before selecting fallback candidates.",
15160
+ footer: /* @__PURE__ */ jsxs56("div", { className: "flex items-center justify-end gap-2", children: [
15161
+ /* @__PURE__ */ jsx77(Button, { type: "button", variant: "ghost", onClick: onClose, className: "rounded-md", children: "Cancel" }),
15162
+ /* @__PURE__ */ jsx77(Button, { type: "button", onClick: handleContinue, disabled: activeServiceId === void 0 || scope === "node" && !nodeId, className: "rounded-md", children: "Continue" })
15163
+ ] }),
15164
+ children: /* @__PURE__ */ jsxs56("div", { className: "space-y-5", children: [
15165
+ /* @__PURE__ */ jsxs56("div", { className: "space-y-2", children: [
15166
+ /* @__PURE__ */ jsx77("label", { className: "text-sm font-medium text-slate-900 dark:text-slate-100", children: "Scope" }),
15167
+ /* @__PURE__ */ jsx77(
15168
+ InputField16,
15169
+ {
15170
+ variant: "radio",
15171
+ label: "Scope",
15172
+ value: scope,
15173
+ onChange: ({ value }) => setScope(value),
15174
+ options: [
15175
+ ...!hasGlobal ? [{ value: "global", label: "Global" }] : [],
15176
+ { value: "node", label: nodeScopeDisabled ? "Node (Unavailable)" : "Node" }
15177
+ ]
15178
+ }
15179
+ ),
15180
+ /* @__PURE__ */ jsx77("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: scope === "global" ? "Use one global registration for this primary service." : mode === "snapshot" ? "Pick a node currently active in the order snapshot for this primary service." : mode === "props" ? "Pick a tag, field, or option from ServiceProps that maps to this primary service." : "Node-scoped registration is unavailable without OrderSnapshot or ServiceProps." })
15181
+ ] }),
15182
+ scope === "node" ? /* @__PURE__ */ jsxs56("div", { className: "space-y-2", children: [
15183
+ /* @__PURE__ */ jsx77("label", { className: "text-sm font-medium text-slate-900 dark:text-slate-100", children: "Node id" }),
15184
+ /* @__PURE__ */ jsx77(
15185
+ InputField16,
15186
+ {
15187
+ variant: "select",
15188
+ label: "Node id",
15189
+ value: nodeId || void 0,
15190
+ onChange: ({ value }) => setNodeId(String(value ?? "")),
15191
+ options: nodeTargets.map((node) => ({
15192
+ value: node.id,
15193
+ label: `[${node.kind}] ${node.label} - #${String(node.serviceId)}`
15194
+ })),
15195
+ placeholder: "Select node",
15196
+ searchable: true,
15197
+ clearable: false,
15198
+ fullWidth: true
15199
+ }
15200
+ ),
15201
+ nodeScopeDisabled ? /* @__PURE__ */ jsx77("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: mode === "snapshot" ? "No active snapshot nodes were found for this primary service." : mode === "props" ? "No ServiceProps nodes were found for this primary service." : "Node-scoped registration requires either OrderSnapshot or ServiceProps." }) : null
15202
+ ] }) : null
15203
+ ] })
15204
+ }
15205
+ );
15206
+ }
15207
+ function FallbackAddCandidatesDialog({
15208
+ open,
15209
+ onClose,
15210
+ context,
15211
+ primaryId
15212
+ }) {
15213
+ const { eligible, addMany } = useFallbackEditor2();
15214
+ const eligibleServices = useEligibleServiceList();
15215
+ const [query, setQuery] = useState34("");
15216
+ const [filterEligibleOnly, setFilterEligibleOnly] = useState34(true);
15217
+ const [selected, setSelected] = useState34(/* @__PURE__ */ new Set());
15218
+ const [submitting, setSubmitting] = useState34(false);
15219
+ useEffect21(() => {
15220
+ if (!open) {
15221
+ setQuery("");
15222
+ setFilterEligibleOnly(true);
15223
+ setSelected(/* @__PURE__ */ new Set());
15224
+ }
15225
+ }, [open]);
15226
+ const allowedIds = useMemo35(() => {
15227
+ if (!context || !filterEligibleOnly) return null;
15228
+ return new Set(eligible(context).map((id) => String(id)));
15229
+ }, [context, eligible, filterEligibleOnly]);
15230
+ const items = useMemo35(() => {
15231
+ const normalizedQuery = query.trim().toLowerCase();
15232
+ return eligibleServices.filter((service) => {
15233
+ if (primaryId !== void 0 && String(service.id) === String(primaryId)) return false;
15234
+ if (allowedIds && !allowedIds.has(String(service.id))) return false;
15235
+ if (!normalizedQuery) return true;
15236
+ return String(service.id).includes(normalizedQuery) || String(service.name ?? "").toLowerCase().includes(normalizedQuery) || String(service.platform ?? "").toLowerCase().includes(normalizedQuery);
15237
+ });
15238
+ }, [allowedIds, eligibleServices, primaryId, query]);
15239
+ function toggle(id) {
15240
+ setSelected((previous) => {
15241
+ const next = new Set(previous);
15242
+ const key = String(id);
15243
+ if (next.has(key)) next.delete(key);
15244
+ else next.add(key);
15245
+ return next;
15246
+ });
15247
+ }
15248
+ async function handleAdd() {
15249
+ if (!context || selected.size === 0) return;
15250
+ setSubmitting(true);
15251
+ try {
15252
+ const ids = items.filter((item) => selected.has(String(item.id))).map((item) => item.id);
15253
+ addMany(context, ids);
15254
+ onClose();
15255
+ } finally {
15256
+ setSubmitting(false);
15257
+ }
15258
+ }
15259
+ return /* @__PURE__ */ jsx77(
15260
+ ModalShell,
15261
+ {
15262
+ open: open && Boolean(context),
15263
+ onClose,
15264
+ title: "Add fallback services",
15265
+ description: "Search and select one or more eligible fallback candidates.",
15266
+ size: "wide",
15267
+ footer: /* @__PURE__ */ jsxs56("div", { className: "flex items-center justify-between gap-4", children: [
15268
+ /* @__PURE__ */ jsxs56("p", { className: "text-sm text-slate-500 dark:text-slate-400", children: [
15269
+ selected.size,
15270
+ " selected"
15271
+ ] }),
15272
+ /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2", children: [
15273
+ /* @__PURE__ */ jsx77(Button, { type: "button", variant: "ghost", onClick: onClose, className: "rounded-md", children: "Cancel" }),
15274
+ /* @__PURE__ */ jsx77(Button, { type: "button", onClick: () => void handleAdd(), disabled: selected.size === 0 || submitting, className: "rounded-md", children: submitting ? "Adding..." : "Add selected" })
15275
+ ] })
15276
+ ] }),
15277
+ children: /* @__PURE__ */ jsxs56("div", { className: "space-y-4", children: [
15278
+ /* @__PURE__ */ jsxs56("div", { className: "grid gap-3 md:grid-cols-[minmax(0,1fr)_220px]", children: [
15279
+ /* @__PURE__ */ jsx77(
15280
+ InputField16,
15281
+ {
15282
+ variant: "text",
15283
+ label: "Search eligible services",
15284
+ value: query,
15285
+ onChange: ({ value }) => setQuery(String(value ?? "")),
15286
+ placeholder: "Search eligible services",
15287
+ leadingControl: /* @__PURE__ */ jsx77(Search, { className: "size-4 text-slate-400" }),
15288
+ joinControls: true,
15289
+ extendBoxToControls: true,
15290
+ fullWidth: true
15291
+ }
15292
+ ),
15293
+ /* @__PURE__ */ jsx77("div", { className: "rounded-md border border-slate-200 bg-slate-50/70 px-4 py-3 dark:border-slate-800 dark:bg-slate-900/70", children: /* @__PURE__ */ jsx77(
15294
+ InputField16,
15295
+ {
15296
+ variant: "toggle",
15297
+ label: "Filter eligible only",
15298
+ value: filterEligibleOnly,
15299
+ onChange: ({ value }) => setFilterEligibleOnly(Boolean(value)),
15300
+ onText: "On",
15301
+ offText: "Off"
15302
+ }
15303
+ ) })
15304
+ ] }),
15305
+ /* @__PURE__ */ jsx77(
15306
+ VirtualServiceList,
15307
+ {
15308
+ items,
15309
+ selected,
15310
+ onToggle: toggle,
15311
+ emptyText: "No eligible services found."
15312
+ }
15313
+ )
15314
+ ] })
15315
+ }
15316
+ );
15317
+ }
15318
+ function VirtualServiceList({
15319
+ items,
15320
+ selected,
15321
+ onToggle,
15322
+ height = 420,
15323
+ rowHeight = 72,
15324
+ emptyText = "No services found."
15325
+ }) {
15326
+ const [scrollTop, setScrollTop] = useState34(0);
15327
+ const total = items.length;
15328
+ const visibleCount = Math.ceil(height / rowHeight);
15329
+ const overscan = 6;
15330
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
15331
+ const end = Math.min(total, start + visibleCount + overscan * 2);
15332
+ const visibleItems = items.slice(start, end);
15333
+ if (total === 0) {
15334
+ return /* @__PURE__ */ jsx77(
15335
+ "div",
15336
+ {
15337
+ className: "flex items-center justify-center rounded-md border border-dashed border-slate-300 bg-slate-50/80 text-sm text-slate-500 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-400",
15338
+ style: { height },
15339
+ children: emptyText
15340
+ }
15341
+ );
15342
+ }
15343
+ return /* @__PURE__ */ jsx77(
15344
+ "div",
15345
+ {
15346
+ className: "overflow-auto rounded-md border border-slate-200 bg-white/90 dark:border-slate-800 dark:bg-slate-950/70",
15347
+ style: { height },
15348
+ onScroll: (event) => setScrollTop(event.currentTarget.scrollTop),
15349
+ children: /* @__PURE__ */ jsx77("div", { className: "relative", style: { height: total * rowHeight }, children: visibleItems.map((item, index) => {
15350
+ const absoluteIndex = start + index;
15351
+ const key = String(item.id);
15352
+ const checked = selected.has(key);
15353
+ return /* @__PURE__ */ jsxs56(
15354
+ "button",
15355
+ {
15356
+ type: "button",
15357
+ onClick: () => onToggle(item.id),
15358
+ className: cn(
15359
+ "absolute left-0 right-0 flex items-center justify-between gap-3 border-b border-slate-100 px-4 text-left transition dark:border-slate-800",
15360
+ checked ? "bg-sky-50 dark:bg-sky-500/10" : "bg-white/90 hover:bg-slate-50 dark:bg-slate-950/70 dark:hover:bg-slate-900"
15361
+ ),
15362
+ style: { top: absoluteIndex * rowHeight, height: rowHeight },
15363
+ children: [
15364
+ /* @__PURE__ */ jsxs56("div", { className: "min-w-0", children: [
15365
+ /* @__PURE__ */ jsxs56("div", { className: "truncate text-sm font-semibold text-slate-900 dark:text-slate-100", children: [
15366
+ "Service #",
15367
+ String(item.id),
15368
+ " - ",
15369
+ item.name ?? "Unnamed"
15370
+ ] }),
15371
+ /* @__PURE__ */ jsxs56("div", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: [
15372
+ item.platform ?? "Unknown platform",
15373
+ typeof item.rate === "number" ? ` | Rate ${item.rate}` : ""
15374
+ ] })
15375
+ ] }),
15376
+ /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2", children: [
15377
+ checked ? /* @__PURE__ */ jsx77(ToneBadge, { label: "Selected", tone: "info" }) : null,
15378
+ /* @__PURE__ */ jsx77(
15379
+ "span",
15380
+ {
15381
+ className: cn(
15382
+ "inline-flex size-5 items-center justify-center rounded-md border transition",
15383
+ checked ? "border-sky-500 bg-sky-500 text-white" : "border-slate-300 bg-white text-transparent dark:border-slate-700 dark:bg-slate-900"
15384
+ ),
15385
+ children: /* @__PURE__ */ jsx77(Check, { className: "size-3.5" })
15386
+ }
15387
+ )
15388
+ ] })
15389
+ ]
15390
+ },
15391
+ key
15392
+ );
15393
+ }) })
15394
+ }
15395
+ );
15396
+ }
15397
+ function resolveNodeMeta(props, nodeId) {
15398
+ if (!props) return { kind: "node", label: nodeId };
15399
+ const tag = props.filters?.find((entry) => entry.id === nodeId);
15400
+ if (tag) {
15401
+ return {
15402
+ kind: "tag",
15403
+ label: tag.label ?? tag.title ?? tag.id
15404
+ };
15405
+ }
15406
+ const field = props.fields?.find((entry) => entry.id === nodeId);
15407
+ if (field) {
15408
+ return {
15409
+ kind: "field",
15410
+ label: field.label ?? field.title ?? field.id
15411
+ };
15412
+ }
15413
+ for (const fieldItem of props.fields ?? []) {
15414
+ const option = fieldItem.options?.find((entry) => entry.id === nodeId);
15415
+ if (!option) continue;
15416
+ return {
15417
+ kind: "option",
15418
+ label: option.label ?? option.title ?? String(option.value ?? option.id)
15419
+ };
15420
+ }
15421
+ return { kind: "node", label: nodeId };
15422
+ }
15423
+ function dedupeNodeTargets(entries) {
15424
+ const seen = /* @__PURE__ */ new Set();
15425
+ return entries.filter((entry) => {
15426
+ if (seen.has(entry.id)) return false;
15427
+ seen.add(entry.id);
15428
+ return true;
15429
+ });
15430
+ }
15431
+ function registrationToScope(registration) {
15432
+ if (registration.scope === "global") {
15433
+ return {
15434
+ scope: "global",
15435
+ primary: registration.primary
15436
+ };
15437
+ }
15438
+ return {
15439
+ scope: "node",
15440
+ nodeId: registration.scopeId
15441
+ };
15442
+ }
15443
+
15444
+ // src/workspace/fallback-editor/fallback-registrations-panel.tsx
15445
+ import { Fragment as Fragment15, jsx as jsx78, jsxs as jsxs57 } from "react/jsx-runtime";
15446
+ function FallbackRegistrationsPanel() {
15447
+ const { activeServiceId, remove, clear, check } = useFallbackEditor3();
15448
+ const registrations = useActiveFallbackRegistrations3();
15449
+ const eligibleServices = useEligibleServiceList2();
15450
+ const [candidatePickerOpen, setCandidatePickerOpen] = useState35(false);
15451
+ const [candidateContext, setCandidateContext] = useState35(null);
15452
+ const [candidatePrimaryId, setCandidatePrimaryId] = useState35(void 0);
15453
+ const [registrationDialogOpen, setRegistrationDialogOpen] = useState35(false);
15454
+ const openCandidatePicker = useCallback20((context, primaryId) => {
15455
+ setCandidateContext(context);
15456
+ setCandidatePrimaryId(primaryId);
15457
+ setCandidatePickerOpen(true);
15458
+ }, []);
15459
+ if (activeServiceId === void 0 || activeServiceId === null) {
15460
+ return /* @__PURE__ */ jsx78(SectionCard, { className: "p-5", children: /* @__PURE__ */ jsx78(
15461
+ EmptyState2,
15462
+ {
15463
+ title: "Select a primary service",
15464
+ description: "Pick a service from the left sidebar to review or create fallback registrations."
15465
+ }
15466
+ ) });
15467
+ }
15468
+ return /* @__PURE__ */ jsxs57(Fragment15, { children: [
15469
+ /* @__PURE__ */ jsxs57(SectionCard, { className: "flex min-h-0 flex-col flex-1 overflow-hidden", children: [
15470
+ /* @__PURE__ */ jsx78("div", { className: "border-b border-slate-200 px-5 py-4 dark:border-slate-800", children: /* @__PURE__ */ jsx78(
15471
+ SectionHeader2,
15472
+ {
15473
+ title: "Registered fallbacks",
15474
+ description: "Add global or node-scoped registrations, then curate the fallback candidates for each scope.",
15475
+ action: /* @__PURE__ */ jsxs57(Button, { type: "button", variant: "outline", onClick: () => setRegistrationDialogOpen(true), className: "rounded-md", children: [
15476
+ /* @__PURE__ */ jsx78(Plus, { className: "size-4" }),
15477
+ "Add registration"
15478
+ ] })
15479
+ }
15480
+ ) }),
15481
+ /* @__PURE__ */ jsx78(ScrollArea, { className: "min-h-0 flex-1", "data-testid": "fallback-editor-registrations-scroll", children: /* @__PURE__ */ jsx78("div", { className: "space-y-4 p-4", children: registrations.length === 0 ? /* @__PURE__ */ jsx78(
15482
+ EmptyState2,
15483
+ {
15484
+ title: "No registrations yet",
15485
+ description: "Create a global or node-scoped registration for the selected primary service."
15486
+ }
15487
+ ) : registrations.map((registration, index) => {
15488
+ const context = registrationToScope(registration);
15489
+ const candidates = registration.services;
15490
+ return /* @__PURE__ */ jsxs57(
15491
+ "div",
15492
+ {
15493
+ className: "rounded-md border border-slate-200 bg-slate-50/80 p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900/60",
15494
+ children: [
15495
+ /* @__PURE__ */ jsxs57("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
15496
+ /* @__PURE__ */ jsxs57("div", { className: "space-y-2", children: [
15497
+ /* @__PURE__ */ jsxs57("div", { className: "flex flex-wrap items-center gap-2", children: [
15498
+ /* @__PURE__ */ jsx78(ToneBadge, { label: registration.scope === "global" ? "Global registration" : `Node ${registration.scopeId ?? ""}`.trim(), tone: "info" }),
15499
+ /* @__PURE__ */ jsx78(ToneBadge, { label: `Primary #${String(registration.primary)}` })
15500
+ ] }),
15501
+ /* @__PURE__ */ jsx78("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: registration.scope === "global" ? "Primary service fallback list" : `Node-scoped fallback list for ${registration.scopeId}` })
15502
+ ] }),
15503
+ /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
15504
+ /* @__PURE__ */ jsxs57(Button, { type: "button", variant: "outline", onClick: () => openCandidatePicker(context, registration.primary), className: "rounded-md", children: [
15505
+ /* @__PURE__ */ jsx78(Plus, { className: "size-4" }),
15506
+ "Add fallback"
15507
+ ] }),
15508
+ /* @__PURE__ */ jsxs57(Button, { type: "button", variant: "outline", onClick: () => clear(context), className: "rounded-md", children: [
15509
+ /* @__PURE__ */ jsx78(Trash2, { className: "size-4" }),
15510
+ "Clear"
15511
+ ] })
15512
+ ] })
15513
+ ] }),
15514
+ /* @__PURE__ */ jsx78("div", { className: "mt-4 flex flex-wrap gap-2", children: candidates.length === 0 ? /* @__PURE__ */ jsx78("span", { className: "text-xs text-slate-500 dark:text-slate-400", children: "No fallback services yet." }) : candidates.map((candidate) => {
15515
+ const preview = check(context, [candidate]);
15516
+ const rejected = preview.rejected[0];
15517
+ const service = eligibleServices.find((entry) => String(entry.id) === String(candidate));
15518
+ return /* @__PURE__ */ jsxs57(
15519
+ "div",
15520
+ {
15521
+ className: [
15522
+ "inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs",
15523
+ rejected ? "border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-200" : "border-slate-200 bg-white text-slate-700 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-200"
15524
+ ].join(" "),
15525
+ children: [
15526
+ /* @__PURE__ */ jsx78("span", { children: service ? `#${String(service.id)} - ${service.name ?? "Unnamed"}` : `#${String(candidate)}` }),
15527
+ /* @__PURE__ */ jsx78(
15528
+ ToneBadge,
15529
+ {
15530
+ label: rejected ? rejected.reasons.join(", ") : "valid",
15531
+ tone: rejected ? "danger" : "success"
15532
+ }
15533
+ ),
15534
+ /* @__PURE__ */ jsx78(
15535
+ "button",
15536
+ {
15537
+ type: "button",
15538
+ "aria-label": `Remove candidate ${String(candidate)}`,
15539
+ onClick: () => remove(context, candidate),
15540
+ className: "text-current/70 transition hover:text-current",
15541
+ children: /* @__PURE__ */ jsx78(X2, { className: "size-3.5" })
15542
+ }
15543
+ )
15544
+ ]
15545
+ },
15546
+ String(candidate)
15547
+ );
15548
+ }) })
15549
+ ]
15550
+ },
15551
+ `${registration.scope}:${String(registration.scopeId ?? "global")}:${index}`
15552
+ );
15553
+ }) }) })
15554
+ ] }),
15555
+ /* @__PURE__ */ jsx78(
15556
+ FallbackAddRegistrationDialog,
15557
+ {
15558
+ open: registrationDialogOpen,
15559
+ onClose: () => setRegistrationDialogOpen(false),
15560
+ onSelect: (context, primaryId) => {
15561
+ setRegistrationDialogOpen(false);
15562
+ openCandidatePicker(context, primaryId);
15563
+ }
15564
+ }
15565
+ ),
15566
+ /* @__PURE__ */ jsx78(
15567
+ FallbackAddCandidatesDialog,
15568
+ {
15569
+ open: candidatePickerOpen,
15570
+ onClose: () => setCandidatePickerOpen(false),
15571
+ context: candidateContext,
15572
+ primaryId: candidatePrimaryId
15573
+ }
15574
+ )
15575
+ ] });
15576
+ }
15577
+
15578
+ // src/workspace/fallback-editor/fallback-service-sidebar.tsx
15579
+ import { useFallbackEditor as useFallbackEditor4, usePrimaryServiceList as usePrimaryServiceList2 } from "@timeax/digital-service-engine/react";
15580
+ import { InputField as InputField17 } from "@timeax/form-palette";
15581
+ import { Search as Search2 } from "lucide-react";
15582
+ import { useMemo as useMemo36, useState as useState36 } from "react";
15583
+ import { jsx as jsx79, jsxs as jsxs58 } from "react/jsx-runtime";
15584
+ function FallbackServiceSidebar() {
15585
+ const { activeServiceId, setActiveServiceId, get } = useFallbackEditor4();
15586
+ const services2 = usePrimaryServiceList2();
15587
+ const [query, setQuery] = useState36("");
15588
+ const filtered = useMemo36(() => {
15589
+ const normalizedQuery = query.trim().toLowerCase();
15590
+ if (!normalizedQuery) return services2;
15591
+ return services2.filter((service) => {
15592
+ return String(service.id).includes(normalizedQuery) || String(service.name ?? "").toLowerCase().includes(normalizedQuery) || String(service.platform ?? "").toLowerCase().includes(normalizedQuery);
15593
+ });
15594
+ }, [query, services2]);
15595
+ return /* @__PURE__ */ jsxs58(SectionCard, { className: "flex h-full min-h-0 min-w-70 flex-col overflow-hidden border-r-0", children: [
15596
+ /* @__PURE__ */ jsxs58("div", { className: "border-b border-slate-200 px-4 py-4 dark:border-slate-800 space-y-2", children: [
15597
+ /* @__PURE__ */ jsx79(SectionHeader2, { title: "Primary services", description: "Choose the primary service whose fallback registrations you want to edit." }),
15598
+ /* @__PURE__ */ jsx79(
15599
+ InputField17,
15600
+ {
15601
+ variant: "text",
15602
+ value: query,
15603
+ onChange: ({ value }) => setQuery(String(value ?? "")),
15604
+ placeholder: "Search primary service",
15605
+ icon: /* @__PURE__ */ jsx79(Search2, { className: "size-4 text-slate-400" })
15606
+ }
15607
+ )
15608
+ ] }),
15609
+ /* @__PURE__ */ jsx79(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx79("div", { className: "space-y-2 p-3", children: filtered.map((service) => {
15610
+ const selected = String(service.id) === String(activeServiceId);
15611
+ const count = get(service.id).length;
15612
+ return /* @__PURE__ */ jsx79(
15613
+ "button",
15614
+ {
15615
+ type: "button",
15616
+ onClick: () => setActiveServiceId(service.id),
15617
+ className: cn(
15618
+ "w-full rounded-md border px-4 py-3 text-left transition",
15619
+ "hover:-translate-y-0.5 hover:border-slate-300 hover:shadow-md dark:hover:border-slate-700",
15620
+ selected ? "border-sky-300 bg-sky-50 shadow-sm dark:border-sky-500/40 dark:bg-sky-500/10" : "border-slate-200 bg-white/90 dark:border-slate-800 dark:bg-slate-950/70"
15621
+ ),
15622
+ children: /* @__PURE__ */ jsxs58("div", { className: "flex items-start justify-between gap-3", children: [
15623
+ /* @__PURE__ */ jsxs58("div", { className: "min-w-0", children: [
15624
+ /* @__PURE__ */ jsxs58("p", { title: service.name, className: "truncate text-sm font-semibold text-slate-900 dark:text-slate-100", children: [
15625
+ "Service #",
15626
+ String(service.id),
15627
+ " - ",
15628
+ service.name ?? "Unnamed"
15629
+ ] }),
15630
+ /* @__PURE__ */ jsxs58("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: [
15631
+ service.platform ?? "Unknown platform",
15632
+ typeof service.rate === "number" ? ` | Rate ${service.rate}` : ""
15633
+ ] })
15634
+ ] }),
15635
+ /* @__PURE__ */ jsx79(ToneBadge, { label: `${count} reg`, tone: selected ? "info" : "neutral", className: "shrink-0" })
15636
+ ] })
15637
+ },
15638
+ String(service.id)
15639
+ );
15640
+ }) }) })
15641
+ ] });
15642
+ }
15643
+
15644
+ // src/workspace/fallback-editor/fallback-settings-panel.tsx
15645
+ import { useFallbackEditor as useFallbackEditor5 } from "@timeax/digital-service-engine/react";
15646
+ import { InputField as InputField18 } from "@timeax/form-palette";
15647
+ import { useEffect as useEffect22, useState as useState37 } from "react";
15648
+ import { jsx as jsx80, jsxs as jsxs59 } from "react/jsx-runtime";
15649
+ function FallbackSettingsPanel() {
15650
+ const { settings, saveSettings, settingsSaving } = useFallbackEditor5();
15651
+ const [draft, setDraft] = useState37(settings);
15652
+ const [error, setError] = useState37(null);
15653
+ const [saved, setSaved] = useState37(false);
15654
+ useEffect22(() => {
15655
+ setDraft(settings);
15656
+ setSaved(false);
15657
+ setError(null);
15658
+ }, [settings]);
15659
+ const changed = JSON.stringify(draft ?? {}) !== JSON.stringify(settings ?? {});
15660
+ const ratePolicy = draft.ratePolicy ?? { kind: "lte_primary", pct: 5 };
15661
+ async function handleSave() {
15662
+ setError(null);
15663
+ setSaved(false);
15664
+ try {
15665
+ await saveSettings(draft);
15666
+ setSaved(true);
15667
+ } catch (nextError) {
15668
+ setError(nextError instanceof Error ? nextError.message : "Failed to save fallback settings.");
15669
+ }
15670
+ }
15671
+ function setRatePolicy(next) {
15672
+ setDraft((previous) => ({
15673
+ ...previous,
15674
+ ratePolicy: next
15675
+ }));
15676
+ }
15677
+ return /* @__PURE__ */ jsxs59(SectionCard, { className: "flex flex-1 min-h-0 flex-col overflow-hidden", children: [
15678
+ /* @__PURE__ */ jsx80("div", { className: "border-b border-slate-200 px-5 py-4 dark:border-slate-800", children: /* @__PURE__ */ jsx80(
15679
+ SectionHeader2,
15680
+ {
15681
+ title: "Fallback settings",
15682
+ description: "Persist policy changes through the host editor without changing the fallback payload shape.",
15683
+ action: /* @__PURE__ */ jsx80(Button, { type: "button", onClick: () => void handleSave(), disabled: !changed || settingsSaving, className: "rounded-md", children: settingsSaving ? "Saving..." : "Save settings" })
15684
+ }
15685
+ ) }),
15686
+ /* @__PURE__ */ jsx80(ScrollArea, { className: "min-h-0 flex-1 p-5", "data-testid": "fallback-editor-settings-scroll", children: /* @__PURE__ */ jsxs59("div", { className: "space-y-5", children: [
15687
+ /* @__PURE__ */ jsx80(SettingRow, { title: "Require constraint fit", hint: "Reject or warn when a candidate does not match effective tag constraints.", children: /* @__PURE__ */ jsx80(
15688
+ InputField18,
15689
+ {
15690
+ variant: "toggle",
15691
+ value: Boolean(draft.requireConstraintFit),
15692
+ onChange: ({ value }) => setDraft((previous) => ({
15693
+ ...previous,
15694
+ requireConstraintFit: Boolean(value)
15695
+ })),
15696
+ onText: "Enabled",
15697
+ offText: "Disabled"
15698
+ }
15699
+ ) }),
15700
+ /* @__PURE__ */ jsx80(SettingRow, { title: "Rate policy", hint: "Controls how fallback service rates are compared against the primary service.", children: /* @__PURE__ */ jsx80("div", { className: "flex flex-col gap-2 md:items-end", children: /* @__PURE__ */ jsx80(
15701
+ InputField18,
15702
+ {
15703
+ variant: "select",
15704
+ value: ratePolicy.kind,
15705
+ onChange: ({ value }) => {
15706
+ const kind = value;
15707
+ const pct = ratePolicy.kind === "eq_primary" ? 5 : ratePolicy.pct;
15708
+ if (kind === "eq_primary") {
15709
+ setRatePolicy({ kind: "eq_primary" });
15710
+ return;
15711
+ }
15712
+ if (kind === "lte_primary") {
15713
+ setRatePolicy({ kind: "lte_primary", pct });
15714
+ return;
15715
+ }
15716
+ if (kind === "within_pct") {
15717
+ setRatePolicy({ kind: "within_pct", pct });
15718
+ return;
15719
+ }
15720
+ setRatePolicy({ kind: "at_least_pct_lower", pct });
15721
+ },
15722
+ options: [
15723
+ { value: "eq_primary", label: "Equals Primary" },
15724
+ { value: "lte_primary", label: "Less than or Equals" },
15725
+ { value: "within_pct", label: "Within Range" },
15726
+ { value: "at_least_pct_lower", label: "Lower by" }
15727
+ ],
15728
+ clearable: false
15729
+ }
15730
+ ) }) }),
15731
+ ratePolicy.kind !== "eq_primary" ? /* @__PURE__ */ jsx80(SettingRow, { title: "Rate Percentage", hint: "Rate percentage the policy is guarded by", children: /* @__PURE__ */ jsx80("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx80("div", { className: "w-32", children: /* @__PURE__ */ jsx80(
15732
+ InputField18,
15733
+ {
15734
+ variant: "number",
15735
+ value: ratePolicy.pct,
15736
+ onChange: ({ value }) => {
15737
+ const pct = typeof value === "number" ? value : Number(value ?? 0);
15738
+ setRatePolicy({
15739
+ ...ratePolicy,
15740
+ pct
15741
+ });
15742
+ },
15743
+ min: 0,
15744
+ step: 0.01,
15745
+ fullWidth: true,
15746
+ showButtons: true,
15747
+ trailingIcons: [/* @__PURE__ */ jsx80("span", { className: "pr-2", children: "%" })]
15748
+ }
15749
+ ) }) }) }) : null,
15750
+ /* @__PURE__ */ jsx80(SettingRow, { title: "Selection strategy", hint: "How valid fallback candidates are ordered in previews.", children: /* @__PURE__ */ jsx80(
15751
+ InputField18,
15752
+ {
15753
+ variant: "select",
15754
+ label: "Selection strategy",
15755
+ value: draft.selectionStrategy ?? "priority",
15756
+ onChange: ({ value }) => setDraft((previous) => ({
15757
+ ...previous,
15758
+ selectionStrategy: value
15759
+ })),
15760
+ options: [
15761
+ { value: "priority", label: "priority" },
15762
+ { value: "cheapest", label: "cheapest" }
15763
+ ],
15764
+ clearable: false
15765
+ }
15766
+ ) }),
15767
+ /* @__PURE__ */ jsx80(SettingRow, { title: "Mode", hint: "Use strict for enforced filtering, dev for advisory feedback.", children: /* @__PURE__ */ jsx80(
15768
+ InputField18,
15769
+ {
15770
+ variant: "select",
15771
+ label: "Mode",
15772
+ value: draft.mode ?? "strict",
15773
+ onChange: ({ value }) => setDraft((previous) => ({
15774
+ ...previous,
15775
+ mode: value
15776
+ })),
15777
+ options: [
15778
+ { value: "strict", label: "strict" },
15779
+ { value: "dev", label: "dev" }
15780
+ ],
15781
+ clearable: false
15782
+ }
15783
+ ) }),
15784
+ saved && !error ? /* @__PURE__ */ jsx80(Alert, { className: "border border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-500/30 dark:bg-emerald-500/10 dark:text-emerald-200", children: /* @__PURE__ */ jsx80(AlertDescription, { children: "Settings saved." }) }) : null,
15785
+ error ? /* @__PURE__ */ jsx80(Alert, { variant: "destructive", className: "border border-rose-200 bg-rose-50 dark:border-rose-500/30 dark:bg-rose-500/10", children: /* @__PURE__ */ jsx80(AlertDescription, { children: error }) }) : null
15786
+ ] }) })
15787
+ ] });
15788
+ }
15789
+ function SettingRow({ title, hint, children }) {
15790
+ return /* @__PURE__ */ jsxs59("div", { className: "flex flex-col gap-3 border-b border-dashed border-slate-200 pb-5 last:border-b-0 last:pb-0 md:flex-row md:items-center md:justify-between dark:border-slate-800", children: [
15791
+ /* @__PURE__ */ jsxs59("div", { className: "max-w-xl", children: [
15792
+ /* @__PURE__ */ jsx80("div", { className: "text-sm font-medium text-slate-900 dark:text-slate-100", children: title }),
15793
+ /* @__PURE__ */ jsx80("div", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: hint })
15794
+ ] }),
15795
+ /* @__PURE__ */ jsx80("div", { children })
15796
+ ] });
15797
+ }
15798
+
15799
+ // src/workspace/fallback-editor/native-fallback-editor.tsx
15800
+ import { jsx as jsx81, jsxs as jsxs60 } from "react/jsx-runtime";
15801
+ function NativeFallbackEditor({
15802
+ className,
15803
+ fallbacks,
15804
+ props,
15805
+ snapshot,
15806
+ primaryServices,
15807
+ eligibleServices,
15808
+ settings,
15809
+ initialServiceId,
15810
+ initialTab,
15811
+ onSettingsChange,
15812
+ onSave,
15813
+ onValidate,
15814
+ onReset
15815
+ }) {
15816
+ return /* @__PURE__ */ jsx81(
15817
+ FallbackEditorProvider,
15818
+ {
15819
+ fallbacks,
15820
+ props,
15821
+ snapshot,
15822
+ primaryServices,
15823
+ eligibleServices,
15824
+ settings,
15825
+ initialServiceId,
15826
+ initialTab,
15827
+ onSettingsChange,
15828
+ onSave,
15829
+ onValidate,
15830
+ onReset,
15831
+ children: /* @__PURE__ */ jsx81(NativeFallbackEditorInner, { className })
15832
+ }
15833
+ );
15834
+ }
15835
+ function NativeFallbackEditorInner({ className }) {
15836
+ const {
15837
+ activeTab,
15838
+ setActiveTab,
15839
+ activeServiceId,
15840
+ saveFallbacks,
15841
+ validateFallbacks,
15842
+ resetEditor,
15843
+ state,
15844
+ headerSaving,
15845
+ headerValidating,
15846
+ headerResetting
15847
+ } = useFallbackEditor6();
15848
+ const registrations = useActiveFallbackRegistrations4();
15849
+ const services2 = usePrimaryServiceList3();
15850
+ const activeServiceLabel = useMemo37(() => {
15851
+ const service = services2.find((entry) => String(entry.id) === String(activeServiceId));
15852
+ if (!service) return void 0;
15853
+ return `${service.name ?? "Unnamed"} (#${String(service.id)})`;
15854
+ }, [activeServiceId, services2]);
15855
+ return /* @__PURE__ */ jsxs60("div", { className: cn("flex h-full min-h-0 flex-col gap-4 text-slate-900 dark:text-slate-100", className), children: [
15856
+ /* @__PURE__ */ jsx81(
15857
+ FallbackEditorHeader,
15858
+ {
15859
+ activeServiceLabel,
15860
+ registrationCount: registrations.length,
15861
+ changed: state.changed,
15862
+ onReset: resetEditor,
15863
+ onValidate: validateFallbacks,
15864
+ onSave: saveFallbacks,
15865
+ resetting: headerResetting,
15866
+ validating: headerValidating,
15867
+ saving: headerSaving
15868
+ }
15869
+ ),
15870
+ /* @__PURE__ */ jsxs60(ResizablePanelGroup, { direction: "horizontal", className: "min-h-0 flex-1 gap-0 overflow-hidden", "data-testid": "fallback-editor-layout", children: [
15871
+ /* @__PURE__ */ jsx81(ResizablePanel, { defaultSize: 300, minSize: 300, maxSize: 350, className: "", children: /* @__PURE__ */ jsx81("div", { className: "flex h-full min-h-0 min-w-70", "data-testid": "fallback-editor-sidebar-panel", children: /* @__PURE__ */ jsx81(FallbackServiceSidebar, {}) }) }),
15872
+ /* @__PURE__ */ jsx81(ResizableHandle, {}),
15873
+ /* @__PURE__ */ jsx81(ResizablePanel, { defaultSize: 78, minSize: 66, className: "pl-4", children: /* @__PURE__ */ jsxs60("div", { className: "grid h-full min-h-0 gap-4 xl:grid-cols-[minmax(0,1fr)_360px]", "data-testid": "fallback-editor-main-panel", children: [
15874
+ /* @__PURE__ */ jsxs60(
15875
+ Tabs,
15876
+ {
15877
+ value: activeTab,
15878
+ onValueChange: (value) => setActiveTab(value),
15879
+ className: "min-h-0 gap-4 overflow-hidden",
15880
+ children: [
15881
+ /* @__PURE__ */ jsx81(SectionCard, { className: "shrink-0 px-5 py-4", children: /* @__PURE__ */ jsxs60("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between", children: [
15882
+ /* @__PURE__ */ jsxs60("div", { className: "min-w-0", children: [
15883
+ /* @__PURE__ */ jsx81("h2", { className: "text-lg font-semibold text-slate-900 dark:text-slate-100", children: activeServiceId != null ? `Service #${String(activeServiceId)}` : "No service selected" }),
15884
+ /* @__PURE__ */ jsx81("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: "Edit fallback registrations, review validation hints, and persist policy updates." })
15885
+ ] }),
15886
+ /* @__PURE__ */ jsxs60(TabsList, { children: [
15887
+ /* @__PURE__ */ jsx81(TabsTrigger, { value: "registrations", children: "Registrations" }),
15888
+ /* @__PURE__ */ jsx81(TabsTrigger, { value: "settings", children: "Settings" })
15889
+ ] })
15890
+ ] }) }),
15891
+ /* @__PURE__ */ jsx81(TabsContent, { value: "registrations", className: "min-h-0 overflow-hidden", "data-testid": "fallback-editor-registrations-tab", children: /* @__PURE__ */ jsx81(FallbackRegistrationsPanel, {}) }),
15892
+ /* @__PURE__ */ jsx81(TabsContent, { value: "settings", className: "min-h-0 flex flex-col overflow-hidden", "data-testid": "fallback-editor-settings-tab", children: /* @__PURE__ */ jsx81(FallbackSettingsPanel, {}) })
15893
+ ]
15894
+ }
15895
+ ),
15896
+ /* @__PURE__ */ jsx81("div", { className: "min-h-0 overflow-hidden flex flex-col", "data-testid": "fallback-editor-details-panel", children: /* @__PURE__ */ jsx81(FallbackDetailsPanel, {}) })
15897
+ ] }) })
15898
+ ] })
15899
+ ] });
15900
+ }
15901
+
14598
15902
  // src/workspace/fallback-editor-modal.tsx
14599
15903
  import { useCanvas as useCanvas18, useWorkspace as useWorkspace15 } from "@timeax/digital-service-engine/workspace";
14600
15904
  import cloneDeep4 from "lodash/cloneDeep";
14601
- import { Suspense, lazy, createContext as createContext4, useCallback as useCallback20, useContext as useContext4, useEffect as useEffect21, useMemo as useMemo34, useState as useState33 } from "react";
15905
+ import { createContext as createContext4, useCallback as useCallback21, useContext as useContext4, useEffect as useEffect23, useMemo as useMemo38, useState as useState38 } from "react";
14602
15906
  import { createPortal as createPortal4 } from "react-dom";
14603
15907
  import { FiX as FiX4 } from "react-icons/fi";
14604
- import { jsx as jsx73, jsxs as jsxs53 } from "react/jsx-runtime";
14605
- var LazyFallbackEditor = lazy(async () => {
14606
- const mod = await import("@timeax/digital-service-engine/react");
14607
- return { default: mod.FallbackEditor };
14608
- });
15908
+ import { jsx as jsx82, jsxs as jsxs61 } from "react/jsx-runtime";
14609
15909
  var noop2 = () => {
14610
15910
  };
14611
15911
  var defaultContextValue2 = {
@@ -14618,14 +15918,14 @@ var FallbackEditorModalContext = createContext4(defaultContextValue2);
14618
15918
  function FallbackEditorModalProvider({ children }) {
14619
15919
  const canvas = useCanvas18();
14620
15920
  const ws = useWorkspace15();
14621
- const [launch, setLaunch] = useState33(null);
14622
- const [sessionId, setSessionId] = useState33(0);
14623
- const [surfaceError, setSurfaceError] = useState33(null);
14624
- const close = useCallback20(() => {
15921
+ const [launch, setLaunch] = useState38(null);
15922
+ const [sessionId, setSessionId] = useState38(0);
15923
+ const [surfaceError, setSurfaceError] = useState38(null);
15924
+ const close = useCallback21(() => {
14625
15925
  setLaunch(null);
14626
15926
  setSurfaceError(null);
14627
15927
  }, []);
14628
- const openForNode = useCallback20((input) => {
15928
+ const openForNode = useCallback21((input) => {
14629
15929
  setSurfaceError(null);
14630
15930
  setSessionId((current) => current + 1);
14631
15931
  setLaunch({
@@ -14636,7 +15936,7 @@ function FallbackEditorModalProvider({ children }) {
14636
15936
  nodeLabel: input.nodeLabel ?? input.nodeId
14637
15937
  });
14638
15938
  }, []);
14639
- const openForService = useCallback20((input) => {
15939
+ const openForService = useCallback21((input) => {
14640
15940
  setSurfaceError(null);
14641
15941
  setSessionId((current) => current + 1);
14642
15942
  setLaunch({
@@ -14645,7 +15945,7 @@ function FallbackEditorModalProvider({ children }) {
14645
15945
  serviceName: input.serviceName
14646
15946
  });
14647
15947
  }, []);
14648
- const persistProps = useCallback20(
15948
+ const persistProps = useCallback21(
14649
15949
  (label, mutate) => {
14650
15950
  const editorAny = canvas.api.editor;
14651
15951
  if (typeof editorAny.transact !== "function" || typeof editorAny.replaceProps !== "function") {
@@ -14659,7 +15959,7 @@ function FallbackEditorModalProvider({ children }) {
14659
15959
  },
14660
15960
  [canvas.api.builder, canvas.api.editor, canvas.props]
14661
15961
  );
14662
- const handleSave = useCallback20(
15962
+ const handleSave = useCallback21(
14663
15963
  async (nextFallbacks) => {
14664
15964
  setSurfaceError(null);
14665
15965
  try {
@@ -14676,7 +15976,7 @@ function FallbackEditorModalProvider({ children }) {
14676
15976
  },
14677
15977
  [close, persistProps]
14678
15978
  );
14679
- const handleSettingsChange = useCallback20(
15979
+ const handleSettingsChange = useCallback21(
14680
15980
  async (nextSettings) => {
14681
15981
  setSurfaceError(null);
14682
15982
  try {
@@ -14692,26 +15992,26 @@ function FallbackEditorModalProvider({ children }) {
14692
15992
  },
14693
15993
  [persistProps]
14694
15994
  );
14695
- const launchTitle = useMemo34(() => {
15995
+ const launchTitle = useMemo38(() => {
14696
15996
  if (!launch) return "Fallback editor";
14697
15997
  if (launch.source === "node") {
14698
15998
  return launch.nodeLabel ? `Fallback editor for ${launch.nodeLabel}` : "Fallback editor";
14699
15999
  }
14700
16000
  return launch.serviceName ? `Fallback editor for ${launch.serviceName}` : `Fallback editor for service #${String(launch.initialServiceId)}`;
14701
16001
  }, [launch]);
14702
- const launchDescription = useMemo34(() => {
16002
+ const launchDescription = useMemo38(() => {
14703
16003
  if (!launch) return "";
14704
16004
  if (launch.source === "node") {
14705
16005
  return `Browse and edit fallback registrations for service #${String(launch.initialServiceId)}. Node-scoped and global registrations remain available inside the editor.`;
14706
16006
  }
14707
16007
  return `Browse and edit all fallback registrations for service #${String(launch.initialServiceId)} from Active Services.`;
14708
16008
  }, [launch]);
14709
- const servicesMap = useMemo34(() => ws.services.data ?? {}, [ws.services.data]);
14710
- const fallbackSettings = useMemo34(
16009
+ const servicesMap = useMemo38(() => ws.services.data ?? {}, [ws.services.data]);
16010
+ const fallbackSettings = useMemo38(
14711
16011
  () => canvas.props?.fallbackSettings ?? {},
14712
16012
  [canvas.props]
14713
16013
  );
14714
- useEffect21(() => {
16014
+ useEffect23(() => {
14715
16015
  if (!launch) return;
14716
16016
  const onKeyDown = (event) => {
14717
16017
  if (event.key === "Escape") close();
@@ -14719,7 +16019,7 @@ function FallbackEditorModalProvider({ children }) {
14719
16019
  window.addEventListener("keydown", onKeyDown);
14720
16020
  return () => window.removeEventListener("keydown", onKeyDown);
14721
16021
  }, [close, launch]);
14722
- const value = useMemo34(
16022
+ const value = useMemo38(
14723
16023
  () => ({
14724
16024
  openForNode,
14725
16025
  openForService,
@@ -14728,51 +16028,45 @@ function FallbackEditorModalProvider({ children }) {
14728
16028
  }),
14729
16029
  [close, launch, openForNode, openForService]
14730
16030
  );
14731
- return /* @__PURE__ */ jsxs53(FallbackEditorModalContext.Provider, { value, children: [
16031
+ return /* @__PURE__ */ jsxs61(FallbackEditorModalContext.Provider, { value, children: [
14732
16032
  children,
14733
16033
  typeof document !== "undefined" && launch ? createPortal4(
14734
- /* @__PURE__ */ jsx73(
16034
+ /* @__PURE__ */ jsx82(
14735
16035
  "div",
14736
16036
  {
14737
16037
  className: "fixed inset-0 z-50 flex items-center justify-center bg-slate-950/60 p-4 backdrop-blur-sm",
14738
16038
  onMouseDown: (event) => {
14739
16039
  if (event.target === event.currentTarget) close();
14740
16040
  },
14741
- children: /* @__PURE__ */ jsxs53(
16041
+ children: /* @__PURE__ */ jsxs61(
14742
16042
  "div",
14743
16043
  {
14744
16044
  className: cn(
14745
- "flex h-[min(90vh,56rem)] w-[min(96vw,88rem)] flex-col overflow-hidden rounded-[28px] border border-slate-200 bg-white shadow-2xl dark:border-slate-800 dark:bg-slate-950"
16045
+ "flex h-[min(90vh,56rem)] w-[min(96vw,88rem)] flex-col overflow-hidden rounded-md border border-slate-200 bg-white shadow-2xl dark:border-slate-800 dark:bg-slate-950"
14746
16046
  ),
14747
16047
  children: [
14748
- /* @__PURE__ */ jsxs53("div", { className: "flex items-start justify-between gap-4 border-b border-slate-200 px-6 py-4 dark:border-slate-800", children: [
14749
- /* @__PURE__ */ jsxs53("div", { className: "min-w-0", children: [
14750
- /* @__PURE__ */ jsx73("h2", { className: "text-lg font-semibold text-slate-900 dark:text-slate-100", children: launchTitle }),
14751
- /* @__PURE__ */ jsx73("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: launchDescription })
16048
+ /* @__PURE__ */ jsxs61("div", { className: "flex items-start justify-between gap-4 border-b border-slate-200 px-6 py-4 dark:border-slate-800", children: [
16049
+ /* @__PURE__ */ jsxs61("div", { className: "min-w-0", children: [
16050
+ /* @__PURE__ */ jsx82("h2", { className: "text-lg font-semibold text-slate-900 dark:text-slate-100", children: launchTitle }),
16051
+ /* @__PURE__ */ jsx82("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: launchDescription })
14752
16052
  ] }),
14753
- /* @__PURE__ */ jsx73(Button, { type: "button", variant: "ghost", size: "sm", onClick: close, className: "h-9 rounded-xl px-2", children: /* @__PURE__ */ jsx73(FiX4, {}) })
16053
+ /* @__PURE__ */ jsx82(Button, { type: "button", variant: "ghost", size: "sm", onClick: close, className: "h-9 rounded-md px-2", children: /* @__PURE__ */ jsx82(FiX4, {}) })
14754
16054
  ] }),
14755
- surfaceError ? /* @__PURE__ */ jsx73("div", { className: "border-b border-rose-200 bg-rose-50 px-6 py-3 text-sm text-rose-700 dark:border-rose-900/40 dark:bg-rose-950/20 dark:text-rose-200", children: surfaceError }) : null,
14756
- /* @__PURE__ */ jsx73("div", { className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx73(
14757
- Suspense,
16055
+ surfaceError ? /* @__PURE__ */ jsx82("div", { className: "border-b border-rose-200 bg-rose-50 px-6 py-3 text-sm text-rose-700 dark:border-rose-900/40 dark:bg-rose-950/20 dark:text-rose-200", children: surfaceError }) : null,
16056
+ /* @__PURE__ */ jsx82("div", { className: "min-h-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsx82(
16057
+ NativeFallbackEditor,
14758
16058
  {
14759
- fallback: /* @__PURE__ */ jsx73("div", { className: "flex h-full min-h-96 items-center justify-center px-6 text-sm text-slate-500 dark:text-slate-400", children: "Loading fallback editor..." }),
14760
- children: /* @__PURE__ */ jsx73(
14761
- LazyFallbackEditor,
14762
- {
14763
- className: "min-h-full bg-transparent p-5 dark:bg-transparent",
14764
- fallbacks: canvas.props.fallbacks,
14765
- props: canvas.props,
14766
- primaryServices: servicesMap,
14767
- eligibleServices: servicesMap,
14768
- settings: fallbackSettings,
14769
- initialServiceId: launch.initialServiceId,
14770
- onSettingsChange: handleSettingsChange,
14771
- onSave: handleSave
14772
- },
14773
- `${launch.source}:${String(launch.initialServiceId)}:${sessionId}`
14774
- )
14775
- }
16059
+ className: "h-full p-5",
16060
+ fallbacks: canvas.props.fallbacks,
16061
+ props: canvas.props,
16062
+ primaryServices: servicesMap,
16063
+ eligibleServices: servicesMap,
16064
+ settings: fallbackSettings,
16065
+ initialServiceId: launch.initialServiceId,
16066
+ onSettingsChange: handleSettingsChange,
16067
+ onSave: handleSave
16068
+ },
16069
+ `${launch.source}:${String(launch.initialServiceId)}:${sessionId}`
14776
16070
  ) })
14777
16071
  ]
14778
16072
  }
@@ -14789,7 +16083,7 @@ function useFallbackEditorModal() {
14789
16083
 
14790
16084
  // src/workspace/bottom-panel/index.tsx
14791
16085
  import { useCanvas as useCanvas21, useWorkspace as useWorkspace16 } from "@timeax/digital-service-engine/workspace";
14792
- import { useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo36, useRef as useRef12, useState as useState36 } from "react";
16086
+ import { useCallback as useCallback22, useEffect as useEffect26, useMemo as useMemo40, useRef as useRef12, useState as useState41 } from "react";
14793
16087
  import { FiEye as FiEye3, FiEyeOff as FiEyeOff2, FiSearch, FiTerminal as FiTerminal2, FiX as FiX6 } from "react-icons/fi";
14794
16088
  import { LuGripHorizontal, LuLayers3 } from "react-icons/lu";
14795
16089
  import { MdOutlineSync } from "react-icons/md";
@@ -14802,7 +16096,7 @@ import { FiInfo as FiInfo3, FiTrash2, FiX as FiX5 } from "react-icons/fi";
14802
16096
  import "@timeax/digital-service-engine/workspace";
14803
16097
  import { startTransition } from "react";
14804
16098
  import { FiAlertCircle as FiAlertCircle4, FiInfo as FiInfo2 } from "react-icons/fi";
14805
- import { jsx as jsx74 } from "react/jsx-runtime";
16099
+ import { jsx as jsx83 } from "react/jsx-runtime";
14806
16100
  var PANEL_MARGIN = 8;
14807
16101
  var PANEL_LEFT_KEY = "service-builder.bottom-panel.pos-x";
14808
16102
  var PANEL_BOTTOM_KEY = "service-builder.bottom-panel.pos-y";
@@ -14817,9 +16111,9 @@ function sameIds(a, b) {
14817
16111
  return a.length === b.length && a.every((value, index) => value === b[index]);
14818
16112
  }
14819
16113
  function iconForSeverity(severity) {
14820
- if (severity === "error") return /* @__PURE__ */ jsx74(FiAlertCircle4, { className: "text-lg text-rose-500" });
14821
- if (severity === "warning") return /* @__PURE__ */ jsx74(FiAlertCircle4, { className: "text-lg text-amber-500" });
14822
- return /* @__PURE__ */ jsx74(FiInfo2, { className: "text-lg text-sky-500" });
16114
+ if (severity === "error") return /* @__PURE__ */ jsx83(FiAlertCircle4, { className: "text-lg text-rose-500" });
16115
+ if (severity === "warning") return /* @__PURE__ */ jsx83(FiAlertCircle4, { className: "text-lg text-amber-500" });
16116
+ return /* @__PURE__ */ jsx83(FiInfo2, { className: "text-lg text-sky-500" });
14823
16117
  }
14824
16118
  function severityBadgeClassName(severity) {
14825
16119
  return cn(
@@ -15000,7 +16294,7 @@ function toNodeChip(canvas, id) {
15000
16294
  }
15001
16295
 
15002
16296
  // src/workspace/bottom-panel/console-tab.tsx
15003
- import { Fragment as Fragment15, jsx as jsx75, jsxs as jsxs54 } from "react/jsx-runtime";
16297
+ import { Fragment as Fragment16, jsx as jsx84, jsxs as jsxs62 } from "react/jsx-runtime";
15004
16298
  function ConsoleTab({
15005
16299
  errors,
15006
16300
  notices,
@@ -15029,21 +16323,21 @@ function ConsoleTab({
15029
16323
  ];
15030
16324
  const activeIntro = introState[subTab];
15031
16325
  const introCopy = getConsoleIntroCopy(subTab);
15032
- return /* @__PURE__ */ jsxs54("div", { className: "space-y-4", children: [
15033
- !activeIntro.closed ? /* @__PURE__ */ jsx75("div", { className: "rounded-2xl border border-sky-200/80 bg-sky-50/70 p-3 dark:border-sky-500/20 dark:bg-sky-500/10", children: /* @__PURE__ */ jsxs54("div", { className: "flex items-start justify-between gap-3", children: [
15034
- /* @__PURE__ */ jsxs54("div", { className: "min-w-0", children: [
15035
- /* @__PURE__ */ jsx75("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: introCopy.title }),
15036
- !activeIntro.minimized ? /* @__PURE__ */ jsxs54(Fragment15, { children: [
15037
- /* @__PURE__ */ jsx75("p", { className: "mt-1 text-xs text-slate-600 dark:text-slate-300", children: introCopy.description }),
15038
- /* @__PURE__ */ jsxs54("div", { className: "mt-2 flex flex-wrap items-center gap-2 text-[11px] text-slate-500 dark:text-slate-400", children: [
15039
- /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-white/80 px-2 py-0.5 dark:bg-slate-900/70", children: validating ? "Validating..." : "Console idle" }),
15040
- /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-white/80 px-2 py-0.5 dark:bg-slate-900/70", children: shortcutLabel }),
15041
- /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-white/80 px-2 py-0.5 dark:bg-slate-900/70", children: "Press Escape to close" })
16326
+ return /* @__PURE__ */ jsxs62("div", { className: "space-y-4", children: [
16327
+ !activeIntro.closed ? /* @__PURE__ */ jsx84("div", { className: "rounded-2xl border border-sky-200/80 bg-sky-50/70 p-3 dark:border-sky-500/20 dark:bg-sky-500/10", children: /* @__PURE__ */ jsxs62("div", { className: "flex items-start justify-between gap-3", children: [
16328
+ /* @__PURE__ */ jsxs62("div", { className: "min-w-0", children: [
16329
+ /* @__PURE__ */ jsx84("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: introCopy.title }),
16330
+ !activeIntro.minimized ? /* @__PURE__ */ jsxs62(Fragment16, { children: [
16331
+ /* @__PURE__ */ jsx84("p", { className: "mt-1 text-xs text-slate-600 dark:text-slate-300", children: introCopy.description }),
16332
+ /* @__PURE__ */ jsxs62("div", { className: "mt-2 flex flex-wrap items-center gap-2 text-[11px] text-slate-500 dark:text-slate-400", children: [
16333
+ /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-white/80 px-2 py-0.5 dark:bg-slate-900/70", children: validating ? "Validating..." : "Console idle" }),
16334
+ /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-white/80 px-2 py-0.5 dark:bg-slate-900/70", children: shortcutLabel }),
16335
+ /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-white/80 px-2 py-0.5 dark:bg-slate-900/70", children: "Press Escape to close" })
15042
16336
  ] })
15043
16337
  ] }) : null
15044
16338
  ] }),
15045
- /* @__PURE__ */ jsxs54("div", { className: "flex items-center gap-2 text-xs", children: [
15046
- /* @__PURE__ */ jsx75(
16339
+ /* @__PURE__ */ jsxs62("div", { className: "flex items-center gap-2 text-xs", children: [
16340
+ /* @__PURE__ */ jsx84(
15047
16341
  "button",
15048
16342
  {
15049
16343
  type: "button",
@@ -15052,7 +16346,7 @@ function ConsoleTab({
15052
16346
  children: activeIntro.minimized ? "Expand" : "Minimize"
15053
16347
  }
15054
16348
  ),
15055
- /* @__PURE__ */ jsx75(
16349
+ /* @__PURE__ */ jsx84(
15056
16350
  "button",
15057
16351
  {
15058
16352
  type: "button",
@@ -15063,9 +16357,9 @@ function ConsoleTab({
15063
16357
  )
15064
16358
  ] })
15065
16359
  ] }) }) : null,
15066
- /* @__PURE__ */ jsxs54("div", { className: "rounded-2xl border border-slate-200 bg-white/70 p-3 dark:border-slate-800 dark:bg-slate-950/40", children: [
15067
- /* @__PURE__ */ jsxs54("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
15068
- /* @__PURE__ */ jsx75("div", { className: "flex flex-wrap items-center gap-2", children: subTabs.map((tab) => /* @__PURE__ */ jsxs54(
16360
+ /* @__PURE__ */ jsxs62("div", { className: "rounded-2xl border border-slate-200 bg-white/70 p-3 dark:border-slate-800 dark:bg-slate-950/40", children: [
16361
+ /* @__PURE__ */ jsxs62("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
16362
+ /* @__PURE__ */ jsx84("div", { className: "flex flex-wrap items-center gap-2", children: subTabs.map((tab) => /* @__PURE__ */ jsxs62(
15069
16363
  "button",
15070
16364
  {
15071
16365
  type: "button",
@@ -15075,20 +16369,20 @@ function ConsoleTab({
15075
16369
  subTab === tab.id ? "bg-slate-900 text-white dark:bg-slate-100 dark:text-slate-900" : "bg-slate-100 text-slate-600 hover:bg-slate-200 dark:bg-slate-900 dark:text-slate-300 dark:hover:bg-slate-800"
15076
16370
  ),
15077
16371
  children: [
15078
- /* @__PURE__ */ jsx75("span", { children: tab.label }),
15079
- /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-black/10 px-1.5 py-0.5 text-[10px] dark:bg-white/10", children: tab.count })
16372
+ /* @__PURE__ */ jsx84("span", { children: tab.label }),
16373
+ /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-black/10 px-1.5 py-0.5 text-[10px] dark:bg-white/10", children: tab.count })
15080
16374
  ]
15081
16375
  },
15082
16376
  tab.id
15083
16377
  )) }),
15084
- subTab === "logs" && logRows.length ? /* @__PURE__ */ jsxs54(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => errors.clear("logs"), className: "h-8 rounded-xl px-3 text-xs", children: [
15085
- /* @__PURE__ */ jsx75(FiTrash2, {}),
16378
+ subTab === "logs" && logRows.length ? /* @__PURE__ */ jsxs62(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => errors.clear("logs"), className: "h-8 rounded-xl px-3 text-xs", children: [
16379
+ /* @__PURE__ */ jsx84(FiTrash2, {}),
15086
16380
  "Clear logs"
15087
16381
  ] }) : null
15088
16382
  ] }),
15089
- /* @__PURE__ */ jsxs54("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
15090
- /* @__PURE__ */ jsx75("span", { className: "text-[11px] font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Scope" }),
15091
- /* @__PURE__ */ jsx75(
16383
+ /* @__PURE__ */ jsxs62("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
16384
+ /* @__PURE__ */ jsx84("span", { className: "text-[11px] font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Scope" }),
16385
+ /* @__PURE__ */ jsx84(
15092
16386
  "button",
15093
16387
  {
15094
16388
  type: "button",
@@ -15100,7 +16394,7 @@ function ConsoleTab({
15100
16394
  children: "All items"
15101
16395
  }
15102
16396
  ),
15103
- /* @__PURE__ */ jsx75(
16397
+ /* @__PURE__ */ jsx84(
15104
16398
  "button",
15105
16399
  {
15106
16400
  type: "button",
@@ -15112,9 +16406,9 @@ function ConsoleTab({
15112
16406
  children: "Active node"
15113
16407
  }
15114
16408
  ),
15115
- subTab !== "logs" ? /* @__PURE__ */ jsxs54(Fragment15, { children: [
15116
- /* @__PURE__ */ jsx75("span", { className: "ml-2 text-[11px] font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Severity" }),
15117
- ["all", "error", "warning", "info"].map((option) => /* @__PURE__ */ jsx75(
16409
+ subTab !== "logs" ? /* @__PURE__ */ jsxs62(Fragment16, { children: [
16410
+ /* @__PURE__ */ jsx84("span", { className: "ml-2 text-[11px] font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Severity" }),
16411
+ ["all", "error", "warning", "info"].map((option) => /* @__PURE__ */ jsx84(
15118
16412
  "button",
15119
16413
  {
15120
16414
  type: "button",
@@ -15129,23 +16423,23 @@ function ConsoleTab({
15129
16423
  ))
15130
16424
  ] }) : null
15131
16425
  ] }),
15132
- scopeFilter === "activeNode" && !hasActiveSelection ? /* @__PURE__ */ jsx75("p", { className: "mt-2 text-xs text-amber-700 dark:text-amber-300", children: "No active node selected. Select a node to filter by active scope." }) : null
16426
+ scopeFilter === "activeNode" && !hasActiveSelection ? /* @__PURE__ */ jsx84("p", { className: "mt-2 text-xs text-amber-700 dark:text-amber-300", children: "No active node selected. Select a node to filter by active scope." }) : null
15133
16427
  ] }),
15134
- subTab === "validation" ? validationRows.length ? /* @__PURE__ */ jsx75("div", { className: "space-y-3", children: validationRows.map((row) => /* @__PURE__ */ jsx75(ValidationCard, { onNodeClick, row }, row.id)) }) : /* @__PURE__ */ jsx75(
16428
+ subTab === "validation" ? validationRows.length ? /* @__PURE__ */ jsx84("div", { className: "space-y-3", children: validationRows.map((row) => /* @__PURE__ */ jsx84(ValidationCard, { onNodeClick, row }, row.id)) }) : /* @__PURE__ */ jsx84(
15135
16429
  EmptyState,
15136
16430
  {
15137
16431
  title: "No validation rows for this filter",
15138
16432
  description: scopeFilter === "activeNode" ? "No validation rows match the current active node scope." : "No validation rows match the current severity filter."
15139
16433
  }
15140
16434
  ) : null,
15141
- subTab === "logs" ? logRows.length ? /* @__PURE__ */ jsx75("div", { className: "space-y-3", children: logRows.map((row) => /* @__PURE__ */ jsx75(LogCard, { row, onRemove: () => errors.removeLog(row.id) }, row.id)) }) : /* @__PURE__ */ jsx75(
16435
+ subTab === "logs" ? logRows.length ? /* @__PURE__ */ jsx84("div", { className: "space-y-3", children: logRows.map((row) => /* @__PURE__ */ jsx84(LogCard, { row, onRemove: () => errors.removeLog(row.id) }, row.id)) }) : /* @__PURE__ */ jsx84(
15142
16436
  EmptyState,
15143
16437
  {
15144
16438
  title: "No logs for this filter",
15145
16439
  description: scopeFilter === "activeNode" ? "No logs are linked to the current active node scope." : "No logs have been captured yet."
15146
16440
  }
15147
16441
  ) : null,
15148
- subTab === "notices" ? noticeRows.length ? /* @__PURE__ */ jsx75("div", { className: "space-y-3", children: noticeRows.map((row) => /* @__PURE__ */ jsx75(NoticeCard, { notice: row, onNodeClick }, row.id)) }) : /* @__PURE__ */ jsx75(
16442
+ subTab === "notices" ? noticeRows.length ? /* @__PURE__ */ jsx84("div", { className: "space-y-3", children: noticeRows.map((row) => /* @__PURE__ */ jsx84(NoticeCard, { notice: row, onNodeClick }, row.id)) }) : /* @__PURE__ */ jsx84(
15149
16443
  EmptyState,
15150
16444
  {
15151
16445
  title: "No notices for this filter",
@@ -15158,21 +16452,21 @@ function NoticeCard({ notice, onNodeClick }) {
15158
16452
  const canvas = useCanvas20();
15159
16453
  const targetNodeId = notice.target.scope === "node" ? notice.target.node_id : null;
15160
16454
  const targetChip = notice.target.scope === "node" ? toNodeChip(canvas, notice.target.node_id) : "Global notice";
15161
- return /* @__PURE__ */ jsx75("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-950/90", children: /* @__PURE__ */ jsxs54("div", { className: "flex items-start gap-3", children: [
15162
- /* @__PURE__ */ jsx75("div", { className: "mt-0.5", children: iconForSeverity(notice.severity) }),
15163
- /* @__PURE__ */ jsxs54("div", { className: "min-w-0 flex-1 space-y-2", children: [
15164
- /* @__PURE__ */ jsxs54("div", { className: "flex flex-wrap items-center gap-2", children: [
15165
- /* @__PURE__ */ jsx75("span", { className: severityBadgeClassName(notice.severity), children: notice.kind }),
15166
- /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-slate-600 uppercase dark:bg-slate-900 dark:text-slate-300", children: notice.type }),
15167
- /* @__PURE__ */ jsx75("span", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: notice.title })
16455
+ return /* @__PURE__ */ jsx84("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-950/90", children: /* @__PURE__ */ jsxs62("div", { className: "flex items-start gap-3", children: [
16456
+ /* @__PURE__ */ jsx84("div", { className: "mt-0.5", children: iconForSeverity(notice.severity) }),
16457
+ /* @__PURE__ */ jsxs62("div", { className: "min-w-0 flex-1 space-y-2", children: [
16458
+ /* @__PURE__ */ jsxs62("div", { className: "flex flex-wrap items-center gap-2", children: [
16459
+ /* @__PURE__ */ jsx84("span", { className: severityBadgeClassName(notice.severity), children: notice.kind }),
16460
+ /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-slate-600 uppercase dark:bg-slate-900 dark:text-slate-300", children: notice.type }),
16461
+ /* @__PURE__ */ jsx84("span", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: notice.title })
15168
16462
  ] }),
15169
- notice.description ? /* @__PURE__ */ jsx75("p", { className: "text-sm text-slate-600 dark:text-slate-300", children: notice.description }) : null,
15170
- notice.reason ? /* @__PURE__ */ jsxs54("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: [
16463
+ notice.description ? /* @__PURE__ */ jsx84("p", { className: "text-sm text-slate-600 dark:text-slate-300", children: notice.description }) : null,
16464
+ notice.reason ? /* @__PURE__ */ jsxs62("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: [
15171
16465
  "Reason: ",
15172
16466
  notice.reason
15173
16467
  ] }) : null,
15174
- /* @__PURE__ */ jsxs54("div", { className: "flex flex-wrap items-center gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
15175
- notice.target.scope === "node" ? /* @__PURE__ */ jsx75(
16468
+ /* @__PURE__ */ jsxs62("div", { className: "flex flex-wrap items-center gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
16469
+ notice.target.scope === "node" ? /* @__PURE__ */ jsx84(
15176
16470
  "button",
15177
16471
  {
15178
16472
  type: "button",
@@ -15180,13 +16474,13 @@ function NoticeCard({ notice, onNodeClick }) {
15180
16474
  className: "rounded-full bg-slate-100 px-2.5 py-1 text-xs text-slate-700 transition hover:bg-slate-200 dark:bg-slate-900 dark:text-slate-300 dark:hover:bg-slate-800",
15181
16475
  children: targetChip
15182
16476
  }
15183
- ) : /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-xs text-slate-700 dark:bg-slate-900 dark:text-slate-300", children: targetChip }),
15184
- notice.marked_at ? /* @__PURE__ */ jsx75("span", { children: new Date(notice.marked_at).toLocaleString() }) : null,
15185
- notice.icon ? /* @__PURE__ */ jsxs54("span", { children: [
16477
+ ) : /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-xs text-slate-700 dark:bg-slate-900 dark:text-slate-300", children: targetChip }),
16478
+ notice.marked_at ? /* @__PURE__ */ jsx84("span", { children: new Date(notice.marked_at).toLocaleString() }) : null,
16479
+ notice.icon ? /* @__PURE__ */ jsxs62("span", { children: [
15186
16480
  "Icon: ",
15187
16481
  notice.icon
15188
16482
  ] }) : null,
15189
- notice.color ? /* @__PURE__ */ jsxs54("span", { children: [
16483
+ notice.color ? /* @__PURE__ */ jsxs62("span", { children: [
15190
16484
  "Color: ",
15191
16485
  notice.color
15192
16486
  ] }) : null
@@ -15197,19 +16491,19 @@ function NoticeCard({ notice, onNodeClick }) {
15197
16491
  function ValidationCard({ row, onNodeClick }) {
15198
16492
  const canvas = useCanvas20();
15199
16493
  const scope = describeValidationScope(canvas, row);
15200
- return /* @__PURE__ */ jsx75(
16494
+ return /* @__PURE__ */ jsx84(
15201
16495
  "div",
15202
16496
  {
15203
16497
  className: "rounded-2xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-950/90",
15204
16498
  onClick: () => scope.length && canvas.api.setHighlighted(scope),
15205
- children: /* @__PURE__ */ jsxs54("div", { className: "flex items-start gap-3", children: [
15206
- /* @__PURE__ */ jsx75("div", { className: "mt-0.5", children: iconForSeverity(row.severity) }),
15207
- /* @__PURE__ */ jsxs54("div", { className: "min-w-0 flex-1", children: [
15208
- /* @__PURE__ */ jsxs54("div", { className: "flex flex-wrap items-center gap-2", children: [
15209
- /* @__PURE__ */ jsx75("span", { className: severityBadgeClassName(row.severity), children: row.code.replaceAll("_", " ") }),
15210
- /* @__PURE__ */ jsx75("span", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: row.message })
16499
+ children: /* @__PURE__ */ jsxs62("div", { className: "flex items-start gap-3", children: [
16500
+ /* @__PURE__ */ jsx84("div", { className: "mt-0.5", children: iconForSeverity(row.severity) }),
16501
+ /* @__PURE__ */ jsxs62("div", { className: "min-w-0 flex-1", children: [
16502
+ /* @__PURE__ */ jsxs62("div", { className: "flex flex-wrap items-center gap-2", children: [
16503
+ /* @__PURE__ */ jsx84("span", { className: severityBadgeClassName(row.severity), children: row.code.replaceAll("_", " ") }),
16504
+ /* @__PURE__ */ jsx84("span", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: row.message })
15211
16505
  ] }),
15212
- scope.length ? /* @__PURE__ */ jsx75("div", { className: "mt-3 flex flex-wrap gap-2", children: scope.map((item) => /* @__PURE__ */ jsx75(
16506
+ scope.length ? /* @__PURE__ */ jsx84("div", { className: "mt-3 flex flex-wrap gap-2", children: scope.map((item) => /* @__PURE__ */ jsx84(
15213
16507
  "span",
15214
16508
  {
15215
16509
  onClick: () => onNodeClick(row.nodeId),
@@ -15224,17 +16518,17 @@ function ValidationCard({ row, onNodeClick }) {
15224
16518
  );
15225
16519
  }
15226
16520
  function LogCard({ row, onRemove }) {
15227
- return /* @__PURE__ */ jsx75("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-950/90", children: /* @__PURE__ */ jsxs54("div", { className: "flex items-start gap-3", children: [
15228
- /* @__PURE__ */ jsx75("div", { className: "mt-0.5", children: /* @__PURE__ */ jsx75(FiInfo3, { className: "text-lg text-sky-500" }) }),
15229
- /* @__PURE__ */ jsxs54("div", { className: "min-w-0 flex-1", children: [
15230
- /* @__PURE__ */ jsxs54("div", { className: "flex flex-wrap items-center gap-2", children: [
15231
- /* @__PURE__ */ jsx75("span", { className: "rounded-full bg-sky-100 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-sky-700 uppercase dark:bg-sky-500/15 dark:text-sky-200", children: row.code ?? "log" }),
15232
- /* @__PURE__ */ jsx75("span", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: row.message })
16521
+ return /* @__PURE__ */ jsx84("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-950/90", children: /* @__PURE__ */ jsxs62("div", { className: "flex items-start gap-3", children: [
16522
+ /* @__PURE__ */ jsx84("div", { className: "mt-0.5", children: /* @__PURE__ */ jsx84(FiInfo3, { className: "text-lg text-sky-500" }) }),
16523
+ /* @__PURE__ */ jsxs62("div", { className: "min-w-0 flex-1", children: [
16524
+ /* @__PURE__ */ jsxs62("div", { className: "flex flex-wrap items-center gap-2", children: [
16525
+ /* @__PURE__ */ jsx84("span", { className: "rounded-full bg-sky-100 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-sky-700 uppercase dark:bg-sky-500/15 dark:text-sky-200", children: row.code ?? "log" }),
16526
+ /* @__PURE__ */ jsx84("span", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: row.message })
15233
16527
  ] }),
15234
- /* @__PURE__ */ jsxs54("div", { className: "mt-3 flex items-center justify-between gap-3 text-xs text-slate-500 dark:text-slate-400", children: [
15235
- /* @__PURE__ */ jsx75("span", { children: new Date(row.createdAt).toLocaleTimeString() }),
15236
- /* @__PURE__ */ jsxs54(Button, { type: "button", variant: "ghost", size: "sm", onClick: onRemove, className: "h-7 rounded-xl px-2 text-xs", children: [
15237
- /* @__PURE__ */ jsx75(FiX5, {}),
16528
+ /* @__PURE__ */ jsxs62("div", { className: "mt-3 flex items-center justify-between gap-3 text-xs text-slate-500 dark:text-slate-400", children: [
16529
+ /* @__PURE__ */ jsx84("span", { children: new Date(row.createdAt).toLocaleTimeString() }),
16530
+ /* @__PURE__ */ jsxs62(Button, { type: "button", variant: "ghost", size: "sm", onClick: onRemove, className: "h-7 rounded-xl px-2 text-xs", children: [
16531
+ /* @__PURE__ */ jsx84(FiX5, {}),
15238
16532
  "Dismiss"
15239
16533
  ] })
15240
16534
  ] })
@@ -15243,8 +16537,8 @@ function LogCard({ row, onRemove }) {
15243
16537
  }
15244
16538
 
15245
16539
  // src/workspace/bottom-panel/service-picker-dialog.tsx
15246
- import { InputField as InputField16 } from "@timeax/form-palette";
15247
- import { useEffect as useEffect22, useMemo as useMemo35, useState as useState34 } from "react";
16540
+ import { InputField as InputField19 } from "@timeax/form-palette";
16541
+ import { useEffect as useEffect24, useMemo as useMemo39, useState as useState39 } from "react";
15248
16542
  import { createPortal as createPortal5 } from "react-dom";
15249
16543
 
15250
16544
  // src/workspace/bottom-panel/service-picker.ts
@@ -15362,7 +16656,7 @@ function isScalar(value) {
15362
16656
  }
15363
16657
 
15364
16658
  // src/workspace/bottom-panel/service-picker-dialog.tsx
15365
- import { jsx as jsx76, jsxs as jsxs55 } from "react/jsx-runtime";
16659
+ import { jsx as jsx85, jsxs as jsxs63 } from "react/jsx-runtime";
15366
16660
  function ServicePickerDialog({
15367
16661
  open,
15368
16662
  groupLabel,
@@ -15373,14 +16667,14 @@ function ServicePickerDialog({
15373
16667
  onOpenChange,
15374
16668
  onConfirm
15375
16669
  }) {
15376
- const [filters, setFilters] = useState34(() => createDefaultServicePickerFilters());
15377
- const [selectedIds, setSelectedIds] = useState34(/* @__PURE__ */ new Set());
15378
- useEffect22(() => {
16670
+ const [filters, setFilters] = useState39(() => createDefaultServicePickerFilters());
16671
+ const [selectedIds, setSelectedIds] = useState39(/* @__PURE__ */ new Set());
16672
+ useEffect24(() => {
15379
16673
  if (!open) return;
15380
16674
  setFilters(createDefaultServicePickerFilters());
15381
16675
  setSelectedIds(/* @__PURE__ */ new Set());
15382
16676
  }, [open]);
15383
- useEffect22(() => {
16677
+ useEffect24(() => {
15384
16678
  if (!open) return;
15385
16679
  const onKeyDown = (event) => {
15386
16680
  if (event.key === "Escape") onOpenChange(false);
@@ -15388,14 +16682,14 @@ function ServicePickerDialog({
15388
16682
  window.addEventListener("keydown", onKeyDown);
15389
16683
  return () => window.removeEventListener("keydown", onKeyDown);
15390
16684
  }, [onOpenChange, open]);
15391
- const categories = useMemo35(
16685
+ const categories = useMemo39(
15392
16686
  () => Array.from(new Set(services2.map((service) => service.category).filter(Boolean))).sort((a, b) => a.localeCompare(b)),
15393
16687
  [services2]
15394
16688
  );
15395
- const flags = useMemo35(() => Array.from(new Set(services2.flatMap((service) => service.flags))).sort((a, b) => a.localeCompare(b)), [services2]);
15396
- const metaPaths = useMemo35(() => discoverServiceMetaPaths(Object.values(serviceMap)), [serviceMap]);
16689
+ const flags = useMemo39(() => Array.from(new Set(services2.flatMap((service) => service.flags))).sort((a, b) => a.localeCompare(b)), [services2]);
16690
+ const metaPaths = useMemo39(() => discoverServiceMetaPaths(Object.values(serviceMap)), [serviceMap]);
15397
16691
  const metaValues = metaPaths.find((entry) => entry.path === filters.metaPath)?.values ?? [];
15398
- const filteredServices = useMemo35(
16692
+ const filteredServices = useMemo39(
15399
16693
  () => filterServicePickerServices({
15400
16694
  services: services2,
15401
16695
  serviceMap,
@@ -15408,7 +16702,7 @@ function ServicePickerDialog({
15408
16702
  const selectedCount = selectedIds.size;
15409
16703
  const canConfirm = selectedCount > 0;
15410
16704
  return createPortal5(
15411
- /* @__PURE__ */ jsx76("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-slate-950/45 p-4", children: /* @__PURE__ */ jsxs55(
16705
+ /* @__PURE__ */ jsx85("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-slate-950/45 p-4", children: /* @__PURE__ */ jsxs63(
15412
16706
  "div",
15413
16707
  {
15414
16708
  role: "dialog",
@@ -15416,17 +16710,17 @@ function ServicePickerDialog({
15416
16710
  "aria-label": "Service picker",
15417
16711
  className: "flex h-[min(80vh,42rem)] w-[min(72rem,calc(100vw-2rem))] flex-col overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-2xl dark:border-slate-800 dark:bg-slate-950",
15418
16712
  children: [
15419
- /* @__PURE__ */ jsx76("div", { className: "border-b border-slate-200 px-5 py-4 dark:border-slate-800", children: /* @__PURE__ */ jsxs55("div", { className: "flex items-start justify-between gap-4", children: [
15420
- /* @__PURE__ */ jsxs55("div", { children: [
15421
- /* @__PURE__ */ jsx76("h3", { className: "text-lg font-semibold text-slate-900 dark:text-slate-100", children: "Assign services to group" }),
15422
- /* @__PURE__ */ jsx76("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: groupLabel ? `Pick one or more services to append into ${groupLabel}.` : "Pick one or more services to append into the selected catalog group." })
16713
+ /* @__PURE__ */ jsx85("div", { className: "border-b border-slate-200 px-5 py-4 dark:border-slate-800", children: /* @__PURE__ */ jsxs63("div", { className: "flex items-start justify-between gap-4", children: [
16714
+ /* @__PURE__ */ jsxs63("div", { children: [
16715
+ /* @__PURE__ */ jsx85("h3", { className: "text-lg font-semibold text-slate-900 dark:text-slate-100", children: "Assign services to group" }),
16716
+ /* @__PURE__ */ jsx85("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: groupLabel ? `Pick one or more services to append into ${groupLabel}.` : "Pick one or more services to append into the selected catalog group." })
15423
16717
  ] }),
15424
- /* @__PURE__ */ jsx76(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), className: "rounded-xl", children: "Close" })
16718
+ /* @__PURE__ */ jsx85(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), className: "rounded-xl", children: "Close" })
15425
16719
  ] }) }),
15426
- /* @__PURE__ */ jsxs55("div", { className: "grid h-full min-h-0 flex-1 overflow-hidden md:grid-cols-[18rem_minmax(0,1fr)]", children: [
15427
- /* @__PURE__ */ jsx76("div", { className: "min-h-0 border-r border-slate-200 dark:border-slate-800", children: /* @__PURE__ */ jsx76(ScrollArea, { className: "h-full min-h-0", children: /* @__PURE__ */ jsxs55("div", { className: "space-y-4 p-4", children: [
15428
- /* @__PURE__ */ jsx76(FilterField, { label: "Search", children: /* @__PURE__ */ jsx76(
15429
- InputField16,
16720
+ /* @__PURE__ */ jsxs63("div", { className: "grid h-full min-h-0 flex-1 overflow-hidden md:grid-cols-[18rem_minmax(0,1fr)]", children: [
16721
+ /* @__PURE__ */ jsx85("div", { className: "min-h-0 border-r border-slate-200 dark:border-slate-800", children: /* @__PURE__ */ jsx85(ScrollArea, { className: "h-full min-h-0", children: /* @__PURE__ */ jsxs63("div", { className: "space-y-4 p-4", children: [
16722
+ /* @__PURE__ */ jsx85(FilterField, { label: "Search", children: /* @__PURE__ */ jsx85(
16723
+ InputField19,
15430
16724
  {
15431
16725
  variant: "text",
15432
16726
  label: "Picker search",
@@ -15436,8 +16730,8 @@ function ServicePickerDialog({
15436
16730
  autoComplete: "off"
15437
16731
  }
15438
16732
  ) }),
15439
- /* @__PURE__ */ jsx76(FilterField, { label: "Category", children: /* @__PURE__ */ jsx76(
15440
- InputField16,
16733
+ /* @__PURE__ */ jsx85(FilterField, { label: "Category", children: /* @__PURE__ */ jsx85(
16734
+ InputField19,
15441
16735
  {
15442
16736
  variant: "select",
15443
16737
  label: "Category filter",
@@ -15447,8 +16741,8 @@ function ServicePickerDialog({
15447
16741
  onChange: (event) => setFilters((current) => ({ ...current, category: String(event.value ?? "") }))
15448
16742
  }
15449
16743
  ) }),
15450
- /* @__PURE__ */ jsx76(FilterField, { label: "Flag", children: /* @__PURE__ */ jsx76(
15451
- InputField16,
16744
+ /* @__PURE__ */ jsx85(FilterField, { label: "Flag", children: /* @__PURE__ */ jsx85(
16745
+ InputField19,
15452
16746
  {
15453
16747
  variant: "select",
15454
16748
  label: "Flag filter",
@@ -15458,8 +16752,8 @@ function ServicePickerDialog({
15458
16752
  onChange: (event) => setFilters((current) => ({ ...current, flag: String(event.value ?? "") }))
15459
16753
  }
15460
16754
  ) }),
15461
- /* @__PURE__ */ jsx76(FilterField, { label: "Activity", children: /* @__PURE__ */ jsx76(
15462
- InputField16,
16755
+ /* @__PURE__ */ jsx85(FilterField, { label: "Activity", children: /* @__PURE__ */ jsx85(
16756
+ InputField19,
15463
16757
  {
15464
16758
  variant: "select",
15465
16759
  label: "Activity filter",
@@ -15475,9 +16769,9 @@ function ServicePickerDialog({
15475
16769
  }))
15476
16770
  }
15477
16771
  ) }),
15478
- /* @__PURE__ */ jsxs55("div", { className: "grid grid-cols-2 gap-2", children: [
15479
- /* @__PURE__ */ jsx76(FilterField, { label: "Min rate", children: /* @__PURE__ */ jsx76(
15480
- InputField16,
16772
+ /* @__PURE__ */ jsxs63("div", { className: "grid grid-cols-2 gap-2", children: [
16773
+ /* @__PURE__ */ jsx85(FilterField, { label: "Min rate", children: /* @__PURE__ */ jsx85(
16774
+ InputField19,
15481
16775
  {
15482
16776
  variant: "number",
15483
16777
  label: "Minimum rate filter",
@@ -15487,8 +16781,8 @@ function ServicePickerDialog({
15487
16781
  autoComplete: "off"
15488
16782
  }
15489
16783
  ) }),
15490
- /* @__PURE__ */ jsx76(FilterField, { label: "Max rate", children: /* @__PURE__ */ jsx76(
15491
- InputField16,
16784
+ /* @__PURE__ */ jsx85(FilterField, { label: "Max rate", children: /* @__PURE__ */ jsx85(
16785
+ InputField19,
15492
16786
  {
15493
16787
  variant: "number",
15494
16788
  label: "Maximum rate filter",
@@ -15499,9 +16793,9 @@ function ServicePickerDialog({
15499
16793
  }
15500
16794
  ) })
15501
16795
  ] }),
15502
- /* @__PURE__ */ jsx76(FilterField, { label: "Name keyword", children: /* @__PURE__ */ jsxs55("div", { className: "space-y-2", children: [
15503
- /* @__PURE__ */ jsx76(
15504
- InputField16,
16796
+ /* @__PURE__ */ jsx85(FilterField, { label: "Name keyword", children: /* @__PURE__ */ jsxs63("div", { className: "space-y-2", children: [
16797
+ /* @__PURE__ */ jsx85(
16798
+ InputField19,
15505
16799
  {
15506
16800
  variant: "select",
15507
16801
  label: "Keyword mode",
@@ -15516,8 +16810,8 @@ function ServicePickerDialog({
15516
16810
  }))
15517
16811
  }
15518
16812
  ),
15519
- /* @__PURE__ */ jsx76(
15520
- InputField16,
16813
+ /* @__PURE__ */ jsx85(
16814
+ InputField19,
15521
16815
  {
15522
16816
  variant: "text",
15523
16817
  label: "Keyword filter",
@@ -15528,8 +16822,8 @@ function ServicePickerDialog({
15528
16822
  }
15529
16823
  )
15530
16824
  ] }) }),
15531
- /* @__PURE__ */ jsx76(FilterField, { label: "Meta key", children: /* @__PURE__ */ jsx76(
15532
- InputField16,
16825
+ /* @__PURE__ */ jsx85(FilterField, { label: "Meta key", children: /* @__PURE__ */ jsx85(
16826
+ InputField19,
15533
16827
  {
15534
16828
  variant: "select",
15535
16829
  label: "Meta key filter",
@@ -15543,8 +16837,8 @@ function ServicePickerDialog({
15543
16837
  }))
15544
16838
  }
15545
16839
  ) }),
15546
- /* @__PURE__ */ jsx76(FilterField, { label: "Meta value", children: /* @__PURE__ */ jsx76(
15547
- InputField16,
16840
+ /* @__PURE__ */ jsx85(FilterField, { label: "Meta value", children: /* @__PURE__ */ jsx85(
16841
+ InputField19,
15548
16842
  {
15549
16843
  variant: "select",
15550
16844
  label: "Meta value filter",
@@ -15555,7 +16849,7 @@ function ServicePickerDialog({
15555
16849
  onChange: (event) => setFilters((current) => ({ ...current, metaValue: String(event.value ?? "") }))
15556
16850
  }
15557
16851
  ) }),
15558
- /* @__PURE__ */ jsx76("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx76(
16852
+ /* @__PURE__ */ jsx85("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx85(
15559
16853
  Button,
15560
16854
  {
15561
16855
  type: "button",
@@ -15570,18 +16864,18 @@ function ServicePickerDialog({
15570
16864
  }
15571
16865
  ) })
15572
16866
  ] }) }) }),
15573
- /* @__PURE__ */ jsxs55("div", { className: "flex min-h-0 flex-col overflow-hidden", children: [
15574
- /* @__PURE__ */ jsxs55("div", { className: "border-b border-slate-200 px-4 py-3 text-sm text-slate-500 dark:border-slate-800 dark:text-slate-400", children: [
16867
+ /* @__PURE__ */ jsxs63("div", { className: "flex min-h-0 flex-col overflow-hidden", children: [
16868
+ /* @__PURE__ */ jsxs63("div", { className: "border-b border-slate-200 px-4 py-3 text-sm text-slate-500 dark:border-slate-800 dark:text-slate-400", children: [
15575
16869
  filteredServices.length,
15576
16870
  " service",
15577
16871
  filteredServices.length === 1 ? "" : "s",
15578
16872
  " found"
15579
16873
  ] }),
15580
- /* @__PURE__ */ jsx76(ScrollArea, { className: "h-full min-h-0 flex-1", children: /* @__PURE__ */ jsx76("div", { className: "space-y-2 p-4", children: filteredServices.length ? filteredServices.map((service) => {
16874
+ /* @__PURE__ */ jsx85(ScrollArea, { className: "h-full min-h-0 flex-1", children: /* @__PURE__ */ jsx85("div", { className: "space-y-2 p-4", children: filteredServices.length ? filteredServices.map((service) => {
15581
16875
  const id = String(service.id);
15582
16876
  const selected = selectedIds.has(id);
15583
16877
  const alreadyAssigned = existingGroupServiceIds.has(id);
15584
- return /* @__PURE__ */ jsxs55(
16878
+ return /* @__PURE__ */ jsxs63(
15585
16879
  "label",
15586
16880
  {
15587
16881
  className: cn(
@@ -15589,7 +16883,7 @@ function ServicePickerDialog({
15589
16883
  selected ? "border-blue-300 bg-blue-50 dark:border-blue-500/40 dark:bg-blue-500/10" : "border-slate-200 bg-white hover:border-slate-300 hover:bg-slate-50 dark:border-slate-800 dark:bg-slate-950/60 dark:hover:border-slate-700"
15590
16884
  ),
15591
16885
  children: [
15592
- /* @__PURE__ */ jsx76(
16886
+ /* @__PURE__ */ jsx85(
15593
16887
  "input",
15594
16888
  {
15595
16889
  type: "checkbox",
@@ -15603,21 +16897,21 @@ function ServicePickerDialog({
15603
16897
  })
15604
16898
  }
15605
16899
  ),
15606
- /* @__PURE__ */ jsxs55("div", { className: "min-w-0 flex-1", children: [
15607
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center justify-between gap-3", children: [
15608
- /* @__PURE__ */ jsxs55("div", { className: "min-w-0", children: [
15609
- /* @__PURE__ */ jsx76("div", { className: "truncate text-sm font-semibold text-slate-900 dark:text-slate-100", children: service.name }),
15610
- /* @__PURE__ */ jsxs55("div", { className: "mt-1 flex flex-wrap gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
15611
- /* @__PURE__ */ jsxs55("span", { children: [
16900
+ /* @__PURE__ */ jsxs63("div", { className: "min-w-0 flex-1", children: [
16901
+ /* @__PURE__ */ jsxs63("div", { className: "flex items-center justify-between gap-3", children: [
16902
+ /* @__PURE__ */ jsxs63("div", { className: "min-w-0", children: [
16903
+ /* @__PURE__ */ jsx85("div", { className: "truncate text-sm font-semibold text-slate-900 dark:text-slate-100", children: service.name }),
16904
+ /* @__PURE__ */ jsxs63("div", { className: "mt-1 flex flex-wrap gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
16905
+ /* @__PURE__ */ jsxs63("span", { children: [
15612
16906
  "#",
15613
16907
  service.id
15614
16908
  ] }),
15615
- service.category ? /* @__PURE__ */ jsx76("span", { children: service.category }) : null,
15616
- service.platformId ? /* @__PURE__ */ jsx76("span", { children: service.platformId }) : null
16909
+ service.category ? /* @__PURE__ */ jsx85("span", { children: service.category }) : null,
16910
+ service.platformId ? /* @__PURE__ */ jsx85("span", { children: service.platformId }) : null
15617
16911
  ] })
15618
16912
  ] }),
15619
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
15620
- /* @__PURE__ */ jsx76(
16913
+ /* @__PURE__ */ jsxs63("div", { className: "flex items-center gap-2", children: [
16914
+ /* @__PURE__ */ jsx85(
15621
16915
  ServiceMetaPopover,
15622
16916
  {
15623
16917
  meta: serviceMap[id]?.meta,
@@ -15625,34 +16919,34 @@ function ServicePickerDialog({
15625
16919
  stopEventPropagation: true
15626
16920
  }
15627
16921
  ),
15628
- alreadyAssigned ? /* @__PURE__ */ jsx76("span", { className: "rounded-full bg-emerald-50 px-2.5 py-1 text-[11px] text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-200", children: "Already in group" }) : null
16922
+ alreadyAssigned ? /* @__PURE__ */ jsx85("span", { className: "rounded-full bg-emerald-50 px-2.5 py-1 text-[11px] text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-200", children: "Already in group" }) : null
15629
16923
  ] })
15630
16924
  ] }),
15631
- /* @__PURE__ */ jsxs55("div", { className: "mt-3 flex flex-wrap gap-2", children: [
15632
- service.rate != null ? /* @__PURE__ */ jsxs55("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600 dark:bg-slate-900 dark:text-slate-300", children: [
16925
+ /* @__PURE__ */ jsxs63("div", { className: "mt-3 flex flex-wrap gap-2", children: [
16926
+ service.rate != null ? /* @__PURE__ */ jsxs63("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600 dark:bg-slate-900 dark:text-slate-300", children: [
15633
16927
  "Rate ",
15634
16928
  service.rate
15635
16929
  ] }) : null,
15636
- service.flags.slice(0, 3).map((flag) => /* @__PURE__ */ jsx76("span", { className: "rounded-full bg-amber-50 px-2.5 py-1 text-[11px] text-amber-700 dark:bg-amber-500/10 dark:text-amber-200", children: flag }, flag))
16930
+ service.flags.slice(0, 3).map((flag) => /* @__PURE__ */ jsx85("span", { className: "rounded-full bg-amber-50 px-2.5 py-1 text-[11px] text-amber-700 dark:bg-amber-500/10 dark:text-amber-200", children: flag }, flag))
15637
16931
  ] })
15638
16932
  ] })
15639
16933
  ]
15640
16934
  },
15641
16935
  id
15642
16936
  );
15643
- }) : /* @__PURE__ */ jsx76("div", { className: "rounded-2xl border border-dashed border-slate-300 px-4 py-10 text-center text-sm text-slate-500 dark:border-slate-700 dark:text-slate-400", children: "No services match the current filters." }) }) })
16937
+ }) : /* @__PURE__ */ jsx85("div", { className: "rounded-2xl border border-dashed border-slate-300 px-4 py-10 text-center text-sm text-slate-500 dark:border-slate-700 dark:text-slate-400", children: "No services match the current filters." }) }) })
15644
16938
  ] })
15645
16939
  ] }),
15646
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center justify-between gap-3 border-t border-slate-200 px-5 py-4 dark:border-slate-800", children: [
15647
- /* @__PURE__ */ jsxs55("div", { className: "text-sm text-slate-500 dark:text-slate-400", children: [
16940
+ /* @__PURE__ */ jsxs63("div", { className: "flex items-center justify-between gap-3 border-t border-slate-200 px-5 py-4 dark:border-slate-800", children: [
16941
+ /* @__PURE__ */ jsxs63("div", { className: "text-sm text-slate-500 dark:text-slate-400", children: [
15648
16942
  selectedCount,
15649
16943
  " service",
15650
16944
  selectedCount === 1 ? "" : "s",
15651
16945
  " selected"
15652
16946
  ] }),
15653
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
15654
- /* @__PURE__ */ jsx76(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), className: "rounded-xl", children: "Cancel" }),
15655
- /* @__PURE__ */ jsx76(
16947
+ /* @__PURE__ */ jsxs63("div", { className: "flex items-center gap-2", children: [
16948
+ /* @__PURE__ */ jsx85(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), className: "rounded-xl", children: "Cancel" }),
16949
+ /* @__PURE__ */ jsx85(
15656
16950
  Button,
15657
16951
  {
15658
16952
  type: "button",
@@ -15674,8 +16968,8 @@ function ServicePickerDialog({
15674
16968
  );
15675
16969
  }
15676
16970
  function FilterField({ label, children }) {
15677
- return /* @__PURE__ */ jsxs55("label", { className: "block space-y-1.5", children: [
15678
- /* @__PURE__ */ jsx76("span", { className: "text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400", children: label }),
16971
+ return /* @__PURE__ */ jsxs63("label", { className: "block space-y-1.5", children: [
16972
+ /* @__PURE__ */ jsx85("span", { className: "text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400", children: label }),
15679
16973
  children
15680
16974
  ] });
15681
16975
  }
@@ -15686,73 +16980,36 @@ function toPickerSelectOptions(values) {
15686
16980
  }));
15687
16981
  }
15688
16982
 
15689
- // src/components/ui/resizable.tsx
15690
- import { GripVertical } from "lucide-react";
15691
- import "react";
15692
- import { Group as Group2, Panel as Panel3, Separator as Separator3 } from "react-resizable-panels";
15693
- import { jsx as jsx77 } from "react/jsx-runtime";
15694
- function ResizablePanelGroup({
15695
- className,
15696
- direction = "horizontal",
15697
- ...props
15698
- }) {
15699
- return /* @__PURE__ */ jsx77(Group2, { className: cn("flex h-full w-full data-[group-orientation=vertical]:flex-col", className), orientation: direction, ...props });
15700
- }
15701
- function ResizablePanel({
15702
- className,
15703
- ...props
15704
- }) {
15705
- return /* @__PURE__ */ jsx77(Panel3, { className: cn("min-h-0 min-w-0", className), ...props });
15706
- }
15707
- function ResizableHandle({
15708
- withHandle,
15709
- className,
15710
- ...props
15711
- }) {
15712
- return /* @__PURE__ */ jsx77(
15713
- Separator3,
15714
- {
15715
- className: cn(
15716
- "relative flex w-3 shrink-0 items-center justify-center bg-transparent outline-none transition-colors after:absolute after:inset-y-3 after:left-1/2 after:w-px after:-translate-x-1/2 after:rounded-full after:bg-slate-200 dark:after:bg-slate-800",
15717
- "hover:after:bg-slate-300 dark:hover:after:bg-slate-700",
15718
- className
15719
- ),
15720
- ...props,
15721
- children: withHandle ? /* @__PURE__ */ jsx77("div", { className: "z-10 flex h-10 w-3 items-center justify-center rounded-full border border-slate-200 bg-white text-slate-400 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-500", children: /* @__PURE__ */ jsx77(GripVertical, { className: "h-3.5 w-3.5" }) }) : null
15722
- }
15723
- );
15724
- }
15725
-
15726
16983
  // src/workspace/bottom-panel/services-split-pane.tsx
15727
- import { InputField as InputField17 } from "@timeax/form-palette";
15728
- import { useEffect as useEffect23, useState as useState35 } from "react";
16984
+ import { InputField as InputField20 } from "@timeax/form-palette";
16985
+ import { useEffect as useEffect25, useState as useState40 } from "react";
15729
16986
  import { FaFolderOpen as FaFolderOpen2 } from "react-icons/fa";
15730
16987
  import { FiEdit2, FiFilter as FiFilter2, FiFolderPlus, FiPlus as FiPlus2, FiTrash2 as FiTrash22 } from "react-icons/fi";
15731
16988
 
15732
16989
  // src/workspace/bottom-panel/service-detail-card.tsx
15733
- import { jsx as jsx78, jsxs as jsxs56 } from "react/jsx-runtime";
16990
+ import { jsx as jsx86, jsxs as jsxs64 } from "react/jsx-runtime";
15734
16991
  function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQuickAdd, onOpenFallbackEditor }) {
15735
16992
  const summary = row.summary;
15736
16993
  const service = row.service;
15737
- return /* @__PURE__ */ jsxs56("div", { className: "space-y-5", children: [
15738
- /* @__PURE__ */ jsxs56("div", { className: "rounded-3xl border border-slate-200 bg-slate-50/80 p-5 dark:border-slate-800 dark:bg-slate-900/40", children: [
15739
- /* @__PURE__ */ jsxs56("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
15740
- /* @__PURE__ */ jsxs56("div", { className: "min-w-0", children: [
15741
- /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2", children: [
15742
- /* @__PURE__ */ jsx78(StatusDot, { tone: row.statusTone, className: "mt-0.5" }),
15743
- /* @__PURE__ */ jsxs56("span", { children: [
16994
+ return /* @__PURE__ */ jsxs64("div", { className: "space-y-5", children: [
16995
+ /* @__PURE__ */ jsxs64("div", { className: "rounded-3xl border border-slate-200 bg-slate-50/80 p-5 dark:border-slate-800 dark:bg-slate-900/40", children: [
16996
+ /* @__PURE__ */ jsxs64("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
16997
+ /* @__PURE__ */ jsxs64("div", { className: "min-w-0", children: [
16998
+ /* @__PURE__ */ jsxs64("div", { className: "flex items-center gap-2", children: [
16999
+ /* @__PURE__ */ jsx86(StatusDot, { tone: row.statusTone, className: "mt-0.5" }),
17000
+ /* @__PURE__ */ jsxs64("span", { children: [
15744
17001
  "#",
15745
17002
  summary.id
15746
17003
  ] })
15747
17004
  ] }),
15748
- /* @__PURE__ */ jsxs56("div", { className: "mt-2 flex flex-wrap gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
15749
- summary.category ? /* @__PURE__ */ jsx78("span", { children: summary.category }) : null,
15750
- summary.platformId ? /* @__PURE__ */ jsx78("span", { children: summary.platformId }) : null
17005
+ /* @__PURE__ */ jsxs64("div", { className: "mt-2 flex flex-wrap gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
17006
+ summary.category ? /* @__PURE__ */ jsx86("span", { children: summary.category }) : null,
17007
+ summary.platformId ? /* @__PURE__ */ jsx86("span", { children: summary.platformId }) : null
15751
17008
  ] })
15752
17009
  ] }),
15753
- /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2", children: [
15754
- /* @__PURE__ */ jsx78(ServiceMetaPopover, { meta: service?.meta }),
15755
- mode === "active" && onOpenFallbackQuickAdd ? /* @__PURE__ */ jsx78(
17010
+ /* @__PURE__ */ jsxs64("div", { className: "flex items-center gap-2", children: [
17011
+ /* @__PURE__ */ jsx86(ServiceMetaPopover, { meta: service?.meta }),
17012
+ mode === "active" && onOpenFallbackQuickAdd ? /* @__PURE__ */ jsx86(
15756
17013
  "button",
15757
17014
  {
15758
17015
  type: "button",
@@ -15761,7 +17018,7 @@ function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQui
15761
17018
  children: "Add fallbacks"
15762
17019
  }
15763
17020
  ) : null,
15764
- mode === "active" && onOpenFallbackEditor ? /* @__PURE__ */ jsx78(
17021
+ mode === "active" && onOpenFallbackEditor ? /* @__PURE__ */ jsx86(
15765
17022
  "button",
15766
17023
  {
15767
17024
  type: "button",
@@ -15770,41 +17027,41 @@ function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQui
15770
17027
  children: "Open fallback editor"
15771
17028
  }
15772
17029
  ) : null,
15773
- /* @__PURE__ */ jsx78("span", { className: statusBadgeClassName(row.statusTone), children: row.statusLabel })
17030
+ /* @__PURE__ */ jsx86("span", { className: statusBadgeClassName(row.statusTone), children: row.statusLabel })
15774
17031
  ] })
15775
17032
  ] }),
15776
- /* @__PURE__ */ jsxs56("div", { className: "mt-4 grid gap-3 sm:grid-cols-2", children: [
15777
- /* @__PURE__ */ jsx78(DetailMetric, { label: "Rate", value: summary.rate != null ? String(summary.rate) : "Not set" }),
15778
- /* @__PURE__ */ jsx78(DetailMetric, { label: "Estimate", value: summary.estimate ?? "No estimate" }),
15779
- /* @__PURE__ */ jsx78(DetailMetric, { label: "Min", value: summary.min != null ? String(summary.min) : "0" }),
15780
- /* @__PURE__ */ jsx78(DetailMetric, { label: "Max", value: summary.max != null ? String(summary.max) : "Unlimited" })
17033
+ /* @__PURE__ */ jsxs64("div", { className: "mt-4 grid gap-3 sm:grid-cols-2", children: [
17034
+ /* @__PURE__ */ jsx86(DetailMetric, { label: "Rate", value: summary.rate != null ? String(summary.rate) : "Not set" }),
17035
+ /* @__PURE__ */ jsx86(DetailMetric, { label: "Estimate", value: summary.estimate ?? "No estimate" }),
17036
+ /* @__PURE__ */ jsx86(DetailMetric, { label: "Min", value: summary.min != null ? String(summary.min) : "0" }),
17037
+ /* @__PURE__ */ jsx86(DetailMetric, { label: "Max", value: summary.max != null ? String(summary.max) : "Unlimited" })
15781
17038
  ] })
15782
17039
  ] }),
15783
- mode !== "active" ? /* @__PURE__ */ jsxs56("section", { className: "space-y-3", children: [
15784
- /* @__PURE__ */ jsx78(
17040
+ mode !== "active" ? /* @__PURE__ */ jsxs64("section", { className: "space-y-3", children: [
17041
+ /* @__PURE__ */ jsx86(
15785
17042
  SectionTitle2,
15786
17043
  {
15787
17044
  title: "Context fit",
15788
17045
  description: mode === "catalog" ? "This summary shows how the service fits the current visible-group context while browsing catalog groups." : "This summary shows how the service fits the current visible-group context."
15789
17046
  }
15790
17047
  ),
15791
- /* @__PURE__ */ jsxs56("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/80", children: [
15792
- /* @__PURE__ */ jsxs56("div", { className: "flex flex-wrap gap-2", children: [
15793
- /* @__PURE__ */ jsx78(
17048
+ /* @__PURE__ */ jsxs64("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/80", children: [
17049
+ /* @__PURE__ */ jsxs64("div", { className: "flex flex-wrap gap-2", children: [
17050
+ /* @__PURE__ */ jsx86(
15794
17051
  FilterChip,
15795
17052
  {
15796
17053
  label: row.check?.fitsConstraints ? "Constraints fit" : "Constraint mismatch",
15797
17054
  tone: row.check?.fitsConstraints ? "success" : "danger"
15798
17055
  }
15799
17056
  ),
15800
- /* @__PURE__ */ jsx78(
17057
+ /* @__PURE__ */ jsx86(
15801
17058
  FilterChip,
15802
17059
  {
15803
17060
  label: row.check?.passesRate ? "Rate ok" : "Rate blocked",
15804
17061
  tone: row.check?.passesRate ? "success" : "warning"
15805
17062
  }
15806
17063
  ),
15807
- /* @__PURE__ */ jsx78(
17064
+ /* @__PURE__ */ jsx86(
15808
17065
  FilterChip,
15809
17066
  {
15810
17067
  label: snapshot?.state.enforcePolicies === false ? "Policies relaxed" : row.check?.passesPolicies ? "Policies pass" : "Policy blocked",
@@ -15812,20 +17069,20 @@ function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQui
15812
17069
  }
15813
17070
  )
15814
17071
  ] }),
15815
- row.reasonLabels.length ? /* @__PURE__ */ jsx78("div", { className: "mt-3 flex flex-wrap gap-2", children: row.reasonLabels.map((reason) => /* @__PURE__ */ jsx78(
17072
+ row.reasonLabels.length ? /* @__PURE__ */ jsx86("div", { className: "mt-3 flex flex-wrap gap-2", children: row.reasonLabels.map((reason) => /* @__PURE__ */ jsx86(
15816
17073
  "span",
15817
17074
  {
15818
17075
  className: "rounded-full bg-amber-50 px-2.5 py-1 text-xs text-amber-700 dark:bg-amber-500/10 dark:text-amber-200",
15819
17076
  children: reason
15820
17077
  },
15821
17078
  `${row.id}:${reason}`
15822
- )) }) : /* @__PURE__ */ jsx78("p", { className: "mt-3 text-sm text-slate-500 dark:text-slate-400", children: "This service is a clean fit for the current visible-group and selected-trigger context." })
17079
+ )) }) : /* @__PURE__ */ jsx86("p", { className: "mt-3 text-sm text-slate-500 dark:text-slate-400", children: "This service is a clean fit for the current visible-group and selected-trigger context." })
15823
17080
  ] })
15824
17081
  ] }) : null,
15825
- /* @__PURE__ */ jsxs56("section", { className: "space-y-3", children: [
15826
- /* @__PURE__ */ jsx78(SectionTitle2, { title: "Capabilities", description: "Flags and pricing hints attached to this service." }),
15827
- /* @__PURE__ */ jsx78("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/80", children: summary.flags.length || service?.meta ? /* @__PURE__ */ jsxs56("div", { className: "flex flex-wrap gap-2", children: [
15828
- summary.flags.map((flag) => /* @__PURE__ */ jsx78(
17082
+ /* @__PURE__ */ jsxs64("section", { className: "space-y-3", children: [
17083
+ /* @__PURE__ */ jsx86(SectionTitle2, { title: "Capabilities", description: "Flags and pricing hints attached to this service." }),
17084
+ /* @__PURE__ */ jsx86("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/80", children: summary.flags.length || service?.meta ? /* @__PURE__ */ jsxs64("div", { className: "flex flex-wrap gap-2", children: [
17085
+ summary.flags.map((flag) => /* @__PURE__ */ jsx86(
15829
17086
  "span",
15830
17087
  {
15831
17088
  className: "rounded-full bg-emerald-50 px-2.5 py-1 text-xs text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-200",
@@ -15833,7 +17090,7 @@ function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQui
15833
17090
  },
15834
17091
  flag
15835
17092
  )),
15836
- Object.keys(service?.meta ?? {}).slice(0, 3).map((key) => /* @__PURE__ */ jsx78(
17093
+ Object.keys(service?.meta ?? {}).slice(0, 3).map((key) => /* @__PURE__ */ jsx86(
15837
17094
  "span",
15838
17095
  {
15839
17096
  className: "rounded-full bg-slate-100 px-2.5 py-1 text-xs text-slate-600 dark:bg-slate-900 dark:text-slate-300",
@@ -15841,17 +17098,17 @@ function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQui
15841
17098
  },
15842
17099
  key
15843
17100
  ))
15844
- ] }) : /* @__PURE__ */ jsx78("p", { className: "text-sm text-slate-500 dark:text-slate-400", children: "No capability flags were published for this service." }) })
17101
+ ] }) : /* @__PURE__ */ jsx86("p", { className: "text-sm text-slate-500 dark:text-slate-400", children: "No capability flags were published for this service." }) })
15845
17102
  ] }),
15846
- /* @__PURE__ */ jsxs56("section", { className: "space-y-3", children: [
15847
- /* @__PURE__ */ jsx78(
17103
+ /* @__PURE__ */ jsxs64("section", { className: "space-y-3", children: [
17104
+ /* @__PURE__ */ jsx86(
15848
17105
  SectionTitle2,
15849
17106
  {
15850
17107
  title: "Bindings",
15851
17108
  description: "Nodes currently connected to this service. Click any node to jump back into the canvas."
15852
17109
  }
15853
17110
  ),
15854
- /* @__PURE__ */ jsx78("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/80", children: summary.attachedNodeIds.length ? /* @__PURE__ */ jsx78("div", { className: "flex flex-wrap gap-2", children: summary.attachedNodeIds.map((nodeId, index) => /* @__PURE__ */ jsx78(
17111
+ /* @__PURE__ */ jsx86("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-950/80", children: summary.attachedNodeIds.length ? /* @__PURE__ */ jsx86("div", { className: "flex flex-wrap gap-2", children: summary.attachedNodeIds.map((nodeId, index) => /* @__PURE__ */ jsx86(
15855
17112
  "button",
15856
17113
  {
15857
17114
  type: "button",
@@ -15860,58 +17117,59 @@ function ServiceDetailCard({ mode, row, snapshot, onNodeClick, onOpenFallbackQui
15860
17117
  children: summary.attachedNodeLabels[index] ?? nodeId
15861
17118
  },
15862
17119
  `${row.id}:${nodeId}`
15863
- )) }) : /* @__PURE__ */ jsx78("p", { className: "text-sm text-slate-500 dark:text-slate-400", children: "This service is not attached to any node yet. Drag it from the catalog onto a node to assign it." }) })
17120
+ )) }) : /* @__PURE__ */ jsx86("p", { className: "text-sm text-slate-500 dark:text-slate-400", children: "This service is not attached to any node yet. Drag it from the catalog onto a node to assign it." }) })
15864
17121
  ] })
15865
17122
  ] });
15866
17123
  }
15867
17124
  function SectionTitle2({ title, description }) {
15868
- return /* @__PURE__ */ jsxs56("div", { children: [
15869
- /* @__PURE__ */ jsx78("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
15870
- /* @__PURE__ */ jsx78("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: description })
17125
+ return /* @__PURE__ */ jsxs64("div", { children: [
17126
+ /* @__PURE__ */ jsx86("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
17127
+ /* @__PURE__ */ jsx86("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: description })
15871
17128
  ] });
15872
17129
  }
15873
17130
  function DetailMetric({ label, value }) {
15874
- return /* @__PURE__ */ jsxs56("div", { className: "rounded-2xl bg-white px-4 py-3 dark:bg-slate-950", children: [
15875
- /* @__PURE__ */ jsx78("p", { className: "text-[11px] font-semibold tracking-[0.16em] text-slate-400 uppercase dark:text-slate-500", children: label }),
15876
- /* @__PURE__ */ jsx78("p", { className: "mt-2 text-sm font-semibold text-slate-900 dark:text-slate-100", children: value })
17131
+ return /* @__PURE__ */ jsxs64("div", { className: "rounded-2xl bg-white px-4 py-3 dark:bg-slate-950", children: [
17132
+ /* @__PURE__ */ jsx86("p", { className: "text-[11px] font-semibold tracking-[0.16em] text-slate-400 uppercase dark:text-slate-500", children: label }),
17133
+ /* @__PURE__ */ jsx86("p", { className: "mt-2 text-sm font-semibold text-slate-900 dark:text-slate-100", children: value })
15877
17134
  ] });
15878
17135
  }
15879
17136
  function FilterChip({ label, tone = "default" }) {
15880
- return /* @__PURE__ */ jsx78("span", { className: cn("rounded-full px-2.5 py-1 text-[11px] font-medium", filterChipClassName(tone)), children: label });
17137
+ return /* @__PURE__ */ jsx86("span", { className: cn("rounded-full px-2.5 py-1 text-[11px] font-medium", filterChipClassName(tone)), children: label });
15881
17138
  }
15882
17139
 
15883
17140
  // src/workspace/bottom-panel/services-split-pane.tsx
15884
- import { jsx as jsx79, jsxs as jsxs57 } from "react/jsx-runtime";
17141
+ import { jsx as jsx87, jsxs as jsxs65 } from "react/jsx-runtime";
15885
17142
  var UNGROUPED_TREE_VALUE2 = "__catalog_ungrouped__";
15886
17143
  function ServicesSplitPane(props) {
15887
17144
  const emptyTitle = props.mode === "active" ? "No active services yet" : "No services match this view";
15888
17145
  const emptyDescription = props.mode === "active" ? "Connect a service to a tag, field, or option and it will appear here with its bindings." : props.mode === "catalog" ? "Select a catalog group or create one to organize source services for faster assignment." : "Try changing the search or toggles to bring more services into view.";
15889
- return /* @__PURE__ */ jsx79("div", { className: "min-h-90 p-4", children: /* @__PURE__ */ jsxs57(ResizablePanelGroup, { direction: "horizontal", className: "min-h-90", children: [
15890
- /* @__PURE__ */ jsx79(ResizablePanel, { defaultSize: 44, minSize: 30, children: /* @__PURE__ */ jsxs57("section", { className: "flex h-full min-h-0 flex-col overflow-hidden", children: [
15891
- /* @__PURE__ */ jsxs57("div", { className: "space-y-3 border-b border-slate-100 pr-4 dark:border-slate-800", children: [
15892
- /* @__PURE__ */ jsxs57("div", { className: "flex items-center justify-between gap-3", children: [
15893
- /* @__PURE__ */ jsx79("div", { children: /* @__PURE__ */ jsx79("h4", { className: "mt-1 text-base font-semibold text-slate-900 dark:text-slate-100", children: props.mode === "active" ? "Attached services" : props.mode === "catalog" ? "Catalog workspace" : "All services" }) }),
15894
- /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
15895
- props.mode === "catalog" ? /* @__PURE__ */ jsx79("span", { className: "rounded-full bg-blue-50 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-blue-700 uppercase dark:bg-blue-500/10 dark:text-blue-200", children: props.selectedCatalogGroupLabel ?? "Ungrouped" }) : null,
15896
- /* @__PURE__ */ jsx79("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-slate-600 uppercase dark:bg-slate-900 dark:text-slate-300", children: props.rows.length })
17146
+ const [size, setSize] = useState40(44);
17147
+ return /* @__PURE__ */ jsx87("div", { className: "min-h-90 p-4", children: /* @__PURE__ */ jsxs65(ResizablePanelGroup, { direction: "horizontal", className: "min-h-90", children: [
17148
+ /* @__PURE__ */ jsx87(ResizablePanel, { onResize: (s) => setSize(s.inPixels), defaultSize: 44, minSize: 30, children: /* @__PURE__ */ jsxs65("section", { className: "flex h-full min-h-0 flex-col overflow-hidden", style: { "--resizable-width": size + "px" }, children: [
17149
+ /* @__PURE__ */ jsxs65("div", { className: "space-y-3 border-b border-slate-100 pr-4 dark:border-slate-800", children: [
17150
+ /* @__PURE__ */ jsxs65("div", { className: "flex items-center justify-between gap-3", children: [
17151
+ /* @__PURE__ */ jsx87("div", { children: /* @__PURE__ */ jsx87("h4", { className: "mt-1 text-base font-semibold text-slate-900 dark:text-slate-100", children: props.mode === "active" ? "Attached services" : props.mode === "catalog" ? "Catalog workspace" : "All services" }) }),
17152
+ /* @__PURE__ */ jsxs65("div", { className: "flex items-center gap-2", children: [
17153
+ props.mode === "catalog" ? /* @__PURE__ */ jsx87("span", { className: "rounded-full bg-blue-50 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-blue-700 uppercase dark:bg-blue-500/10 dark:text-blue-200", children: props.selectedCatalogGroupLabel ?? "Ungrouped" }) : null,
17154
+ /* @__PURE__ */ jsx87("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[10px] font-semibold tracking-[0.16em] text-slate-600 uppercase dark:bg-slate-900 dark:text-slate-300", children: props.rows.length })
15897
17155
  ] })
15898
17156
  ] }),
15899
- props.mode === "all" && props.appliedSnapshot?.selectedTag ? /* @__PURE__ */ jsxs57("div", { className: "flex flex-wrap gap-2 pb-3", children: [
15900
- /* @__PURE__ */ jsx79(FilterChip2, { label: `Context tag: ${props.appliedSnapshot.selectedTag.label}` }),
15901
- /* @__PURE__ */ jsx79(
17157
+ props.mode === "all" && props.appliedSnapshot?.selectedTag ? /* @__PURE__ */ jsxs65("div", { className: "flex flex-wrap gap-2 pb-3", children: [
17158
+ /* @__PURE__ */ jsx87(FilterChip2, { label: `Context tag: ${props.appliedSnapshot.selectedTag.label}` }),
17159
+ /* @__PURE__ */ jsx87(
15902
17160
  FilterChip2,
15903
17161
  {
15904
17162
  label: `${props.appliedSnapshot.state.selectedButtons.length} selected trigger${props.appliedSnapshot.state.selectedButtons.length === 1 ? "" : "s"}`
15905
17163
  }
15906
17164
  ),
15907
- /* @__PURE__ */ jsx79(
17165
+ /* @__PURE__ */ jsx87(
15908
17166
  FilterChip2,
15909
17167
  {
15910
17168
  label: `${props.appliedSnapshot.usedServiceIds.length} active service${props.appliedSnapshot.usedServiceIds.length === 1 ? "" : "s"} in context`
15911
17169
  }
15912
17170
  )
15913
17171
  ] }) : null,
15914
- props.mode === "catalog" ? /* @__PURE__ */ jsx79("div", { className: "space-y-3 pb-3", children: /* @__PURE__ */ jsx79(
17172
+ props.mode === "catalog" ? /* @__PURE__ */ jsx87("div", { className: "space-y-3 pb-3", children: /* @__PURE__ */ jsx87(
15915
17173
  CatalogToolbar,
15916
17174
  {
15917
17175
  groups: props.catalogGroups ?? [],
@@ -15933,7 +17191,7 @@ function ServicesSplitPane(props) {
15933
17191
  }
15934
17192
  ) }) : null
15935
17193
  ] }),
15936
- /* @__PURE__ */ jsx79(ScrollArea, { className: "h-[calc(var(--bottom-panel-height)-14.5rem)] max-h-[calc(var(--bottom-panel-height)-14.5rem)] min-h-0 flex-1", children: /* @__PURE__ */ jsx79("div", { className: "space-y-2 p-3 pl-0", children: props.rows.length === 0 ? /* @__PURE__ */ jsx79(EmptyState, { title: emptyTitle, description: emptyDescription }) : props.rows.map((row) => /* @__PURE__ */ jsxs57(
17194
+ /* @__PURE__ */ jsx87(ScrollArea, { className: "h-[calc(var(--bottom-panel-height)-14.5rem)] max-h-[calc(var(--bottom-panel-height)-14.5rem)] min-h-0 flex-1", children: /* @__PURE__ */ jsx87("div", { className: "space-y-2 p-3 pl-0", children: props.rows.length === 0 ? /* @__PURE__ */ jsx87(EmptyState, { title: emptyTitle, description: emptyDescription }) : props.rows.map((row) => /* @__PURE__ */ jsxs65(
15937
17195
  "button",
15938
17196
  {
15939
17197
  type: "button",
@@ -15946,34 +17204,34 @@ function ServicesSplitPane(props) {
15946
17204
  props.selectedRowId === row.id ? "border-blue-300 bg-blue-50 shadow-sm dark:border-blue-500/40 dark:bg-blue-500/10" : "border-slate-200 bg-white hover:border-slate-300 hover:bg-slate-50 dark:border-slate-800 dark:bg-slate-950/60 dark:hover:border-slate-700"
15947
17205
  ),
15948
17206
  children: [
15949
- /* @__PURE__ */ jsxs57("div", { className: "flex items-start justify-between gap-3", children: [
15950
- /* @__PURE__ */ jsxs57("div", { className: "min-w-0", children: [
15951
- /* @__PURE__ */ jsxs57("div", { className: "flex items-center gap-2", children: [
15952
- /* @__PURE__ */ jsx79(StatusDot, { tone: row.statusTone }),
15953
- /* @__PURE__ */ jsx79("span", { className: "truncate text-sm font-semibold text-slate-900 dark:text-slate-100", children: row.summary.name })
17207
+ /* @__PURE__ */ jsxs65("div", { className: "flex items-start justify-between gap-3", children: [
17208
+ /* @__PURE__ */ jsxs65("div", { className: "min-w-0", children: [
17209
+ /* @__PURE__ */ jsxs65("div", { className: "flex items-center gap-2", children: [
17210
+ /* @__PURE__ */ jsx87(StatusDot, { tone: row.statusTone }),
17211
+ /* @__PURE__ */ jsx87("span", { title: row.summary.name, className: "truncate max-w-[calc(var(--resizable-width)-12rem)] text-sm font-semibold text-slate-900 dark:text-slate-100", children: row.summary.name })
15954
17212
  ] }),
15955
- /* @__PURE__ */ jsxs57("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
15956
- /* @__PURE__ */ jsxs57("span", { children: [
17213
+ /* @__PURE__ */ jsxs65("div", { className: "mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500 dark:text-slate-400", children: [
17214
+ /* @__PURE__ */ jsxs65("span", { children: [
15957
17215
  "#",
15958
17216
  row.summary.id
15959
17217
  ] }),
15960
- row.summary.category ? /* @__PURE__ */ jsx79("span", { children: row.summary.category }) : null,
15961
- row.summary.platformId ? /* @__PURE__ */ jsx79("span", { children: row.summary.platformId }) : null
17218
+ row.summary.category ? /* @__PURE__ */ jsx87("span", { children: row.summary.category }) : null,
17219
+ row.summary.platformId ? /* @__PURE__ */ jsx87("span", { children: row.summary.platformId }) : null
15962
17220
  ] })
15963
17221
  ] }),
15964
- /* @__PURE__ */ jsx79("span", { className: statusBadgeClassName(row.statusTone), children: row.statusLabel })
17222
+ /* @__PURE__ */ jsx87("span", { className: statusBadgeClassName(row.statusTone), children: row.statusLabel })
15965
17223
  ] }),
15966
- /* @__PURE__ */ jsxs57("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
15967
- /* @__PURE__ */ jsxs57("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600 dark:bg-slate-900 dark:text-slate-300", children: [
17224
+ /* @__PURE__ */ jsxs65("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
17225
+ /* @__PURE__ */ jsxs65("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600 dark:bg-slate-900 dark:text-slate-300", children: [
15968
17226
  row.summary.attachmentCount,
15969
17227
  " node",
15970
17228
  row.summary.attachmentCount === 1 ? "" : "s"
15971
17229
  ] }),
15972
- row.summary.rate != null ? /* @__PURE__ */ jsxs57("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600 dark:bg-slate-900 dark:text-slate-300", children: [
17230
+ row.summary.rate != null ? /* @__PURE__ */ jsxs65("span", { className: "rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600 dark:bg-slate-900 dark:text-slate-300", children: [
15973
17231
  "Rate ",
15974
17232
  row.summary.rate
15975
17233
  ] }) : null,
15976
- row.reasonLabels.slice(0, 2).map((reason) => /* @__PURE__ */ jsx79(
17234
+ row.reasonLabels.slice(0, 2).map((reason) => /* @__PURE__ */ jsx87(
15977
17235
  "span",
15978
17236
  {
15979
17237
  className: "rounded-full bg-amber-50 px-2.5 py-1 text-[11px] text-amber-700 dark:bg-amber-500/10 dark:text-amber-200",
@@ -15987,14 +17245,14 @@ function ServicesSplitPane(props) {
15987
17245
  row.id
15988
17246
  )) }) })
15989
17247
  ] }) }),
15990
- /* @__PURE__ */ jsx79(ResizableHandle, { withHandle: true }),
15991
- /* @__PURE__ */ jsx79(ResizablePanel, { defaultSize: 56, minSize: 36, children: /* @__PURE__ */ jsxs57("section", { className: "flex h-full min-h-0 flex-col overflow-hidden", children: [
15992
- /* @__PURE__ */ jsxs57("div", { className: "border-b border-slate-100 px-4 dark:border-slate-800", children: [
15993
- /* @__PURE__ */ jsx79("p", { className: "text-xs font-semibold tracking-[0.18em] text-slate-400 uppercase dark:text-slate-500", children: "Service detail" }),
15994
- /* @__PURE__ */ jsx79("h4", { className: "mt-1 text-base font-semibold text-slate-900 dark:text-slate-100", children: props.detailRow ? props.detailRow.summary.name : "Select a service" }),
15995
- /* @__PURE__ */ jsx79("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: props.mode === "active" ? "Highlight connected nodes, inspect usage, and jump back into the canvas." : props.mode === "catalog" ? "Inspect compatibility, pricing, and bindings while browsing manual catalog groups." : "Inspect compatibility, pricing, and bindings before assigning the service to a node." })
17248
+ /* @__PURE__ */ jsx87(ResizableHandle, { withHandle: true }),
17249
+ /* @__PURE__ */ jsx87(ResizablePanel, { defaultSize: 56, minSize: 36, children: /* @__PURE__ */ jsxs65("section", { className: "flex h-full min-h-0 flex-col overflow-hidden", children: [
17250
+ /* @__PURE__ */ jsxs65("div", { className: "border-b border-slate-100 px-4 dark:border-slate-800", children: [
17251
+ /* @__PURE__ */ jsx87("p", { className: "text-xs font-semibold tracking-[0.18em] text-slate-400 uppercase dark:text-slate-500", children: "Service detail" }),
17252
+ /* @__PURE__ */ jsx87("h4", { className: "mt-1 text-base font-semibold text-slate-900 dark:text-slate-100", children: props.detailRow ? props.detailRow.summary.name : "Select a service" }),
17253
+ /* @__PURE__ */ jsx87("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: props.mode === "active" ? "Highlight connected nodes, inspect usage, and jump back into the canvas." : props.mode === "catalog" ? "Inspect compatibility, pricing, and bindings while browsing manual catalog groups." : "Inspect compatibility, pricing, and bindings before assigning the service to a node." })
15996
17254
  ] }),
15997
- /* @__PURE__ */ jsx79(ScrollArea, { className: "h-[calc(var(--bottom-panel-height)-14.5rem)] max-h-[calc(var(--bottom-panel-height)-14.5rem)] min-h-0 flex-1", children: /* @__PURE__ */ jsx79("div", { className: "p-5", children: props.detailRow ? /* @__PURE__ */ jsx79(
17255
+ /* @__PURE__ */ jsx87(ScrollArea, { className: "h-[calc(var(--bottom-panel-height)-14.5rem)] max-h-[calc(var(--bottom-panel-height)-14.5rem)] min-h-0 flex-1", children: /* @__PURE__ */ jsx87("div", { className: "p-5", children: props.detailRow ? /* @__PURE__ */ jsx87(
15998
17256
  ServiceDetailCard,
15999
17257
  {
16000
17258
  mode: props.mode,
@@ -16004,7 +17262,7 @@ function ServicesSplitPane(props) {
16004
17262
  onOpenFallbackQuickAdd: props.onOpenFallbackQuickAdd,
16005
17263
  onOpenFallbackEditor: props.onOpenFallbackEditor
16006
17264
  }
16007
- ) : /* @__PURE__ */ jsx79(
17265
+ ) : /* @__PURE__ */ jsx87(
16008
17266
  EmptyState,
16009
17267
  {
16010
17268
  title: "No service selected",
@@ -16026,8 +17284,8 @@ function CatalogContextPopover({
16026
17284
  onDraftContextChange
16027
17285
  }) {
16028
17286
  const context = draftContext;
16029
- return /* @__PURE__ */ jsxs57(Popover, { open, onOpenChange, children: [
16030
- /* @__PURE__ */ jsx79(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx79(
17287
+ return /* @__PURE__ */ jsxs65(Popover, { open, onOpenChange, children: [
17288
+ /* @__PURE__ */ jsx87(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx87(
16031
17289
  "button",
16032
17290
  {
16033
17291
  type: "button",
@@ -16036,10 +17294,10 @@ function CatalogContextPopover({
16036
17294
  "inline-flex h-9 w-9 items-center justify-center rounded-xl border text-sm transition",
16037
17295
  compatibleOnly ? "border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-500/30 dark:bg-blue-500/10 dark:text-blue-200" : "border-slate-200 bg-white text-slate-600 hover:bg-slate-100 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-300 dark:hover:bg-slate-900"
16038
17296
  ),
16039
- children: /* @__PURE__ */ jsx79(FiFilter2, {})
17297
+ children: /* @__PURE__ */ jsx87(FiFilter2, {})
16040
17298
  }
16041
17299
  ) }),
16042
- /* @__PURE__ */ jsxs57(
17300
+ /* @__PURE__ */ jsxs65(
16043
17301
  PopoverContent,
16044
17302
  {
16045
17303
  align: "end",
@@ -16047,31 +17305,31 @@ function CatalogContextPopover({
16047
17305
  collisionPadding: 16,
16048
17306
  className: "max-h-[min(32rem,var(--radix-popover-content-available-height))] w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-2xl p-0",
16049
17307
  children: [
16050
- /* @__PURE__ */ jsxs57("div", { className: "border-b border-slate-200 px-4 py-3 dark:border-slate-800", children: [
16051
- /* @__PURE__ */ jsx79("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: "Catalog context" }),
16052
- /* @__PURE__ */ jsx79("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: "Control compatibility checks here, or link them to the current workspace context." })
17308
+ /* @__PURE__ */ jsxs65("div", { className: "border-b border-slate-200 px-4 py-3 dark:border-slate-800", children: [
17309
+ /* @__PURE__ */ jsx87("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: "Catalog context" }),
17310
+ /* @__PURE__ */ jsx87("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: "Control compatibility checks here, or link them to the current workspace context." })
16053
17311
  ] }),
16054
- /* @__PURE__ */ jsx79(ScrollArea, { className: "h-[calc(var(--radix-popover-content-available-height)-4.5rem)] max-h-[calc(var(--radix-popover-content-available-height)-4.5rem)]", children: /* @__PURE__ */ jsxs57("div", { className: "space-y-4 p-4", children: [
16055
- /* @__PURE__ */ jsxs57("label", { className: "flex items-start justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
16056
- /* @__PURE__ */ jsxs57("span", { className: "min-w-0", children: [
16057
- /* @__PURE__ */ jsx79("span", { className: "block font-medium", children: "Compatible only" }),
16058
- /* @__PURE__ */ jsx79("span", { className: "mt-1 block text-xs text-slate-500 dark:text-slate-400", children: "Show only services that fit this catalog context safely." })
17312
+ /* @__PURE__ */ jsx87(ScrollArea, { className: "h-[calc(var(--radix-popover-content-available-height)-4.5rem)] max-h-[calc(var(--radix-popover-content-available-height)-4.5rem)]", children: /* @__PURE__ */ jsxs65("div", { className: "space-y-4 p-4", children: [
17313
+ /* @__PURE__ */ jsxs65("label", { className: "flex items-start justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
17314
+ /* @__PURE__ */ jsxs65("span", { className: "min-w-0", children: [
17315
+ /* @__PURE__ */ jsx87("span", { className: "block font-medium", children: "Compatible only" }),
17316
+ /* @__PURE__ */ jsx87("span", { className: "mt-1 block text-xs text-slate-500 dark:text-slate-400", children: "Show only services that fit this catalog context safely." })
16059
17317
  ] }),
16060
- /* @__PURE__ */ jsx79("input", { type: "checkbox", checked: compatibleOnly, onChange: (event) => onCompatibleOnlyChange(event.target.checked) })
17318
+ /* @__PURE__ */ jsx87("input", { type: "checkbox", checked: compatibleOnly, onChange: (event) => onCompatibleOnlyChange(event.target.checked) })
16061
17319
  ] }),
16062
- /* @__PURE__ */ jsxs57("label", { className: "flex items-start justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
16063
- /* @__PURE__ */ jsxs57("span", { className: "min-w-0", children: [
16064
- /* @__PURE__ */ jsx79("span", { className: "block font-medium", children: "Link to current context" }),
16065
- /* @__PURE__ */ jsx79("span", { className: "mt-1 block text-xs text-slate-500 dark:text-slate-400", children: "Mirror the current canvas tag and selected buttons while linked." })
17320
+ /* @__PURE__ */ jsxs65("label", { className: "flex items-start justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
17321
+ /* @__PURE__ */ jsxs65("span", { className: "min-w-0", children: [
17322
+ /* @__PURE__ */ jsx87("span", { className: "block font-medium", children: "Link to current context" }),
17323
+ /* @__PURE__ */ jsx87("span", { className: "mt-1 block text-xs text-slate-500 dark:text-slate-400", children: "Mirror the current canvas tag and selected buttons while linked." })
16066
17324
  ] }),
16067
- /* @__PURE__ */ jsx79("input", { type: "checkbox", checked: contextLinked, onChange: (event) => onContextLinkedChange(event.target.checked) })
17325
+ /* @__PURE__ */ jsx87("input", { type: "checkbox", checked: contextLinked, onChange: (event) => onContextLinkedChange(event.target.checked) })
16068
17326
  ] }),
16069
- /* @__PURE__ */ jsxs57("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
16070
- /* @__PURE__ */ jsx79("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Tags" }),
16071
- /* @__PURE__ */ jsx79("div", { className: "space-y-2", children: (draftSnapshot?.tags ?? []).map((tag) => {
17327
+ /* @__PURE__ */ jsxs65("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
17328
+ /* @__PURE__ */ jsx87("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Tags" }),
17329
+ /* @__PURE__ */ jsx87("div", { className: "space-y-2", children: (draftSnapshot?.tags ?? []).map((tag) => {
16072
17330
  const selected = context?.selectedTagId === tag.id;
16073
- return /* @__PURE__ */ jsxs57("label", { className: "flex items-start gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
16074
- /* @__PURE__ */ jsx79(
17331
+ return /* @__PURE__ */ jsxs65("label", { className: "flex items-start gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
17332
+ /* @__PURE__ */ jsx87(
16075
17333
  "input",
16076
17334
  {
16077
17335
  type: "radio",
@@ -16089,25 +17347,25 @@ function CatalogContextPopover({
16089
17347
  })
16090
17348
  }
16091
17349
  ),
16092
- /* @__PURE__ */ jsxs57("span", { className: "min-w-0", children: [
16093
- /* @__PURE__ */ jsx79("span", { className: "block font-medium", children: tag.label }),
16094
- tag.description ? /* @__PURE__ */ jsx79("span", { className: "block text-xs text-slate-500 dark:text-slate-400", children: tag.description }) : null
17350
+ /* @__PURE__ */ jsxs65("span", { className: "min-w-0", children: [
17351
+ /* @__PURE__ */ jsx87("span", { className: "block font-medium", children: tag.label }),
17352
+ tag.description ? /* @__PURE__ */ jsx87("span", { className: "block text-xs text-slate-500 dark:text-slate-400", children: tag.description }) : null
16095
17353
  ] })
16096
17354
  ] }, tag.id);
16097
17355
  }) })
16098
17356
  ] }),
16099
- /* @__PURE__ */ jsxs57("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
16100
- /* @__PURE__ */ jsx79("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Selected buttons" }),
16101
- draftSnapshot?.buttonGroups?.length ? /* @__PURE__ */ jsx79("div", { className: "space-y-3", children: draftSnapshot.buttonGroups.map((group) => /* @__PURE__ */ jsxs57("div", { className: "space-y-2", children: [
16102
- /* @__PURE__ */ jsx79("div", { className: "text-sm font-medium text-slate-900 dark:text-slate-100", children: group.label }),
16103
- /* @__PURE__ */ jsx79("div", { className: "space-y-1", children: group.options.map((option) => {
17357
+ /* @__PURE__ */ jsxs65("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
17358
+ /* @__PURE__ */ jsx87("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Selected buttons" }),
17359
+ draftSnapshot?.buttonGroups?.length ? /* @__PURE__ */ jsx87("div", { className: "space-y-3", children: draftSnapshot.buttonGroups.map((group) => /* @__PURE__ */ jsxs65("div", { className: "space-y-2", children: [
17360
+ /* @__PURE__ */ jsx87("div", { className: "text-sm font-medium text-slate-900 dark:text-slate-100", children: group.label }),
17361
+ /* @__PURE__ */ jsx87("div", { className: "space-y-1", children: group.options.map((option) => {
16104
17362
  const checked = context?.selectedButtons.includes(option.id) ?? false;
16105
- return /* @__PURE__ */ jsxs57(
17363
+ return /* @__PURE__ */ jsxs65(
16106
17364
  "label",
16107
17365
  {
16108
17366
  className: "flex items-start gap-3 text-sm text-slate-900 dark:text-slate-100",
16109
17367
  children: [
16110
- /* @__PURE__ */ jsx79(
17368
+ /* @__PURE__ */ jsx87(
16111
17369
  "input",
16112
17370
  {
16113
17371
  type: "checkbox",
@@ -16124,22 +17382,22 @@ function CatalogContextPopover({
16124
17382
  })
16125
17383
  }
16126
17384
  ),
16127
- /* @__PURE__ */ jsxs57("span", { className: "min-w-0", children: [
16128
- /* @__PURE__ */ jsx79("span", { className: "block", children: option.label }),
16129
- option.description ? /* @__PURE__ */ jsx79("span", { className: "block text-xs text-slate-500 dark:text-slate-400", children: option.description }) : null
17385
+ /* @__PURE__ */ jsxs65("span", { className: "min-w-0", children: [
17386
+ /* @__PURE__ */ jsx87("span", { className: "block", children: option.label }),
17387
+ option.description ? /* @__PURE__ */ jsx87("span", { className: "block text-xs text-slate-500 dark:text-slate-400", children: option.description }) : null
16130
17388
  ] })
16131
17389
  ]
16132
17390
  },
16133
17391
  option.id
16134
17392
  );
16135
17393
  }) })
16136
- ] }, group.id)) }) : /* @__PURE__ */ jsx79("div", { className: "text-sm text-slate-500 dark:text-slate-400", children: "No visible trigger options for the selected tag." })
17394
+ ] }, group.id)) }) : /* @__PURE__ */ jsx87("div", { className: "text-sm text-slate-500 dark:text-slate-400", children: "No visible trigger options for the selected tag." })
16137
17395
  ] }),
16138
- /* @__PURE__ */ jsxs57("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
16139
- /* @__PURE__ */ jsx79("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Safety" }),
16140
- /* @__PURE__ */ jsxs57("label", { className: "flex items-center justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
16141
- /* @__PURE__ */ jsx79("span", { children: "Strict safety" }),
16142
- /* @__PURE__ */ jsx79(
17396
+ /* @__PURE__ */ jsxs65("div", { className: "space-y-2 rounded-2xl border border-slate-200 bg-slate-50/70 p-3 dark:border-slate-800 dark:bg-slate-900/40", children: [
17397
+ /* @__PURE__ */ jsx87("div", { className: "text-xs font-semibold tracking-[0.16em] text-slate-500 uppercase dark:text-slate-400", children: "Safety" }),
17398
+ /* @__PURE__ */ jsxs65("label", { className: "flex items-center justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
17399
+ /* @__PURE__ */ jsx87("span", { children: "Strict safety" }),
17400
+ /* @__PURE__ */ jsx87(
16143
17401
  "input",
16144
17402
  {
16145
17403
  type: "checkbox",
@@ -16152,9 +17410,9 @@ function CatalogContextPopover({
16152
17410
  }
16153
17411
  )
16154
17412
  ] }),
16155
- /* @__PURE__ */ jsxs57("label", { className: "flex items-center justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
16156
- /* @__PURE__ */ jsx79("span", { children: "Enforce policies" }),
16157
- /* @__PURE__ */ jsx79(
17413
+ /* @__PURE__ */ jsxs65("label", { className: "flex items-center justify-between gap-3 text-sm text-slate-900 dark:text-slate-100", children: [
17414
+ /* @__PURE__ */ jsx87("span", { children: "Enforce policies" }),
17415
+ /* @__PURE__ */ jsx87(
16158
17416
  "input",
16159
17417
  {
16160
17418
  type: "checkbox",
@@ -16188,34 +17446,34 @@ function CatalogToolbar({
16188
17446
  }) {
16189
17447
  const treeValue = selectedGroupId ?? (ungroupedSelected ? UNGROUPED_TREE_VALUE2 : void 0);
16190
17448
  const treeOptions = buildCatalogGroupTreeOptions2(groups);
16191
- return /* @__PURE__ */ jsxs57("div", { className: "flex items-center justify-between gap-3", children: [
16192
- /* @__PURE__ */ jsxs57("div", { className: "flex flex-wrap items-center gap-2", children: [
16193
- /* @__PURE__ */ jsx79(
17449
+ return /* @__PURE__ */ jsxs65("div", { className: "flex items-center justify-between gap-3", children: [
17450
+ /* @__PURE__ */ jsxs65("div", { className: "flex flex-wrap items-center gap-2", children: [
17451
+ /* @__PURE__ */ jsx87(
16194
17452
  GroupInputPopoverButton,
16195
17453
  {
16196
17454
  label: "Create top-level group",
16197
- icon: /* @__PURE__ */ jsx79(FiPlus2, {}),
17455
+ icon: /* @__PURE__ */ jsx87(FiPlus2, {}),
16198
17456
  submitLabel: "Create",
16199
17457
  title: "Create root group",
16200
17458
  onSubmit: onCreateRootGroup
16201
17459
  }
16202
17460
  ),
16203
- /* @__PURE__ */ jsx79(
17461
+ /* @__PURE__ */ jsx87(
16204
17462
  GroupInputPopoverButton,
16205
17463
  {
16206
17464
  label: "Create child group",
16207
- icon: /* @__PURE__ */ jsx79(FiFolderPlus, {}),
17465
+ icon: /* @__PURE__ */ jsx87(FiFolderPlus, {}),
16208
17466
  title: "Create child group",
16209
17467
  submitLabel: "Create",
16210
17468
  disabled: !selectedGroupId,
16211
17469
  onSubmit: onCreateChildGroup
16212
17470
  }
16213
17471
  ),
16214
- /* @__PURE__ */ jsx79(
17472
+ /* @__PURE__ */ jsx87(
16215
17473
  GroupInputPopoverButton,
16216
17474
  {
16217
17475
  label: "Rename selected group",
16218
- icon: /* @__PURE__ */ jsx79(FiEdit2, {}),
17476
+ icon: /* @__PURE__ */ jsx87(FiEdit2, {}),
16219
17477
  title: "Rename group",
16220
17478
  submitLabel: "Save",
16221
17479
  disabled: !selectedGroupId,
@@ -16223,11 +17481,11 @@ function CatalogToolbar({
16223
17481
  onSubmit: onRenameGroup
16224
17482
  }
16225
17483
  ),
16226
- /* @__PURE__ */ jsx79(
17484
+ /* @__PURE__ */ jsx87(
16227
17485
  ConfirmPopoverButton,
16228
17486
  {
16229
17487
  label: "Delete selected group",
16230
- icon: /* @__PURE__ */ jsx79(FiTrash22, {}),
17488
+ icon: /* @__PURE__ */ jsx87(FiTrash22, {}),
16231
17489
  title: "Delete group?",
16232
17490
  description: selectedGroupLabel ? `Remove ${selectedGroupLabel} and its child groups.` : "Remove this group and its child groups.",
16233
17491
  confirmLabel: "Delete",
@@ -16235,10 +17493,10 @@ function CatalogToolbar({
16235
17493
  onConfirm: onDeleteGroup
16236
17494
  }
16237
17495
  ),
16238
- /* @__PURE__ */ jsx79(ToolbarIconButton, { label: "Assign services to selected group", disabled: !selectedGroupId, onClick: onAssignServices, children: /* @__PURE__ */ jsx79(FiPlus2, {}) })
17496
+ /* @__PURE__ */ jsx87(ToolbarIconButton, { label: "Assign services to selected group", disabled: !selectedGroupId, onClick: onAssignServices, children: /* @__PURE__ */ jsx87(FiPlus2, {}) })
16239
17497
  ] }),
16240
- /* @__PURE__ */ jsx79(
16241
- InputField17,
17498
+ /* @__PURE__ */ jsx87(
17499
+ InputField20,
16242
17500
  {
16243
17501
  variant: "treeselect",
16244
17502
  mode: "button",
@@ -16252,7 +17510,7 @@ function CatalogToolbar({
16252
17510
  const next = event.value == null ? null : String(event.value);
16253
17511
  onSelectGroup(next === UNGROUPED_TREE_VALUE2 ? null : next);
16254
17512
  },
16255
- button: /* @__PURE__ */ jsx79(FaFolderOpen2, {})
17513
+ button: /* @__PURE__ */ jsx87(FaFolderOpen2, {})
16256
17514
  }
16257
17515
  )
16258
17516
  ] });
@@ -16266,13 +17524,13 @@ function GroupInputPopoverButton({
16266
17524
  disabled = false,
16267
17525
  onSubmit
16268
17526
  }) {
16269
- const [open, setOpen] = useState35(false);
16270
- const [value, setValue] = useState35(initialValue);
16271
- useEffect23(() => {
17527
+ const [open, setOpen] = useState40(false);
17528
+ const [value, setValue] = useState40(initialValue);
17529
+ useEffect25(() => {
16272
17530
  if (open) setValue(initialValue);
16273
17531
  }, [initialValue, open]);
16274
- return /* @__PURE__ */ jsxs57(Popover, { open, onOpenChange: setOpen, children: [
16275
- /* @__PURE__ */ jsx79(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx79(
17532
+ return /* @__PURE__ */ jsxs65(Popover, { open, onOpenChange: setOpen, children: [
17533
+ /* @__PURE__ */ jsx87(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx87(
16276
17534
  "button",
16277
17535
  {
16278
17536
  type: "button",
@@ -16286,13 +17544,13 @@ function GroupInputPopoverButton({
16286
17544
  children: icon
16287
17545
  }
16288
17546
  ) }),
16289
- /* @__PURE__ */ jsx79(PopoverContent, { align: "start", side: "bottom", sideOffset: 8, collisionPadding: 16, className: "w-80 rounded-2xl", children: /* @__PURE__ */ jsxs57("div", { className: "space-y-3", children: [
16290
- /* @__PURE__ */ jsxs57("div", { children: [
16291
- /* @__PURE__ */ jsx79("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
16292
- /* @__PURE__ */ jsx79("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: "Names are editor-side catalog labels only." })
17547
+ /* @__PURE__ */ jsx87(PopoverContent, { align: "start", side: "bottom", sideOffset: 8, collisionPadding: 16, className: "w-80 rounded-2xl", children: /* @__PURE__ */ jsxs65("div", { className: "space-y-3", children: [
17548
+ /* @__PURE__ */ jsxs65("div", { children: [
17549
+ /* @__PURE__ */ jsx87("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
17550
+ /* @__PURE__ */ jsx87("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: "Names are editor-side catalog labels only." })
16293
17551
  ] }),
16294
- /* @__PURE__ */ jsx79(
16295
- InputField17,
17552
+ /* @__PURE__ */ jsx87(
17553
+ InputField20,
16296
17554
  {
16297
17555
  variant: "text",
16298
17556
  label: title,
@@ -16302,9 +17560,9 @@ function GroupInputPopoverButton({
16302
17560
  autoComplete: "off"
16303
17561
  }
16304
17562
  ),
16305
- /* @__PURE__ */ jsxs57("div", { className: "flex justify-end gap-2", children: [
16306
- /* @__PURE__ */ jsx79(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), className: "rounded-xl", children: "Cancel" }),
16307
- /* @__PURE__ */ jsx79(
17563
+ /* @__PURE__ */ jsxs65("div", { className: "flex justify-end gap-2", children: [
17564
+ /* @__PURE__ */ jsx87(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), className: "rounded-xl", children: "Cancel" }),
17565
+ /* @__PURE__ */ jsx87(
16308
17566
  Button,
16309
17567
  {
16310
17568
  type: "button",
@@ -16333,9 +17591,9 @@ function ConfirmPopoverButton({
16333
17591
  disabled = false,
16334
17592
  onConfirm
16335
17593
  }) {
16336
- const [open, setOpen] = useState35(false);
16337
- return /* @__PURE__ */ jsxs57(Popover, { open, onOpenChange: setOpen, children: [
16338
- /* @__PURE__ */ jsx79(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx79(
17594
+ const [open, setOpen] = useState40(false);
17595
+ return /* @__PURE__ */ jsxs65(Popover, { open, onOpenChange: setOpen, children: [
17596
+ /* @__PURE__ */ jsx87(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx87(
16339
17597
  "button",
16340
17598
  {
16341
17599
  type: "button",
@@ -16349,14 +17607,14 @@ function ConfirmPopoverButton({
16349
17607
  children: icon
16350
17608
  }
16351
17609
  ) }),
16352
- /* @__PURE__ */ jsx79(PopoverContent, { align: "start", side: "bottom", sideOffset: 8, collisionPadding: 16, className: "w-80 rounded-2xl", children: /* @__PURE__ */ jsxs57("div", { className: "space-y-3", children: [
16353
- /* @__PURE__ */ jsxs57("div", { children: [
16354
- /* @__PURE__ */ jsx79("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
16355
- /* @__PURE__ */ jsx79("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: description })
17610
+ /* @__PURE__ */ jsx87(PopoverContent, { align: "start", side: "bottom", sideOffset: 8, collisionPadding: 16, className: "w-80 rounded-2xl", children: /* @__PURE__ */ jsxs65("div", { className: "space-y-3", children: [
17611
+ /* @__PURE__ */ jsxs65("div", { children: [
17612
+ /* @__PURE__ */ jsx87("div", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: title }),
17613
+ /* @__PURE__ */ jsx87("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: description })
16356
17614
  ] }),
16357
- /* @__PURE__ */ jsxs57("div", { className: "flex justify-end gap-2", children: [
16358
- /* @__PURE__ */ jsx79(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), className: "rounded-xl", children: "Cancel" }),
16359
- /* @__PURE__ */ jsx79(
17615
+ /* @__PURE__ */ jsxs65("div", { className: "flex justify-end gap-2", children: [
17616
+ /* @__PURE__ */ jsx87(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(false), className: "rounded-xl", children: "Cancel" }),
17617
+ /* @__PURE__ */ jsx87(
16360
17618
  Button,
16361
17619
  {
16362
17620
  type: "button",
@@ -16379,8 +17637,8 @@ function ToolbarIconButton({
16379
17637
  disabled = false,
16380
17638
  onClick
16381
17639
  }) {
16382
- return /* @__PURE__ */ jsxs57(Tooltip, { children: [
16383
- /* @__PURE__ */ jsx79(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx79(
17640
+ return /* @__PURE__ */ jsxs65(Tooltip, { children: [
17641
+ /* @__PURE__ */ jsx87(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx87(
16384
17642
  "button",
16385
17643
  {
16386
17644
  type: "button",
@@ -16394,11 +17652,11 @@ function ToolbarIconButton({
16394
17652
  children
16395
17653
  }
16396
17654
  ) }),
16397
- /* @__PURE__ */ jsx79(TooltipContent, { side: "top", sideOffset: 8, children: label })
17655
+ /* @__PURE__ */ jsx87(TooltipContent, { side: "top", sideOffset: 8, children: label })
16398
17656
  ] });
16399
17657
  }
16400
17658
  function FilterChip2({ label, tone = "default" }) {
16401
- return /* @__PURE__ */ jsx79("span", { className: cn("rounded-full px-2.5 py-1 text-[11px] font-medium", filterChipClassName(tone)), children: label });
17659
+ return /* @__PURE__ */ jsx87("span", { className: cn("rounded-full px-2.5 py-1 text-[11px] font-medium", filterChipClassName(tone)), children: label });
16402
17660
  }
16403
17661
  function buildCatalogGroupTreeOptions2(groups, parentId = null) {
16404
17662
  return groups.filter((group) => (group.parentId ?? null) === parentId).sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.label.localeCompare(b.label)).map((group) => {
@@ -16413,7 +17671,7 @@ function buildCatalogGroupTreeOptions2(groups, parentId = null) {
16413
17671
  }
16414
17672
 
16415
17673
  // src/workspace/bottom-panel/index.tsx
16416
- import { Fragment as Fragment16, jsx as jsx80, jsxs as jsxs58 } from "react/jsx-runtime";
17674
+ import { Fragment as Fragment17, jsx as jsx88, jsxs as jsxs66 } from "react/jsx-runtime";
16417
17675
  var DRAG_MIME = "application/x-service-builder-service";
16418
17676
  function BottomConsolePanel({ controller, errors, activeServices, allServices, onServiceDragStateChange }) {
16419
17677
  const canvas = useCanvas21();
@@ -16424,26 +17682,26 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16424
17682
  const policies2 = ws.policies.policies.data ?? [];
16425
17683
  const currentTagId = canvas.api.selection.currentTag?.();
16426
17684
  const preferredTagId = currentTagId != null ? String(currentTagId) : canvas.layers.tags[0]?.id != null ? String(canvas.layers.tags[0]?.id) : null;
16427
- const [activeSearch, setActiveSearch] = useState36("");
16428
- const [allSearch, setAllSearch] = useState36("");
16429
- const [compatibleOnly, setCompatibleOnly] = useState36(false);
16430
- const [hideActiveServices, setHideActiveServices] = useState36(false);
16431
- const [filterOpen, setFilterOpen] = useState36(false);
16432
- const [searchOpen, setSearchOpen] = useState36(false);
16433
- const [contextLinked, setContextLinked] = useState36(false);
16434
- const [servicePickerOpen, setServicePickerOpen] = useState36(false);
16435
- const [selectedActiveServiceId, setSelectedActiveServiceId] = useState36(null);
16436
- const [selectedAllServiceId, setSelectedAllServiceId] = useState36(null);
16437
- const [catalogContextDraft, setCatalogContextDraft] = useState36(
17685
+ const [activeSearch, setActiveSearch] = useState41("");
17686
+ const [allSearch, setAllSearch] = useState41("");
17687
+ const [compatibleOnly, setCompatibleOnly] = useState41(false);
17688
+ const [hideActiveServices, setHideActiveServices] = useState41(false);
17689
+ const [filterOpen, setFilterOpen] = useState41(false);
17690
+ const [searchOpen, setSearchOpen] = useState41(false);
17691
+ const [contextLinked, setContextLinked] = useState41(false);
17692
+ const [servicePickerOpen, setServicePickerOpen] = useState41(false);
17693
+ const [selectedActiveServiceId, setSelectedActiveServiceId] = useState41(null);
17694
+ const [selectedAllServiceId, setSelectedAllServiceId] = useState41(null);
17695
+ const [catalogContextDraft, setCatalogContextDraft] = useState41(
16438
17696
  () => createDefaultServiceContext(canvas.props, preferredTagId)
16439
17697
  );
16440
- const [catalogState, setCatalogState] = useState36(null);
16441
- const [panelPosition, setPanelPosition] = useState36(() => readStoredPanelPosition());
16442
- const [draggingPanel, setDraggingPanel] = useState36(false);
16443
- const [consoleSubTab, setConsoleSubTab] = useState36("validation");
16444
- const [consoleScopeFilter, setConsoleScopeFilter] = useState36("all");
16445
- const [consoleSeverityFilter, setConsoleSeverityFilter] = useState36("all");
16446
- const [consoleIntroState, setConsoleIntroState] = useState36({
17698
+ const [catalogState, setCatalogState] = useState41(null);
17699
+ const [panelPosition, setPanelPosition] = useState41(() => readStoredPanelPosition());
17700
+ const [draggingPanel, setDraggingPanel] = useState41(false);
17701
+ const [consoleSubTab, setConsoleSubTab] = useState41("validation");
17702
+ const [consoleScopeFilter, setConsoleScopeFilter] = useState41("all");
17703
+ const [consoleSeverityFilter, setConsoleSeverityFilter] = useState41("all");
17704
+ const [consoleIntroState, setConsoleIntroState] = useState41({
16447
17705
  validation: { minimized: false, closed: false },
16448
17706
  logs: { minimized: false, closed: false },
16449
17707
  notices: { minimized: false, closed: false }
@@ -16453,11 +17711,11 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16453
17711
  const panelRef = useRef12(null);
16454
17712
  const searchInputRef = useRef12(null);
16455
17713
  const dragStartRef = useRef12(null);
16456
- const selectedButtons = useMemo36(
17714
+ const selectedButtons = useMemo40(
16457
17715
  () => (canvas.api.selection.selectedButtons?.() ?? []).map((value) => String(value)),
16458
17716
  [canvas.api.selection, canvas.selectionInfo.ids, canvas.selectionInfo.optionIds]
16459
17717
  );
16460
- const liveSelectionContext = useMemo36(
17718
+ const liveSelectionContext = useMemo40(
16461
17719
  () => ({
16462
17720
  selectedTagId: preferredTagId,
16463
17721
  selectedButtons,
@@ -16467,15 +17725,15 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16467
17725
  [preferredTagId, selectedButtons]
16468
17726
  );
16469
17727
  const effectiveCatalogContext = contextLinked ? liveSelectionContext : catalogContextDraft;
16470
- const appliedSnapshot = useMemo36(
17728
+ const appliedSnapshot = useMemo40(
16471
17729
  () => buildServiceContextSnapshot({ props: canvas.props, services: servicesMap, state: effectiveCatalogContext }),
16472
17730
  [canvas.props, effectiveCatalogContext, servicesMap]
16473
17731
  );
16474
- const draftSnapshot = useMemo36(
17732
+ const draftSnapshot = useMemo40(
16475
17733
  () => buildServiceContextSnapshot({ props: canvas.props, services: servicesMap, state: catalogContextDraft }),
16476
17734
  [canvas.props, catalogContextDraft, servicesMap]
16477
17735
  );
16478
- const allChecksById = useMemo36(() => {
17736
+ const allChecksById = useMemo40(() => {
16479
17737
  if (!appliedSnapshot.selectedTag) return /* @__PURE__ */ new Map();
16480
17738
  const candidateIds = Object.values(servicesMap).map((service) => service.id);
16481
17739
  const checks = canvas.api.editor.filterServicesForVisibleGroup(candidateIds, {
@@ -16487,16 +17745,16 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16487
17745
  });
16488
17746
  return new Map(checks.map((check) => [String(check.id), check]));
16489
17747
  }, [appliedSnapshot, canvas.api.editor, policies2, servicesMap]);
16490
- const hiddenServiceIds = useMemo36(() => {
17748
+ const hiddenServiceIds = useMemo40(() => {
16491
17749
  const ids = new Set(activeServices.map((service) => String(service.id)));
16492
17750
  for (const id of appliedSnapshot.usedServiceIds) ids.add(String(id));
16493
17751
  return ids;
16494
17752
  }, [activeServices, appliedSnapshot.usedServiceIds]);
16495
- const activeRows = useMemo36(
17753
+ const activeRows = useMemo40(
16496
17754
  () => activeServices.map((summary) => buildServiceRowVM({ summary, services: servicesMap, search: activeSearch })).filter((row) => row.matchesSearch),
16497
17755
  [activeSearch, activeServices, servicesMap]
16498
17756
  );
16499
- const filteredCatalogRows = useMemo36(
17757
+ const filteredCatalogRows = useMemo40(
16500
17758
  () => allServices.map(
16501
17759
  (summary) => buildServiceRowVM({
16502
17760
  summary,
@@ -16508,25 +17766,25 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16508
17766
  ).filter((row) => row.matchesSearch).filter((row) => !compatibleOnly || row.isCompatible).filter((row) => !hideActiveServices || !hiddenServiceIds.has(row.id)),
16509
17767
  [allChecksById, allSearch, allServices, compatibleOnly, effectiveCatalogContext, hiddenServiceIds, hideActiveServices, servicesMap]
16510
17768
  );
16511
- useEffect24(() => {
17769
+ useEffect26(() => {
16512
17770
  const next = createDefaultServiceContext(canvas.props, preferredTagId);
16513
17771
  setCatalogContextDraft((current) => {
16514
17772
  if (contextLinked) return current;
16515
17773
  return current.selectedTagId ? current : next;
16516
17774
  });
16517
17775
  }, [canvas.props, contextLinked, preferredTagId]);
16518
- useEffect24(() => {
17776
+ useEffect26(() => {
16519
17777
  if (!contextLinked) return;
16520
17778
  setCatalogContextDraft(liveSelectionContext);
16521
17779
  }, [contextLinked, liveSelectionContext]);
16522
- useEffect24(() => {
17780
+ useEffect26(() => {
16523
17781
  if (contextLinked) return;
16524
17782
  const next = sanitizeServiceContext(draftSnapshot, catalogContextDraft);
16525
17783
  if (JSON.stringify(next) !== JSON.stringify(catalogContextDraft)) {
16526
17784
  setCatalogContextDraft(next);
16527
17785
  }
16528
17786
  }, [catalogContextDraft, contextLinked, draftSnapshot]);
16529
- useEffect24(() => {
17787
+ useEffect26(() => {
16530
17788
  const editor = canvas.api.editor;
16531
17789
  const ensured = editor.getCatalog?.() ?? editor.ensureCatalog?.();
16532
17790
  if (ensured) setCatalogState(ensured);
@@ -16544,19 +17802,19 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16544
17802
  };
16545
17803
  }, [canvas.api]);
16546
17804
  const catalogPanelMode = catalogState?.viewMode === "grouped" ? "catalog" : "all";
16547
- const catalogGroups = useMemo36(
17805
+ const catalogGroups = useMemo40(
16548
17806
  () => (catalogState?.nodes ?? []).filter((node) => node.kind === "group").sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.label.localeCompare(b.label)),
16549
17807
  [catalogState]
16550
17808
  );
16551
17809
  const selectedCatalogGroupId = catalogGroups.some((node) => node.id === catalogState?.activeNodeId) ? String(catalogState?.activeNodeId) : null;
16552
- const groupedServiceIds = useMemo36(() => {
17810
+ const groupedServiceIds = useMemo40(() => {
16553
17811
  const ids = /* @__PURE__ */ new Set();
16554
17812
  for (const group of catalogGroups) {
16555
17813
  for (const serviceId of group.serviceIds) ids.add(String(serviceId));
16556
17814
  }
16557
17815
  return ids;
16558
17816
  }, [catalogGroups]);
16559
- const catalogRows = useMemo36(() => {
17817
+ const catalogRows = useMemo40(() => {
16560
17818
  if (!selectedCatalogGroupId) return filteredCatalogRows.filter((row) => !groupedServiceIds.has(row.id));
16561
17819
  const selectedGroup = catalogGroups.find((group) => group.id === selectedCatalogGroupId);
16562
17820
  if (!selectedGroup) return filteredCatalogRows.filter((row) => !groupedServiceIds.has(row.id));
@@ -16564,32 +17822,32 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16564
17822
  return filteredCatalogRows.filter((row) => allowedIds.has(row.id));
16565
17823
  }, [catalogGroups, filteredCatalogRows, groupedServiceIds, selectedCatalogGroupId]);
16566
17824
  const visibleAllRows = catalogPanelMode === "catalog" ? catalogRows : filteredCatalogRows;
16567
- const notices = useMemo36(() => normalizeNotices(canvas.props?.notices), [canvas.props]);
16568
- const activeNodeIds = useMemo36(() => {
17825
+ const notices = useMemo40(() => normalizeNotices(canvas.props?.notices), [canvas.props]);
17826
+ const activeNodeIds = useMemo40(() => {
16569
17827
  const ids = /* @__PURE__ */ new Set();
16570
17828
  if (canvas.activeId) ids.add(String(canvas.activeId));
16571
17829
  for (const id of canvas.selectionInfo.ids) ids.add(String(id));
16572
17830
  return ids;
16573
17831
  }, [canvas.activeId, canvas.selectionInfo.ids]);
16574
17832
  const consoleIssueCount = errors.validation.length + errors.logs.length + notices.length;
16575
- useEffect24(() => {
17833
+ useEffect26(() => {
16576
17834
  setSelectedActiveServiceId((current) => ensureSelectedRow(current, activeRows));
16577
17835
  }, [activeRows]);
16578
- useEffect24(() => {
17836
+ useEffect26(() => {
16579
17837
  if (catalogState?.selectedServiceId == null) return;
16580
17838
  setSelectedAllServiceId(String(catalogState.selectedServiceId));
16581
17839
  }, [catalogState?.selectedServiceId]);
16582
- useEffect24(() => {
17840
+ useEffect26(() => {
16583
17841
  setSelectedAllServiceId((current) => ensureSelectedRow(current, visibleAllRows));
16584
17842
  }, [visibleAllRows]);
16585
- useEffect24(() => {
17843
+ useEffect26(() => {
16586
17844
  const desiredIds = controller.isOpen && controller.activeTab === "activeServices" && selectedActiveServiceId ? activeRows.find((row) => row.id === selectedActiveServiceId)?.summary.attachedNodeIds ?? [] : [];
16587
17845
  if (!sameIds(lastHighlightedIdsRef.current, desiredIds)) {
16588
17846
  canvas.api.setHighlighted(desiredIds);
16589
17847
  lastHighlightedIdsRef.current = [...desiredIds];
16590
17848
  }
16591
17849
  }, [activeRows, canvas.api, controller.activeTab, controller.isOpen, selectedActiveServiceId]);
16592
- useEffect24(() => {
17850
+ useEffect26(() => {
16593
17851
  return () => {
16594
17852
  if (lastHighlightedIdsRef.current.length) {
16595
17853
  canvas.api.setHighlighted([]);
@@ -16597,10 +17855,10 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16597
17855
  }
16598
17856
  };
16599
17857
  }, [canvas.api]);
16600
- useEffect24(() => {
17858
+ useEffect26(() => {
16601
17859
  if (searchOpen) searchInputRef.current?.focus();
16602
17860
  }, [searchOpen]);
16603
- useEffect24(() => {
17861
+ useEffect26(() => {
16604
17862
  setPanelPosition((current) => {
16605
17863
  const resolved = resolvePanelPosition(current, panelRef.current, panelContainerRef.current);
16606
17864
  persistPanelPosition(resolved);
@@ -16622,7 +17880,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16622
17880
  }
16623
17881
  event.preventDefault();
16624
17882
  };
16625
- useEffect24(() => {
17883
+ useEffect26(() => {
16626
17884
  if (!draggingPanel) return;
16627
17885
  const onPointerMove = (event) => {
16628
17886
  const start = dragStartRef.current;
@@ -16650,7 +17908,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16650
17908
  window.removeEventListener("pointercancel", onPointerUp);
16651
17909
  };
16652
17910
  }, [draggingPanel, panelPosition]);
16653
- const setCatalogMode = useCallback21(
17911
+ const setCatalogMode = useCallback22(
16654
17912
  (mode) => {
16655
17913
  const editor = canvas.api.editor;
16656
17914
  editor.ensureCatalog?.();
@@ -16658,27 +17916,27 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16658
17916
  },
16659
17917
  [canvas.api.editor]
16660
17918
  );
16661
- const handleSelectCatalogService = useCallback21(
17919
+ const handleSelectCatalogService = useCallback22(
16662
17920
  (id) => {
16663
17921
  setSelectedAllServiceId(id);
16664
17922
  canvas.api.editor.setSelectedCatalogService?.(id ?? void 0);
16665
17923
  },
16666
17924
  [canvas.api.editor]
16667
17925
  );
16668
- const handleSelectCatalogGroup = useCallback21(
17926
+ const handleSelectCatalogGroup = useCallback22(
16669
17927
  (groupId) => {
16670
17928
  canvas.api.editor.setActiveCatalogNode?.(groupId ?? void 0);
16671
17929
  },
16672
17930
  [canvas.api.editor]
16673
17931
  );
16674
- const handleCreateRootGroup = useCallback21(
17932
+ const handleCreateRootGroup = useCallback22(
16675
17933
  (label) => {
16676
17934
  if (!label.trim()) return;
16677
17935
  canvas.api.editor.createCatalogGroup?.({ label: label.trim() });
16678
17936
  },
16679
17937
  [canvas.api.editor]
16680
17938
  );
16681
- const handleCreateChildGroup = useCallback21(
17939
+ const handleCreateChildGroup = useCallback22(
16682
17940
  (label) => {
16683
17941
  if (!selectedCatalogGroupId) return;
16684
17942
  const editor = canvas.api.editor;
@@ -16687,7 +17945,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16687
17945
  },
16688
17946
  [canvas.api.editor, selectedCatalogGroupId]
16689
17947
  );
16690
- const handleRenameGroup = useCallback21(
17948
+ const handleRenameGroup = useCallback22(
16691
17949
  (label) => {
16692
17950
  if (!selectedCatalogGroupId) return;
16693
17951
  const group = catalogGroups.find((item) => item.id === selectedCatalogGroupId);
@@ -16697,15 +17955,15 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16697
17955
  },
16698
17956
  [canvas.api.editor, catalogGroups, selectedCatalogGroupId]
16699
17957
  );
16700
- const handleDeleteGroup = useCallback21(() => {
17958
+ const handleDeleteGroup = useCallback22(() => {
16701
17959
  if (!selectedCatalogGroupId) return;
16702
17960
  canvas.api.editor.removeCatalogNode?.(selectedCatalogGroupId, { cascade: true });
16703
17961
  }, [canvas.api.editor, selectedCatalogGroupId]);
16704
- const handleAssignServices = useCallback21(() => {
17962
+ const handleAssignServices = useCallback22(() => {
16705
17963
  if (!selectedCatalogGroupId) return;
16706
17964
  setServicePickerOpen(true);
16707
17965
  }, [selectedCatalogGroupId]);
16708
- const handleConfirmAssignServices = useCallback21(
17966
+ const handleConfirmAssignServices = useCallback22(
16709
17967
  (serviceIds) => {
16710
17968
  if (!selectedCatalogGroupId || !serviceIds.length) return;
16711
17969
  canvas.api.editor.assignServicesToCatalogGroup?.(selectedCatalogGroupId, serviceIds, "append");
@@ -16713,18 +17971,18 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16713
17971
  [canvas.api.editor, selectedCatalogGroupId]
16714
17972
  );
16715
17973
  const tabs = [
16716
- { id: "console", label: "Console", icon: /* @__PURE__ */ jsx80(FiTerminal2, {}), count: consoleIssueCount },
16717
- { id: "activeServices", label: "Active Services", icon: /* @__PURE__ */ jsx80(MdOutlineSync, {}), count: activeServices.length },
16718
- { id: "allServices", label: "All Services", icon: /* @__PURE__ */ jsx80(LuLayers3, {}), count: allServices.length }
17974
+ { id: "console", label: "Console", icon: /* @__PURE__ */ jsx88(FiTerminal2, {}), count: consoleIssueCount },
17975
+ { id: "activeServices", label: "Active Services", icon: /* @__PURE__ */ jsx88(MdOutlineSync, {}), count: activeServices.length },
17976
+ { id: "allServices", label: "All Services", icon: /* @__PURE__ */ jsx88(LuLayers3, {}), count: allServices.length }
16719
17977
  ];
16720
17978
  const selectedActiveRow = activeRows.find((row) => row.id === selectedActiveServiceId) ?? null;
16721
17979
  const selectedAllRow = visibleAllRows.find((row) => row.id === selectedAllServiceId) ?? null;
16722
17980
  const selectedCatalogGroup = catalogGroups.find((group) => group.id === selectedCatalogGroupId) ?? null;
16723
- const Search = useMemo36(() => {
17981
+ const Search3 = useMemo40(() => {
16724
17982
  if (!["allServices", "activeServices"].includes(controller.activeTab)) return;
16725
17983
  const method = controller.activeTab == "allServices" ? setAllSearch : setActiveSearch;
16726
17984
  const value = controller.activeTab == "allServices" ? allSearch : activeSearch;
16727
- return /* @__PURE__ */ jsx80("div", { className: "absolute top-0 right-0 z-10", children: /* @__PURE__ */ jsx80(
17985
+ return /* @__PURE__ */ jsx88("div", { className: "absolute top-0 right-0 z-10", children: /* @__PURE__ */ jsx88(
16728
17986
  "input",
16729
17987
  {
16730
17988
  ref: searchInputRef,
@@ -16746,8 +18004,8 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16746
18004
  }
16747
18005
  ) });
16748
18006
  }, [controller.activeTab, activeSearch, allSearch, setActiveSearch, setAllSearch]);
16749
- return /* @__PURE__ */ jsxs58("div", { ref: panelContainerRef, className: "pointer-events-none absolute inset-0", children: [
16750
- /* @__PURE__ */ jsx80(
18007
+ return /* @__PURE__ */ jsxs66("div", { ref: panelContainerRef, className: "pointer-events-none absolute inset-0", children: [
18008
+ /* @__PURE__ */ jsx88(
16751
18009
  ServicePickerDialog,
16752
18010
  {
16753
18011
  open: servicePickerOpen,
@@ -16760,7 +18018,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16760
18018
  onConfirm: handleConfirmAssignServices
16761
18019
  }
16762
18020
  ),
16763
- /* @__PURE__ */ jsxs58(
18021
+ /* @__PURE__ */ jsxs66(
16764
18022
  Panel,
16765
18023
  {
16766
18024
  ref: panelRef,
@@ -16791,8 +18049,8 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16791
18049
  ["--bottom-panel-height"]: controller.height + "px"
16792
18050
  },
16793
18051
  children: [
16794
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center justify-between gap-3 border-b border-slate-200/80 px-3 py-2 dark:border-slate-800/80", children: [
16795
- /* @__PURE__ */ jsx80("div", { className: "flex min-w-0 items-center gap-1", children: tabs.map((tab) => /* @__PURE__ */ jsxs58(
18052
+ /* @__PURE__ */ jsxs66("div", { className: "flex items-center justify-between gap-3 border-b border-slate-200/80 px-3 py-2 dark:border-slate-800/80", children: [
18053
+ /* @__PURE__ */ jsx88("div", { className: "flex min-w-0 items-center gap-1", children: tabs.map((tab) => /* @__PURE__ */ jsxs66(
16796
18054
  "button",
16797
18055
  {
16798
18056
  type: "button",
@@ -16802,9 +18060,9 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16802
18060
  controller.activeTab === tab.id ? "bg-slate-100 text-slate-900 dark:bg-slate-900 dark:text-slate-100" : "text-slate-500 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-900 dark:hover:text-slate-100"
16803
18061
  ),
16804
18062
  children: [
16805
- /* @__PURE__ */ jsx80("span", { className: "text-base", children: tab.icon }),
16806
- /* @__PURE__ */ jsx80("span", { className: "truncate", children: tab.label }),
16807
- typeof tab.count === "number" ? /* @__PURE__ */ jsx80(
18063
+ /* @__PURE__ */ jsx88("span", { className: "text-base", children: tab.icon }),
18064
+ /* @__PURE__ */ jsx88("span", { className: "truncate", children: tab.label }),
18065
+ typeof tab.count === "number" ? /* @__PURE__ */ jsx88(
16808
18066
  "span",
16809
18067
  {
16810
18068
  className: cn(
@@ -16818,8 +18076,8 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16818
18076
  },
16819
18077
  tab.id
16820
18078
  )) }),
16821
- /* @__PURE__ */ jsxs58("div", { className: "flex items-center gap-1", children: [
16822
- /* @__PURE__ */ jsxs58(
18079
+ /* @__PURE__ */ jsxs66("div", { className: "flex items-center gap-1", children: [
18080
+ /* @__PURE__ */ jsxs66(
16823
18081
  "button",
16824
18082
  {
16825
18083
  type: "button",
@@ -16829,16 +18087,16 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16829
18087
  draggingPanel && "cursor-grabbing"
16830
18088
  ),
16831
18089
  children: [
16832
- /* @__PURE__ */ jsx80(LuGripHorizontal, {}),
16833
- /* @__PURE__ */ jsx80("span", { children: draggingPanel ? "Dragging panel..." : "Drag panel" })
18090
+ /* @__PURE__ */ jsx88(LuGripHorizontal, {}),
18091
+ /* @__PURE__ */ jsx88("span", { children: draggingPanel ? "Dragging panel..." : "Drag panel" })
16834
18092
  ]
16835
18093
  }
16836
18094
  ),
16837
- /* @__PURE__ */ jsxs58("div", { className: "hidden items-center gap-2 rounded-xl border border-slate-200/80 px-2 py-1 text-xs text-slate-500 md:flex dark:border-slate-800 dark:text-slate-400", children: [
16838
- /* @__PURE__ */ jsx80(LuGripHorizontal, {}),
16839
- /* @__PURE__ */ jsx80("span", { children: "Resize from top or side edges" })
18095
+ /* @__PURE__ */ jsxs66("div", { className: "hidden items-center gap-2 rounded-xl border border-slate-200/80 px-2 py-1 text-xs text-slate-500 md:flex dark:border-slate-800 dark:text-slate-400", children: [
18096
+ /* @__PURE__ */ jsx88(LuGripHorizontal, {}),
18097
+ /* @__PURE__ */ jsx88("span", { children: "Resize from top or side edges" })
16840
18098
  ] }),
16841
- /* @__PURE__ */ jsx80(
18099
+ /* @__PURE__ */ jsx88(
16842
18100
  Button,
16843
18101
  {
16844
18102
  type: "button",
@@ -16846,30 +18104,30 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16846
18104
  size: "sm",
16847
18105
  onClick: () => controller.close(),
16848
18106
  className: "h-8 rounded-xl px-2 text-slate-500 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-100",
16849
- children: /* @__PURE__ */ jsx80(FiX6, {})
18107
+ children: /* @__PURE__ */ jsx88(FiX6, {})
16850
18108
  }
16851
18109
  )
16852
18110
  ] })
16853
18111
  ] }),
16854
- /* @__PURE__ */ jsxs58("div", { className: "flex min-h-0 flex-1 flex-col bg-slate-50/70 dark:bg-slate-950/40", children: [
16855
- controller.activeTab !== "console" ? /* @__PURE__ */ jsxs58("div", { className: "flex items-center justify-between gap-3 border-b border-slate-200/70 px-4 py-3 dark:border-slate-800/70", children: [
16856
- /* @__PURE__ */ jsxs58("div", { className: "min-w-0", children: [
16857
- /* @__PURE__ */ jsx80("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: controller.activeTab === "activeServices" ? "Connected services" : "Service catalog" }),
16858
- /* @__PURE__ */ jsx80("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: controller.activeTab === "activeServices" ? "Bound services can be highlighted back onto the canvas from here." : catalogPanelMode === "catalog" ? "Browse source services through manual editor-side catalog groups while keeping detail and compatibility visible." : "Browse every source service, filter by current visible-group compatibility, and drag it onto nodes." })
18112
+ /* @__PURE__ */ jsxs66("div", { className: "flex min-h-0 flex-1 flex-col bg-slate-50/70 dark:bg-slate-950/40", children: [
18113
+ controller.activeTab !== "console" ? /* @__PURE__ */ jsxs66("div", { className: "flex items-center justify-between gap-3 border-b border-slate-200/70 px-4 py-3 dark:border-slate-800/70", children: [
18114
+ /* @__PURE__ */ jsxs66("div", { className: "min-w-0", children: [
18115
+ /* @__PURE__ */ jsx88("p", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: controller.activeTab === "activeServices" ? "Connected services" : "Service catalog" }),
18116
+ /* @__PURE__ */ jsx88("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: controller.activeTab === "activeServices" ? "Bound services can be highlighted back onto the canvas from here." : catalogPanelMode === "catalog" ? "Browse source services through manual editor-side catalog groups while keeping detail and compatibility visible." : "Browse every source service, filter by current visible-group compatibility, and drag it onto nodes." })
16859
18117
  ] }),
16860
- /* @__PURE__ */ jsx80("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs58("div", { className: "relative flex items-center gap-2", children: [
16861
- searchOpen ? Search : null,
16862
- /* @__PURE__ */ jsx80(
18118
+ /* @__PURE__ */ jsx88("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs66("div", { className: "relative flex items-center gap-2", children: [
18119
+ searchOpen ? Search3 : null,
18120
+ /* @__PURE__ */ jsx88(
16863
18121
  HeaderIconButton,
16864
18122
  {
16865
18123
  label: "Search services",
16866
18124
  active: searchOpen || Boolean(allSearch),
16867
18125
  onClick: () => setSearchOpen(true),
16868
- children: /* @__PURE__ */ jsx80(FiSearch, {})
18126
+ children: /* @__PURE__ */ jsx88(FiSearch, {})
16869
18127
  }
16870
18128
  ),
16871
- controller.activeTab === "allServices" ? /* @__PURE__ */ jsxs58(Fragment16, { children: [
16872
- /* @__PURE__ */ jsx80(
18129
+ controller.activeTab === "allServices" ? /* @__PURE__ */ jsxs66(Fragment17, { children: [
18130
+ /* @__PURE__ */ jsx88(
16873
18131
  CatalogContextPopover,
16874
18132
  {
16875
18133
  open: filterOpen,
@@ -16883,20 +18141,20 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16883
18141
  onDraftContextChange: setCatalogContextDraft
16884
18142
  }
16885
18143
  ),
16886
- /* @__PURE__ */ jsx80(CatalogModeSwitch, { mode: catalogPanelMode, onChange: setCatalogMode }),
16887
- /* @__PURE__ */ jsx80(
18144
+ /* @__PURE__ */ jsx88(CatalogModeSwitch, { mode: catalogPanelMode, onChange: setCatalogMode }),
18145
+ /* @__PURE__ */ jsx88(
16888
18146
  HeaderIconButton,
16889
18147
  {
16890
18148
  label: "Hide active services",
16891
18149
  active: hideActiveServices,
16892
18150
  onClick: () => setHideActiveServices((current) => !current),
16893
- children: hideActiveServices ? /* @__PURE__ */ jsx80(FiEyeOff2, {}) : /* @__PURE__ */ jsx80(FiEye3, {})
18151
+ children: hideActiveServices ? /* @__PURE__ */ jsx88(FiEyeOff2, {}) : /* @__PURE__ */ jsx88(FiEye3, {})
16894
18152
  }
16895
18153
  )
16896
18154
  ] }) : null
16897
18155
  ] }) })
16898
18156
  ] }) : null,
16899
- controller.activeTab === "console" ? /* @__PURE__ */ jsx80(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx80("div", { className: "p-4", children: /* @__PURE__ */ jsx80(
18157
+ controller.activeTab === "console" ? /* @__PURE__ */ jsx88(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx88("div", { className: "p-4", children: /* @__PURE__ */ jsx88(
16900
18158
  ConsoleTab,
16901
18159
  {
16902
18160
  errors,
@@ -16922,7 +18180,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16922
18180
  onNodeClick: (nodeId) => focusNode(canvas, nodeId)
16923
18181
  }
16924
18182
  ) }) }) : null,
16925
- controller.activeTab === "activeServices" ? /* @__PURE__ */ jsx80(
18183
+ controller.activeTab === "activeServices" ? /* @__PURE__ */ jsx88(
16926
18184
  ServicesSplitPane,
16927
18185
  {
16928
18186
  mode: "active",
@@ -16943,7 +18201,7 @@ function BottomConsolePanel({ controller, errors, activeServices, allServices, o
16943
18201
  })
16944
18202
  }
16945
18203
  ) : null,
16946
- controller.activeTab === "allServices" ? /* @__PURE__ */ jsx80(
18204
+ controller.activeTab === "allServices" ? /* @__PURE__ */ jsx88(
16947
18205
  ServicesSplitPane,
16948
18206
  {
16949
18207
  mode: catalogPanelMode,
@@ -16996,8 +18254,8 @@ function HeaderIconButton({
16996
18254
  active = false,
16997
18255
  onClick
16998
18256
  }) {
16999
- return /* @__PURE__ */ jsxs58(Tooltip, { children: [
17000
- /* @__PURE__ */ jsx80(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx80(
18257
+ return /* @__PURE__ */ jsxs66(Tooltip, { children: [
18258
+ /* @__PURE__ */ jsx88(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx88(
17001
18259
  "button",
17002
18260
  {
17003
18261
  type: "button",
@@ -17010,12 +18268,12 @@ function HeaderIconButton({
17010
18268
  children
17011
18269
  }
17012
18270
  ) }),
17013
- /* @__PURE__ */ jsx80(TooltipContent, { side: "top", sideOffset: 8, children: label })
18271
+ /* @__PURE__ */ jsx88(TooltipContent, { side: "top", sideOffset: 8, children: label })
17014
18272
  ] });
17015
18273
  }
17016
18274
  function CatalogModeSwitch({ mode, onChange }) {
17017
- return /* @__PURE__ */ jsxs58("div", { className: "inline-flex items-center rounded-xl border border-slate-200 bg-white p-1 dark:border-slate-800 dark:bg-slate-950", children: [
17018
- /* @__PURE__ */ jsx80(
18275
+ return /* @__PURE__ */ jsxs66("div", { className: "inline-flex items-center rounded-xl border border-slate-200 bg-white p-1 dark:border-slate-800 dark:bg-slate-950", children: [
18276
+ /* @__PURE__ */ jsx88(
17019
18277
  "button",
17020
18278
  {
17021
18279
  type: "button",
@@ -17027,7 +18285,7 @@ function CatalogModeSwitch({ mode, onChange }) {
17027
18285
  children: "All"
17028
18286
  }
17029
18287
  ),
17030
- /* @__PURE__ */ jsx80(
18288
+ /* @__PURE__ */ jsx88(
17031
18289
  "button",
17032
18290
  {
17033
18291
  type: "button",
@@ -17050,7 +18308,7 @@ import {
17050
18308
  useWorkspace as useWorkspace17,
17051
18309
  Workspace
17052
18310
  } from "@timeax/digital-service-engine/workspace";
17053
- import { useMemo as useMemo37, useState as useState37 } from "react";
18311
+ import { useMemo as useMemo41, useState as useState42 } from "react";
17054
18312
 
17055
18313
  // backend/memory/create-backend.ts
17056
18314
  import { createMemoryWorkspaceBackend } from "@timeax/digital-service-engine/workspace";
@@ -56453,7 +57711,7 @@ var workspaceBackend = {
56453
57711
  };
56454
57712
 
56455
57713
  // src/index.tsx
56456
- import { Fragment as Fragment17, jsx as jsx81, jsxs as jsxs59 } from "react/jsx-runtime";
57714
+ import { Fragment as Fragment18, jsx as jsx89, jsxs as jsxs67 } from "react/jsx-runtime";
56457
57715
  var inputRegistry = createInputRegistry();
56458
57716
  registerEntries(inputRegistry);
56459
57717
  function WorkspaceLayout({ onShare, onPlay, menu }) {
@@ -56461,13 +57719,13 @@ function WorkspaceLayout({ onShare, onPlay, menu }) {
56461
57719
  const ws = useWorkspace17();
56462
57720
  const errors = useErrors();
56463
57721
  const bottomPanel = useBottomConsolePanel();
56464
- const [draggingServiceId, setDraggingServiceId] = useState37(null);
56465
- const serviceSummary = useMemo37(() => buildServiceSummaries(canvas, ws), [canvas.props, canvas.selectionInfo, canvas.activeId, ws.services.data]);
56466
- return /* @__PURE__ */ jsx81(FallbackQuickAddProvider, { children: /* @__PURE__ */ jsx81(NodeContextMenuProvider, { children: /* @__PURE__ */ jsx81(FallbackEditorModalProvider, { children: /* @__PURE__ */ jsxs59("div", { className: "relative flex h-screen flex-col overflow-hidden *:font-display", children: [
56467
- /* @__PURE__ */ jsx81("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__ */ jsx81("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx81(WorkspaceBootStatusSurface, { boot: ws.boot }) }) }),
56468
- /* @__PURE__ */ jsxs59("div", { className: "flex grow overflow-hidden", children: [
56469
- /* @__PURE__ */ jsx81(left_default, { menu }),
56470
- /* @__PURE__ */ jsx81(
57722
+ const [draggingServiceId, setDraggingServiceId] = useState42(null);
57723
+ const serviceSummary = useMemo41(() => buildServiceSummaries(canvas, ws), [canvas.props, canvas.selectionInfo, canvas.activeId, ws.services.data]);
57724
+ return /* @__PURE__ */ jsx89(FallbackQuickAddProvider, { children: /* @__PURE__ */ jsx89(NodeContextMenuProvider, { children: /* @__PURE__ */ jsx89(FallbackEditorModalProvider, { children: /* @__PURE__ */ jsxs67("div", { className: "relative flex h-screen flex-col overflow-hidden *:font-display", children: [
57725
+ /* @__PURE__ */ jsx89("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__ */ jsx89("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx89(WorkspaceBootStatusSurface, { boot: ws.boot }) }) }),
57726
+ /* @__PURE__ */ jsxs67("div", { className: "flex grow overflow-hidden", children: [
57727
+ /* @__PURE__ */ jsx89(left_default, { menu }),
57728
+ /* @__PURE__ */ jsx89(
56471
57729
  CanvasPanel,
56472
57730
  {
56473
57731
  errors,
@@ -56476,9 +57734,9 @@ function WorkspaceLayout({ onShare, onPlay, menu }) {
56476
57734
  onServiceDragStateChange: (serviceId) => setDraggingServiceId(serviceId)
56477
57735
  }
56478
57736
  ),
56479
- /* @__PURE__ */ jsx81(right_default, { onShare, onPlay })
57737
+ /* @__PURE__ */ jsx89(right_default, { onShare, onPlay })
56480
57738
  ] }),
56481
- /* @__PURE__ */ jsx81("div", { className: "pointer-events-none absolute inset-0 z-5", children: /* @__PURE__ */ jsx81(
57739
+ /* @__PURE__ */ jsx89("div", { className: "pointer-events-none absolute inset-0 z-5", children: /* @__PURE__ */ jsx89(
56482
57740
  BottomConsolePanel,
56483
57741
  {
56484
57742
  controller: bottomPanel,
@@ -56566,13 +57824,13 @@ var Styles = `
56566
57824
 
56567
57825
  `;
56568
57826
  function ServiceBuilder({ backend, actor, ratePolicy, fallbackSettings, onShare, onPlay, menu }) {
56569
- return /* @__PURE__ */ jsxs59(Fragment17, { children: [
56570
- /* @__PURE__ */ jsx81("style", { children: Styles }),
56571
- /* @__PURE__ */ jsx81(InputsProvider, { initialRegistry: inputRegistry, children: /* @__PURE__ */ jsx81(Workspace, { backend, actor, ratePolicy, fallbackSettings, children: () => /* @__PURE__ */ jsx81(WorkspaceLayout, { onShare, onPlay, menu }) }) })
57827
+ return /* @__PURE__ */ jsxs67(Fragment18, { children: [
57828
+ /* @__PURE__ */ jsx89("style", { children: Styles }),
57829
+ /* @__PURE__ */ jsx89(InputsProvider, { initialRegistry: inputRegistry, children: /* @__PURE__ */ jsx89(Workspace, { backend, actor, ratePolicy, fallbackSettings, children: () => /* @__PURE__ */ jsx89(WorkspaceLayout, { onShare, onPlay, menu }) }) })
56572
57830
  ] });
56573
57831
  }
56574
57832
  function ServiceBuilderWorkspace({ ratePolicy, fallbackSettings, onShare, onPlay, menu }) {
56575
- return /* @__PURE__ */ jsx81(
57833
+ return /* @__PURE__ */ jsx89(
56576
57834
  ServiceBuilder,
56577
57835
  {
56578
57836
  backend: workspaceBackend,
@@ -56586,6 +57844,7 @@ function ServiceBuilderWorkspace({ ratePolicy, fallbackSettings, onShare, onPlay
56586
57844
  );
56587
57845
  }
56588
57846
  export {
57847
+ NativeFallbackEditor,
56589
57848
  ServiceBuilder,
56590
57849
  ServiceBuilderWorkspace
56591
57850
  };