@trops/dash-core 0.1.662 → 0.1.663

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
@@ -61206,6 +61206,68 @@ function renderFormItem(displayName, key, instructions, required, value, _onChan
61206
61206
  }, "config-item-".concat(key));
61207
61207
  }
61208
61208
 
61209
+ function useConfigTokens() {
61210
+ var _ref = React.useContext(DashReact.ThemeContext) || {},
61211
+ _ref$currentTheme = _ref.currentTheme,
61212
+ currentTheme = _ref$currentTheme === void 0 ? {} : _ref$currentTheme;
61213
+ return {
61214
+ muted: currentTheme["text-neutral-medium"] || "text-gray-400",
61215
+ strong: currentTheme["text-neutral-light"] || "text-gray-200",
61216
+ hairline: currentTheme["border-neutral-dark"] || "border-gray-700",
61217
+ selectedBg: currentTheme["bg-neutral-very-dark"] || "bg-gray-800",
61218
+ selectedBorder: currentTheme["border-primary-dark"] || "border-gray-600",
61219
+ fieldBg: currentTheme["bg-neutral-very-dark"] || "bg-gray-900"
61220
+ };
61221
+ }
61222
+
61223
+ /**
61224
+ * A row in one of the modal's left-hand lists (provider types, widgets,
61225
+ * event handlers) — styled like the Bots view's team list.
61226
+ *
61227
+ * @param {{ title: React.ReactNode, subtitle?: React.ReactNode,
61228
+ * meta?: React.ReactNode, badge?: React.ReactNode,
61229
+ * active?: boolean, mono?: boolean, onClick: () => void }} props
61230
+ * `subtitle` is a registry id (monospace); `meta` a muted count line.
61231
+ */
61232
+ var ConfigListRow = function ConfigListRow(_ref2) {
61233
+ var title = _ref2.title,
61234
+ _ref2$subtitle = _ref2.subtitle,
61235
+ subtitle = _ref2$subtitle === void 0 ? null : _ref2$subtitle,
61236
+ _ref2$meta = _ref2.meta,
61237
+ meta = _ref2$meta === void 0 ? null : _ref2$meta,
61238
+ _ref2$badge = _ref2.badge,
61239
+ badge = _ref2$badge === void 0 ? null : _ref2$badge,
61240
+ _ref2$active = _ref2.active,
61241
+ active = _ref2$active === void 0 ? false : _ref2$active,
61242
+ _ref2$mono = _ref2.mono,
61243
+ mono = _ref2$mono === void 0 ? false : _ref2$mono,
61244
+ onClick = _ref2.onClick;
61245
+ var _useConfigTokens = useConfigTokens(),
61246
+ muted = _useConfigTokens.muted,
61247
+ selectedBg = _useConfigTokens.selectedBg,
61248
+ selectedBorder = _useConfigTokens.selectedBorder;
61249
+ return /*#__PURE__*/jsxRuntime.jsxs("button", {
61250
+ type: "button",
61251
+ onClick: onClick,
61252
+ "aria-current": active ? "true" : undefined,
61253
+ className: "w-full text-left rounded-lg px-3 py-2 border ".concat(active ? "".concat(selectedBg, " ").concat(selectedBorder) : "border-transparent"),
61254
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61255
+ className: "flex flex-row items-center justify-between gap-2 min-w-0",
61256
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
61257
+ className: "text-sm font-medium truncate ".concat(mono ? "font-mono" : ""),
61258
+ children: title
61259
+ }), badge]
61260
+ }), subtitle ? /*#__PURE__*/jsxRuntime.jsx("div", {
61261
+ className: "text-xs font-mono truncate mt-0.5 ".concat(muted),
61262
+ title: typeof subtitle === "string" ? subtitle : undefined,
61263
+ children: subtitle
61264
+ }) : null, meta ? /*#__PURE__*/jsxRuntime.jsx("div", {
61265
+ className: "text-xs mt-0.5 ".concat(muted),
61266
+ children: meta
61267
+ }) : null]
61268
+ });
61269
+ };
61270
+
61209
61271
  function ownKeys$g(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
61210
61272
  function _objectSpread$g(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$g(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$g(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
61211
61273
  function _createForOfIteratorHelper$b(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$b(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
@@ -61241,6 +61303,9 @@ var WidgetsTab = function WidgetsTab(_ref) {
61241
61303
  stagedPrefs = _ref.stagedPrefs,
61242
61304
  stagePrefField = _ref.stagePrefField,
61243
61305
  stagePrefFieldForAll = _ref.stagePrefFieldForAll;
61306
+ var _useConfigTokens = useConfigTokens(),
61307
+ muted = _useConfigTokens.muted,
61308
+ hairline = _useConfigTokens.hairline;
61244
61309
  // Flatten every widget on the workspace, preserving which layout
61245
61310
  // section each came from (Main / Page N / Sidebar) so the left
61246
61311
  // column can group them cleanly. forEachWidget already dedupes.
@@ -61361,67 +61426,55 @@ var WidgetsTab = function WidgetsTab(_ref) {
61361
61426
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
61362
61427
  className: "flex h-full min-h-0",
61363
61428
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61364
- className: "w-64 border-r border-white/10 overflow-y-auto flex-shrink-0",
61365
- children: [sharedFields.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("button", {
61366
- onClick: function onClick() {
61367
- return setSelectedId(ALL_WIDGETS_ID);
61368
- },
61369
- className: "w-full text-left px-4 py-3 border-b border-white/10 transition-colors ".concat(isAllMode ? "bg-indigo-600/20 text-indigo-200" : "hover:bg-white/5 text-gray-300"),
61370
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61371
- className: "flex items-center gap-2",
61429
+ className: "w-64 border-r overflow-y-auto flex-shrink-0 p-3 flex flex-col gap-1 ".concat(hairline),
61430
+ children: [sharedFields.length > 0 && /*#__PURE__*/jsxRuntime.jsx(ConfigListRow, {
61431
+ title: /*#__PURE__*/jsxRuntime.jsxs("span", {
61432
+ className: "flex flex-row items-center gap-2",
61372
61433
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
61373
61434
  icon: "layer-group",
61374
61435
  className: "h-3.5 w-3.5"
61375
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
61376
- className: "font-semibold text-sm",
61377
- children: "All Widgets"
61378
- })]
61379
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
61380
- className: "text-[11px] text-gray-500 mt-0.5",
61381
- children: [sharedFields.length, " shared field", sharedFields.length === 1 ? "" : "s", " \xB7 bulk edit"]
61382
- })]
61436
+ }), "All Widgets"]
61437
+ }),
61438
+ meta: "".concat(sharedFields.length, " shared field").concat(sharedFields.length === 1 ? "" : "s", " \xB7 bulk edit"),
61439
+ active: isAllMode,
61440
+ onClick: function onClick() {
61441
+ return setSelectedId(ALL_WIDGETS_ID);
61442
+ }
61383
61443
  }), groupedWidgets.map(function (_ref2) {
61384
61444
  var _ref3 = _slicedToArray(_ref2, 2),
61385
61445
  section = _ref3[0],
61386
61446
  sectionWidgets = _ref3[1];
61387
61447
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
61388
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
61389
- className: "px-4 pt-3 pb-1 text-[10px] uppercase tracking-wider text-gray-600 font-semibold",
61448
+ className: "flex flex-col gap-1",
61449
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SectionLabel, {
61450
+ className: "px-3 pt-3 pb-1",
61390
61451
  children: section
61391
61452
  }), sectionWidgets.map(function (w) {
61392
61453
  var fieldCount = Object.keys(w.userConfig).length;
61393
61454
  var stagedForWidget = stagedPrefs !== null && stagedPrefs !== void 0 && stagedPrefs[w.id] ? Object.keys(stagedPrefs[w.id]).length : 0;
61394
- var isSel = selectedId === w.id;
61395
- return /*#__PURE__*/jsxRuntime.jsxs("button", {
61455
+ return /*#__PURE__*/jsxRuntime.jsx(ConfigListRow, {
61456
+ title: w.displayName,
61457
+ subtitle: w.widgetRef || null,
61458
+ meta: fieldCount === 0 ? "No configurable fields" : "".concat(fieldCount, " field").concat(fieldCount === 1 ? "" : "s"),
61459
+ badge: stagedForWidget > 0 ? /*#__PURE__*/jsxRuntime.jsxs("span", {
61460
+ className: "flex flex-row items-center gap-1.5 text-xs text-amber-400 flex-shrink-0",
61461
+ title: "Unsaved changes",
61462
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
61463
+ className: "inline-block h-1.5 w-1.5 rounded-full bg-amber-400"
61464
+ }), stagedForWidget]
61465
+ }) : null,
61466
+ active: selectedId === w.id,
61396
61467
  onClick: function onClick() {
61397
61468
  return setSelectedId(w.id);
61398
- },
61399
- className: "w-full text-left px-4 py-2 transition-colors ".concat(isSel ? "bg-indigo-600/20 text-indigo-200" : "hover:bg-white/5 text-gray-300"),
61400
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61401
- className: "flex items-center justify-between",
61402
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
61403
- className: "text-sm truncate",
61404
- children: w.displayName
61405
- }), stagedForWidget > 0 && /*#__PURE__*/jsxRuntime.jsx("span", {
61406
- className: "text-[10px] bg-amber-500/20 text-amber-300 px-1.5 rounded",
61407
- children: stagedForWidget
61408
- })]
61409
- }), w.widgetRef && /*#__PURE__*/jsxRuntime.jsx("div", {
61410
- className: "text-[10px] text-gray-500 font-mono truncate mt-0.5",
61411
- title: w.widgetRef,
61412
- children: w.widgetRef
61413
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
61414
- className: "text-[10px] text-gray-600 mt-0.5",
61415
- children: fieldCount === 0 ? "No configurable fields" : "".concat(fieldCount, " field").concat(fieldCount === 1 ? "" : "s")
61416
- })]
61469
+ }
61417
61470
  }, w.id);
61418
61471
  })]
61419
61472
  }, section);
61420
61473
  })]
61421
61474
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
61422
- className: "flex-1 overflow-y-auto p-4 min-w-0",
61475
+ className: "flex-1 overflow-y-auto p-5 min-w-0",
61423
61476
  children: [!selectedId && /*#__PURE__*/jsxRuntime.jsx("div", {
61424
- className: "text-sm text-gray-500 italic",
61477
+ className: "text-sm italic ".concat(muted),
61425
61478
  children: "Select a widget from the list."
61426
61479
  }), isAllMode && /*#__PURE__*/jsxRuntime.jsx(BulkEditPane, {
61427
61480
  sharedFields: sharedFields,
@@ -61441,19 +61494,22 @@ function SingleWidgetPane(_ref4) {
61441
61494
  var widget = _ref4.widget,
61442
61495
  effectivePrefs = _ref4.effectivePrefs,
61443
61496
  onFieldChange = _ref4.onFieldChange;
61497
+ var _useConfigTokens2 = useConfigTokens(),
61498
+ muted = _useConfigTokens2.muted,
61499
+ strong = _useConfigTokens2.strong;
61444
61500
  var hasFields = Object.keys(widget.userConfig).length > 0;
61445
61501
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
61446
61502
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61447
61503
  className: "mb-3",
61448
61504
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
61449
- className: "text-gray-200 font-semibold",
61505
+ className: "font-semibold ".concat(strong),
61450
61506
  children: widget.displayName
61451
61507
  }), widget.widgetRef && /*#__PURE__*/jsxRuntime.jsx("div", {
61452
- className: "text-xs text-gray-500 font-mono truncate mt-0.5",
61508
+ className: "text-xs font-mono truncate mt-0.5 ".concat(muted),
61453
61509
  title: widget.widgetRef,
61454
61510
  children: widget.widgetRef
61455
61511
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
61456
- className: "text-xs text-gray-600 mt-0.5",
61512
+ className: "text-xs mt-0.5 ".concat(muted),
61457
61513
  children: widget.section
61458
61514
  })]
61459
61515
  }), hasFields ? /*#__PURE__*/jsxRuntime.jsx(PanelEditForm, {
@@ -61461,7 +61517,7 @@ function SingleWidgetPane(_ref4) {
61461
61517
  userPrefs: effectivePrefs,
61462
61518
  onFieldChange: onFieldChange
61463
61519
  }) : /*#__PURE__*/jsxRuntime.jsx("div", {
61464
- className: "text-sm text-gray-500 italic",
61520
+ className: "text-sm italic ".concat(muted),
61465
61521
  children: "This widget has no configurable fields. It may be event-driven \u2014 pair it with a widget that publishes the events it listens for."
61466
61522
  })]
61467
61523
  });
@@ -61470,14 +61526,17 @@ function BulkEditPane(_ref5) {
61470
61526
  var sharedFields = _ref5.sharedFields,
61471
61527
  stagedPrefs = _ref5.stagedPrefs,
61472
61528
  onApplyAll = _ref5.onApplyAll;
61529
+ var _useConfigTokens3 = useConfigTokens(),
61530
+ muted = _useConfigTokens3.muted,
61531
+ strong = _useConfigTokens3.strong;
61473
61532
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
61474
61533
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61475
61534
  className: "mb-3",
61476
61535
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
61477
- className: "text-gray-200 font-semibold",
61536
+ className: "font-semibold ".concat(strong),
61478
61537
  children: "All Widgets"
61479
61538
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
61480
- className: "text-xs text-gray-500",
61539
+ className: "text-xs ".concat(muted),
61481
61540
  children: "Fields declared by 2+ widgets on this dashboard. Apply once to update every matching widget."
61482
61541
  })]
61483
61542
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -61489,7 +61548,7 @@ function BulkEditPane(_ref5) {
61489
61548
  onApplyAll: onApplyAll
61490
61549
  }, "".concat(field.key, "::").concat(field.schema.type));
61491
61550
  }), sharedFields.length === 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
61492
- className: "text-sm text-gray-500 italic",
61551
+ className: "text-sm italic ".concat(muted),
61493
61552
  children: "No shared fields across widgets on this dashboard."
61494
61553
  })]
61495
61554
  })]
@@ -61516,32 +61575,38 @@ function SharedFieldRow(_ref6) {
61516
61575
  if (allSame) setDraft(distinctValues[0]);
61517
61576
  // eslint-disable-next-line react-hooks/exhaustive-deps
61518
61577
  }, [allSame, distinctValues[0]]);
61578
+ var _useConfigTokens4 = useConfigTokens(),
61579
+ muted = _useConfigTokens4.muted,
61580
+ strong = _useConfigTokens4.strong,
61581
+ hairline = _useConfigTokens4.hairline,
61582
+ fieldBg = _useConfigTokens4.fieldBg;
61583
+ var fieldClass = "w-full px-2 py-1.5 rounded-lg border text-sm ".concat(fieldBg, " ").concat(hairline, " ").concat(strong);
61519
61584
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
61520
- className: "border border-white/10 rounded p-3",
61585
+ className: "rounded-lg border p-3 ".concat(hairline),
61521
61586
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61522
61587
  className: "flex items-start justify-between gap-3 mb-2",
61523
61588
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
61524
61589
  className: "flex-1 min-w-0",
61525
61590
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
61526
- className: "text-sm text-gray-200 font-semibold",
61591
+ className: "text-sm font-semibold ".concat(strong),
61527
61592
  children: field.schema.displayName || field.key
61528
61593
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
61529
- className: "text-[11px] text-gray-500",
61594
+ className: "text-xs ".concat(muted),
61530
61595
  children: ["Applies to ", field.widgets.length, " widgets", allSame ? "" : " \xB7 ".concat(distinctValues.length, " distinct values in use")]
61531
61596
  })]
61532
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
61597
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button3, {
61598
+ title: "Apply to all",
61599
+ size: "sm",
61533
61600
  onClick: function onClick() {
61534
61601
  return onApplyAll(field.widgets, field.key, draft);
61535
- },
61536
- className: "px-3 py-1 text-xs bg-indigo-600 hover:bg-indigo-500 text-white rounded transition-colors",
61537
- children: "Apply to all"
61602
+ }
61538
61603
  })]
61539
61604
  }), field.schema.type === "select" ? /*#__PURE__*/jsxRuntime.jsx("select", {
61540
61605
  value: draft,
61541
61606
  onChange: function onChange(e) {
61542
61607
  return setDraft(e.target.value);
61543
61608
  },
61544
- className: "w-full px-2 py-1.5 bg-gray-900 border border-white/10 rounded text-sm text-gray-200",
61609
+ className: fieldClass,
61545
61610
  children: (field.schema.options || []).map(function (opt) {
61546
61611
  return /*#__PURE__*/jsxRuntime.jsx("option", {
61547
61612
  value: opt.value,
@@ -61555,7 +61620,7 @@ function SharedFieldRow(_ref6) {
61555
61620
  return setDraft(e.target.value);
61556
61621
  },
61557
61622
  placeholder: allSame ? "" : "(multiple values — set one for all)",
61558
- className: "w-full px-2 py-1.5 bg-gray-900 border border-white/10 rounded text-sm text-gray-200"
61623
+ className: fieldClass
61559
61624
  })]
61560
61625
  });
61561
61626
  }
@@ -62814,30 +62879,88 @@ function _unsupportedIterableToArray$9(r, a) { if (r) { if ("string" == typeof r
62814
62879
  function _arrayLikeToArray$9(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
62815
62880
  function ownKeys$e(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
62816
62881
  function _objectSpread$e(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$e(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$e(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
62817
- var DashboardConfigModal = function DashboardConfigModal(_ref) {
62818
- var isOpen = _ref.isOpen,
62819
- setIsOpen = _ref.setIsOpen,
62820
- workspace = _ref.workspace;
62821
- _ref.workspaces;
62822
- var appProviders = _ref.appProviders,
62823
- getWidgetRequirements = _ref.getWidgetRequirements,
62824
- _ref$getWidgetConfig = _ref.getWidgetConfig,
62825
- getWidgetConfig = _ref$getWidgetConfig === void 0 ? null : _ref$getWidgetConfig,
62826
- onSaveBindings = _ref.onSaveBindings,
62827
- onSaveListeners = _ref.onSaveListeners,
62828
- _ref$onSaveUserPrefs = _ref.onSaveUserPrefs,
62829
- onSaveUserPrefs = _ref$onSaveUserPrefs === void 0 ? null : _ref$onSaveUserPrefs,
62830
- _ref$onSkip = _ref.onSkip,
62831
- onSkip = _ref$onSkip === void 0 ? null : _ref$onSkip,
62832
- _ref$initialTab = _ref.initialTab,
62833
- initialTab = _ref$initialTab === void 0 ? "providers" : _ref$initialTab,
62834
- _ref$onOpenBotsView = _ref.onOpenBotsView,
62835
- onOpenBotsView = _ref$onOpenBotsView === void 0 ? null : _ref$onOpenBotsView;
62882
+ var ConfigTab = function ConfigTab(_ref) {
62883
+ var active = _ref.active,
62884
+ onClick = _ref.onClick,
62885
+ children = _ref.children;
62886
+ var _useConfigTokens = useConfigTokens(),
62887
+ muted = _useConfigTokens.muted;
62888
+ return /*#__PURE__*/jsxRuntime.jsx("button", {
62889
+ type: "button",
62890
+ role: "tab",
62891
+ "aria-selected": active,
62892
+ onClick: onClick,
62893
+ className: "py-2.5 text-sm font-medium -mb-px border-b-2 ".concat(active ? "border-indigo-400" : "border-transparent ".concat(muted)),
62894
+ children: children
62895
+ });
62896
+ };
62897
+
62898
+ /**
62899
+ * DashboardConfigModal
62900
+ *
62901
+ * Workspace-scoped wiring panel. Lets a user assign providers to every
62902
+ * widget in the current workspace from one place instead of opening each
62903
+ * widget's settings individually. v1 ships the Providers tab; Listeners
62904
+ * tab lands in a follow-up PR (data model needs more exploration).
62905
+ *
62906
+ * Auto-opens on dashboard install when any required provider is still
62907
+ * unresolved after applying app-wide defaults. Also openable manually
62908
+ * via the dashboard toolbar's config button.
62909
+ *
62910
+ * @param {boolean} isOpen
62911
+ * @param {(open: boolean) => void} setIsOpen
62912
+ * @param {object} workspace Current workspace (layout/pages/sidebarLayout/selectedProviders).
62913
+ * @param {object|Array} appProviders Either a map keyed by provider name, or an array. Each entry has
62914
+ * at least { name?, type, providerClass, isDefaultForType }.
62915
+ * @param {(componentName: string) => Array} getWidgetRequirements
62916
+ * Called per widget instance. Should return the `providers: [...]`
62917
+ * array from the component's .dash.js. Usually backed by
62918
+ * ComponentManager.componentMap().
62919
+ * @param {(componentName: string) => object | null} getWidgetConfig
62920
+ * Called per widget instance. Returns the full ComponentManager
62921
+ * entry (events, eventHandlers, displayName, …). Used by the
62922
+ * Listeners tab to discover what each widget emits/handles.
62923
+ * @param {(changes: Array<{widgetId, providerType, providerName}>) => void} onSaveBindings
62924
+ * Called with the staged provider changes on Save. The parent persists
62925
+ * by forwarding to its existing `handleProviderSelect` /
62926
+ * `saveWorkspace` plumbing.
62927
+ * @param {(changes: {adds: Array, removes: Array}) => void} onSaveListeners
62928
+ * Called with the staged listener changes on Save. Each entry is
62929
+ * `{ receiverItemId, handlerName, sourceComponent, sourceItemId, eventName }`.
62930
+ * Parent uses `applyWiringChanges` + saveWorkspace.
62931
+ * @param {(changes: Array<{widgetId, key, value}>) => void} onSaveUserPrefs
62932
+ * Called with the staged widget userPrefs changes on Save. Parent
62933
+ * applies them to workspace + persists via saveWorkspace. Enables
62934
+ * bulk-edit of fields shared across widgets (e.g. basePath).
62935
+ * @param {"providers"|"listeners"|"widgets"} initialTab Which tab to focus when the modal opens.
62936
+ */
62937
+ var DashboardConfigModal = function DashboardConfigModal(_ref2) {
62938
+ var isOpen = _ref2.isOpen,
62939
+ setIsOpen = _ref2.setIsOpen,
62940
+ workspace = _ref2.workspace;
62941
+ _ref2.workspaces;
62942
+ var appProviders = _ref2.appProviders,
62943
+ getWidgetRequirements = _ref2.getWidgetRequirements,
62944
+ _ref2$getWidgetConfig = _ref2.getWidgetConfig,
62945
+ getWidgetConfig = _ref2$getWidgetConfig === void 0 ? null : _ref2$getWidgetConfig,
62946
+ onSaveBindings = _ref2.onSaveBindings,
62947
+ onSaveListeners = _ref2.onSaveListeners,
62948
+ _ref2$onSaveUserPrefs = _ref2.onSaveUserPrefs,
62949
+ onSaveUserPrefs = _ref2$onSaveUserPrefs === void 0 ? null : _ref2$onSaveUserPrefs,
62950
+ _ref2$onSkip = _ref2.onSkip,
62951
+ onSkip = _ref2$onSkip === void 0 ? null : _ref2$onSkip,
62952
+ _ref2$initialTab = _ref2.initialTab,
62953
+ initialTab = _ref2$initialTab === void 0 ? "providers" : _ref2$initialTab,
62954
+ _ref2$onOpenBotsView = _ref2.onOpenBotsView,
62955
+ onOpenBotsView = _ref2$onOpenBotsView === void 0 ? null : _ref2$onOpenBotsView;
62836
62956
  var _useContext = React.useContext(DashReact.ThemeContext),
62837
62957
  currentTheme = _useContext.currentTheme;
62838
62958
  var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
62839
62959
  grow: false
62840
62960
  });
62961
+ var _useConfigTokens2 = useConfigTokens(),
62962
+ muted = _useConfigTokens2.muted,
62963
+ hairline = _useConfigTokens2.hairline;
62841
62964
 
62842
62965
  // Active tab. Defaults to whatever the parent requested via
62843
62966
  // `initialTab`. Resets on each open via the modal's mount cycle.
@@ -63046,10 +63169,10 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
63046
63169
  }
63047
63170
  return Array.from(byPackage.values()).map(function (e) {
63048
63171
  return _objectSpread$e(_objectSpread$e({}, e), {}, {
63049
- components: Array.from(e.components.entries()).map(function (_ref2) {
63050
- var _ref3 = _slicedToArray(_ref2, 2),
63051
- component = _ref3[0],
63052
- count = _ref3[1];
63172
+ components: Array.from(e.components.entries()).map(function (_ref3) {
63173
+ var _ref4 = _slicedToArray(_ref3, 2),
63174
+ component = _ref4[0],
63175
+ count = _ref4[1];
63053
63176
  return {
63054
63177
  component: component,
63055
63178
  count: count
@@ -63370,80 +63493,84 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
63370
63493
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
63371
63494
  className: "flex flex-col h-full w-full rounded-lg overflow-clip border ".concat(panelStyles.backgroundColor || "", " ").concat(panelStyles.borderColor || "", " ").concat(panelStyles.textColor || ""),
63372
63495
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63373
- className: "flex-shrink-0 flex flex-row items-center justify-between p-4",
63496
+ className: "flex-shrink-0 flex flex-row items-start justify-between px-5 pt-4",
63374
63497
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63375
- className: "flex items-center gap-3",
63376
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
63377
- icon: "sliders",
63378
- className: "h-4 w-4 opacity-70"
63379
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
63380
- className: "text-lg font-semibold",
63381
- children: "Dashboard Config"
63382
- }), unresolvedCount > 0 && /*#__PURE__*/jsxRuntime.jsx(DashReact.Tag, {
63383
- text: "".concat(unresolvedCount, " unresolved"),
63384
- className: "bg-amber-900/40 text-amber-200"
63385
- })]
63498
+ className: "flex flex-col gap-0.5 min-w-0",
63499
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63500
+ className: "flex flex-row items-center gap-3",
63501
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
63502
+ icon: "sliders",
63503
+ className: "h-4 w-4 opacity-70"
63504
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
63505
+ className: "text-lg font-semibold",
63506
+ children: "Dashboard Config"
63507
+ }), unresolvedCount > 0 && /*#__PURE__*/jsxRuntime.jsxs("span", {
63508
+ "data-testid": "config-unresolved",
63509
+ className: "flex flex-row items-center gap-1.5 text-sm text-amber-400",
63510
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
63511
+ className: "inline-block h-1.5 w-1.5 rounded-full bg-amber-400"
63512
+ }), unresolvedCount, " unresolved"]
63513
+ })]
63514
+ }), workspace !== null && workspace !== void 0 && workspace.name ? /*#__PURE__*/jsxRuntime.jsx("span", {
63515
+ className: "text-sm truncate ".concat(muted),
63516
+ children: workspace.name
63517
+ }) : null]
63386
63518
  }), /*#__PURE__*/jsxRuntime.jsx("button", {
63387
63519
  type: "button",
63388
63520
  onClick: handleCancel,
63521
+ "aria-label": "Close",
63389
63522
  className: "opacity-50 hover:opacity-100 transition-opacity cursor-pointer",
63390
63523
  children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
63391
63524
  icon: "xmark",
63392
63525
  className: "h-5 w-5"
63393
63526
  })
63394
63527
  })]
63395
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsxs("div", {
63396
- className: "flex-shrink-0 flex flex-row items-center gap-2 px-4 pt-3",
63397
- children: [/*#__PURE__*/jsxRuntime.jsxs("button", {
63398
- type: "button",
63528
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
63529
+ role: "tablist",
63530
+ className: "flex-shrink-0 flex flex-row gap-6 px-5 mt-3 border-b ".concat(hairline),
63531
+ children: [/*#__PURE__*/jsxRuntime.jsxs(ConfigTab, {
63532
+ active: activeTab === "providers",
63399
63533
  onClick: function onClick() {
63400
63534
  return setActiveTab("providers");
63401
63535
  },
63402
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "providers" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63403
63536
  children: ["Providers", unresolvedCount > 0 && /*#__PURE__*/jsxRuntime.jsx("span", {
63404
63537
  className: "ml-2 inline-block h-1.5 w-1.5 rounded-full bg-amber-400 align-middle"
63405
63538
  })]
63406
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
63407
- type: "button",
63539
+ }), /*#__PURE__*/jsxRuntime.jsx(ConfigTab, {
63540
+ active: activeTab === "listeners",
63408
63541
  onClick: function onClick() {
63409
63542
  return setActiveTab("listeners");
63410
63543
  },
63411
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "listeners" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63412
63544
  children: "Listeners"
63413
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
63414
- type: "button",
63545
+ }), /*#__PURE__*/jsxRuntime.jsx(ConfigTab, {
63546
+ active: activeTab === "notifications",
63415
63547
  onClick: function onClick() {
63416
63548
  return setActiveTab("notifications");
63417
63549
  },
63418
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "notifications" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63419
63550
  children: "Notifications"
63420
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
63421
- type: "button",
63551
+ }), /*#__PURE__*/jsxRuntime.jsx(ConfigTab, {
63552
+ active: activeTab === "widgets",
63422
63553
  onClick: function onClick() {
63423
63554
  return setActiveTab("widgets");
63424
63555
  },
63425
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "widgets" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63426
63556
  children: "Widgets"
63427
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
63428
- type: "button",
63557
+ }), /*#__PURE__*/jsxRuntime.jsx(ConfigTab, {
63558
+ active: activeTab === "permissions",
63429
63559
  onClick: function onClick() {
63430
63560
  return setActiveTab("permissions");
63431
63561
  },
63432
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "permissions" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63433
63562
  children: "Permissions"
63434
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
63435
- type: "button",
63563
+ }), /*#__PURE__*/jsxRuntime.jsx(ConfigTab, {
63564
+ active: activeTab === "bots",
63436
63565
  onClick: function onClick() {
63437
63566
  return setActiveTab("bots");
63438
63567
  },
63439
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "bots" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63440
63568
  children: "Bots"
63441
- }), /*#__PURE__*/jsxRuntime.jsxs("button", {
63442
- type: "button",
63569
+ }), /*#__PURE__*/jsxRuntime.jsxs(ConfigTab, {
63570
+ active: activeTab === "dependencies",
63443
63571
  onClick: function onClick() {
63444
63572
  return setActiveTab("dependencies");
63445
63573
  },
63446
- className: "px-3 py-1.5 text-sm font-medium -mb-px border-b-2 ".concat(activeTab === "dependencies" ? "border-indigo-400" : "border-transparent opacity-60 hover:opacity-100"),
63447
63574
  children: ["Dependencies", dependencyCount > 0 && /*#__PURE__*/jsxRuntime.jsxs(DashReact.Caption2, {
63448
63575
  className: "ml-2",
63449
63576
  children: ["(", dependencyCount, ")"]
@@ -63451,7 +63578,7 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
63451
63578
  className: "ml-1 inline-block h-1.5 w-1.5 rounded-full bg-amber-400 align-middle"
63452
63579
  })]
63453
63580
  })]
63454
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsxs("div", {
63581
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
63455
63582
  className: "flex-1 min-h-0 ".concat(activeTab === "widgets" ? "" : "p-5"),
63456
63583
  children: [activeTab === "listeners" && /*#__PURE__*/jsxRuntime.jsx(ListenersTab, {
63457
63584
  emitters: emitters,
@@ -63511,8 +63638,8 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
63511
63638
  * write fails the user can re-toggle. No staging — the bulk modal
63512
63639
  * doesn't gate the user behind a Save button for boolean prefs.
63513
63640
  */
63514
- function NotificationsTab(_ref4) {
63515
- var workspace = _ref4.workspace;
63641
+ function NotificationsTab(_ref5) {
63642
+ var workspace = _ref5.workspace;
63516
63643
  var _useState9 = React.useState(""),
63517
63644
  _useState0 = _slicedToArray(_useState9, 2),
63518
63645
  searchQuery = _useState0[0],
@@ -63754,12 +63881,16 @@ function NotificationsTab(_ref4) {
63754
63881
  * dot per-type when any widget of that type is unresolved). Column 2
63755
63882
  * shows the selected type's bulk dropdown + per-widget dropdowns.
63756
63883
  */
63757
- function ProvidersTab(_ref5) {
63884
+ function ProvidersTab(_ref6) {
63758
63885
  var _typeEntries$, _selectedRows$;
63759
- var grouped = _ref5.grouped,
63760
- providersByType = _ref5.providersByType,
63761
- onBulk = _ref5.onBulk,
63762
- onPerWidget = _ref5.onPerWidget;
63886
+ var grouped = _ref6.grouped,
63887
+ providersByType = _ref6.providersByType,
63888
+ onBulk = _ref6.onBulk,
63889
+ onPerWidget = _ref6.onPerWidget;
63890
+ var _useConfigTokens3 = useConfigTokens(),
63891
+ muted = _useConfigTokens3.muted,
63892
+ hairline = _useConfigTokens3.hairline,
63893
+ fieldBg = _useConfigTokens3.fieldBg;
63763
63894
  var typeEntries = React.useMemo(function () {
63764
63895
  return Array.from(grouped.entries());
63765
63896
  }, [grouped]);
@@ -63790,73 +63921,66 @@ function ProvidersTab(_ref5) {
63790
63921
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
63791
63922
  className: "flex flex-row gap-3 h-full min-h-0",
63792
63923
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63793
- className: "w-56 flex-shrink-0 overflow-hidden flex flex-col border-r border-white/10",
63794
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
63795
- className: "px-3 py-2 text-xs font-semibold opacity-50 uppercase tracking-wider",
63924
+ className: "w-56 flex-shrink-0 overflow-hidden flex flex-col",
63925
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SectionLabel, {
63926
+ className: "px-3 mb-2",
63796
63927
  children: "Provider Types"
63797
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsx("div", {
63798
- className: "overflow-y-auto flex-1",
63799
- children: typeEntries.map(function (_ref6) {
63800
- var _ref7 = _slicedToArray(_ref6, 2),
63801
- providerType = _ref7[0],
63802
- rows = _ref7[1];
63803
- var isActive = selectedType === providerType;
63928
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
63929
+ className: "overflow-y-auto flex-1 flex flex-col gap-1",
63930
+ children: typeEntries.map(function (_ref7) {
63931
+ var _ref8 = _slicedToArray(_ref7, 2),
63932
+ providerType = _ref8[0],
63933
+ rows = _ref8[1];
63804
63934
  var unresolvedHere = rows.filter(function (r) {
63805
63935
  return r.required && !r.resolvedProviderName;
63806
63936
  }).length;
63807
- return /*#__PURE__*/jsxRuntime.jsxs("button", {
63808
- type: "button",
63937
+ return /*#__PURE__*/jsxRuntime.jsx(ConfigListRow, {
63938
+ title: providerType,
63939
+ active: selectedType === providerType,
63809
63940
  onClick: function onClick() {
63810
63941
  return setSelectedType(providerType);
63811
63942
  },
63812
- className: "w-full text-left px-3 py-2 border-l-2 ".concat(isActive ? "bg-indigo-900/30 border-indigo-400" : "border-transparent hover:bg-white/5"),
63813
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63814
- className: "flex items-center gap-2",
63943
+ meta: "".concat(rows.length, " widget").concat(rows.length === 1 ? "" : "s"),
63944
+ badge: unresolvedHere > 0 ? /*#__PURE__*/jsxRuntime.jsxs("span", {
63945
+ className: "flex flex-row items-center gap-1.5 text-xs text-amber-400 flex-shrink-0",
63815
63946
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
63816
- className: "text-sm font-medium truncate",
63817
- children: providerType
63818
- }), unresolvedHere > 0 && /*#__PURE__*/jsxRuntime.jsxs("span", {
63819
- className: "text-[10px] text-amber-300 flex items-center gap-1",
63820
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
63821
- icon: "triangle-exclamation",
63822
- className: "h-2.5 w-2.5"
63823
- }), unresolvedHere]
63824
- })]
63825
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
63826
- className: "text-xs opacity-50 mt-0.5",
63827
- children: [rows.length, " widget", rows.length === 1 ? "" : "s"]
63828
- })]
63947
+ className: "inline-block h-1.5 w-1.5 rounded-full bg-amber-400"
63948
+ }), unresolvedHere]
63949
+ }) : null
63829
63950
  }, providerType);
63830
63951
  })
63831
63952
  })]
63953
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
63954
+ "aria-hidden": true,
63955
+ className: "flex-shrink-0 border-r ".concat(hairline)
63832
63956
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
63833
63957
  className: "flex-1 min-w-0 overflow-hidden flex flex-col",
63834
63958
  children: selectedType ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
63835
63959
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63836
- className: "px-4 py-3 flex-shrink-0",
63960
+ className: "px-4 pb-3 flex-shrink-0 border-b ".concat(hairline),
63837
63961
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63838
63962
  className: "text-sm font-semibold",
63839
63963
  children: [selectedType, " ", /*#__PURE__*/jsxRuntime.jsx("span", {
63840
- className: "opacity-60 font-normal",
63964
+ className: "font-normal ".concat(muted),
63841
63965
  children: "provider"
63842
63966
  })]
63843
63967
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
63844
- className: "text-xs opacity-60 mt-1",
63968
+ className: "text-xs mt-1 ".concat(muted),
63845
63969
  children: "Apply one provider to every widget of this type, or adjust per-widget below."
63846
63970
  })]
63847
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsxs("div", {
63971
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
63848
63972
  className: "flex-1 overflow-y-auto p-4 space-y-4",
63849
63973
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63850
63974
  className: "flex items-center gap-3",
63851
63975
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
63852
- className: "text-xs opacity-60 flex-shrink-0 w-20",
63976
+ className: "text-xs flex-shrink-0 w-20 ".concat(muted),
63853
63977
  children: "Bulk assign"
63854
63978
  }), /*#__PURE__*/jsxRuntime.jsxs("select", {
63855
63979
  value: topValue,
63856
63980
  onChange: function onChange(e) {
63857
63981
  return onBulk(selectedType, e.target.value);
63858
63982
  },
63859
- className: "flex-1 bg-gray-800 border border-white/10 rounded px-3 py-1.5 text-sm",
63983
+ className: "flex-1 rounded-lg border px-3 py-1.5 text-sm ".concat(fieldBg, " ").concat(hairline),
63860
63984
  children: [/*#__PURE__*/jsxRuntime.jsx("option", {
63861
63985
  value: "",
63862
63986
  children: "\u2014 Select provider \u2014"
@@ -63868,10 +63992,11 @@ function ProvidersTab(_ref5) {
63868
63992
  })]
63869
63993
  })]
63870
63994
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
63871
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
63872
- className: "text-xs font-semibold opacity-50 uppercase tracking-wider mb-2",
63995
+ className: "flex flex-col gap-2",
63996
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SectionLabel, {
63873
63997
  children: "Per-widget"
63874
63998
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
63999
+ className: "flex flex-col gap-2",
63875
64000
  children: selectedRows.map(function (row) {
63876
64001
  var _row$layoutItem;
63877
64002
  var hasExplicitOverride = !!((_row$layoutItem = row.layoutItem) !== null && _row$layoutItem !== void 0 && (_row$layoutItem = _row$layoutItem.selectedProviders) !== null && _row$layoutItem !== void 0 && _row$layoutItem[selectedType]);
@@ -63879,35 +64004,29 @@ function ProvidersTab(_ref5) {
63879
64004
  var isMissing = !row.resolvedProviderName;
63880
64005
  var needsAttention = isRequired && isMissing;
63881
64006
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
63882
- className: "flex flex-row items-center gap-3 py-2 px-2 rounded border-l-2 transition-colors ".concat(needsAttention ? "bg-red-900 border-red-500" : "border-transparent hover:bg-gray-800"),
64007
+ "data-testid": "provider-row",
64008
+ className: "flex flex-row items-center gap-3 rounded-lg border px-3 py-2 ".concat(hairline),
63883
64009
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63884
64010
  className: "flex-1 min-w-0",
63885
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
63886
- className: "text-sm truncate flex items-center gap-1.5 ".concat(needsAttention ? "font-semibold text-red-100" : "font-medium"),
63887
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
63888
- className: "truncate",
63889
- children: row.label || row.component || "widget"
63890
- }), isRequired && /*#__PURE__*/jsxRuntime.jsx("span", {
63891
- className: needsAttention ? "text-red-300" : "text-indigo-300",
63892
- title: "Required provider",
63893
- "aria-label": "required",
63894
- children: "*"
63895
- })]
63896
- }), (row.widgetRef || row.component) && /*#__PURE__*/jsxRuntime.jsx(DashReact.Caption, {
63897
- block: true,
63898
- className: "font-mono truncate mt-0.5",
64011
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
64012
+ className: "text-sm font-medium truncate",
64013
+ children: row.label || row.component || "widget"
64014
+ }), (row.widgetRef || row.component) && /*#__PURE__*/jsxRuntime.jsx("div", {
64015
+ className: "text-xs font-mono truncate mt-0.5 ".concat(muted),
63899
64016
  title: row.widgetRef || row.component,
63900
64017
  children: row.widgetRef || row.component
63901
64018
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
63902
- className: "flex items-center gap-1.5 mt-1 text-xs",
63903
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
63904
- className: "uppercase tracking-wide px-1.5 py-0.5 rounded font-semibold ".concat(needsAttention ? "bg-red-600 text-white" : isRequired ? "bg-indigo-800 text-indigo-100" : "bg-gray-700 text-gray-300"),
63905
- children: isRequired ? "required" : "optional"
64019
+ className: "flex flex-row items-center gap-3 mt-1 text-xs",
64020
+ children: [/*#__PURE__*/jsxRuntime.jsxs("span", {
64021
+ className: "flex flex-row items-center gap-1.5 uppercase tracking-wider font-semibold ".concat(needsAttention ? "text-amber-400" : muted),
64022
+ children: [needsAttention && /*#__PURE__*/jsxRuntime.jsx("span", {
64023
+ className: "inline-block h-1.5 w-1.5 rounded-full bg-amber-400"
64024
+ }), isRequired ? "Required" : "Optional"]
63906
64025
  }), hasExplicitOverride && /*#__PURE__*/jsxRuntime.jsx("span", {
63907
- className: "uppercase tracking-wide px-1.5 py-0.5 rounded font-semibold bg-indigo-900 text-indigo-200",
63908
- children: "override"
64026
+ className: "uppercase tracking-wider font-semibold ".concat(muted),
64027
+ children: "Override"
63909
64028
  }), /*#__PURE__*/jsxRuntime.jsx("span", {
63910
- className: "opacity-40 truncate ml-1",
64029
+ className: "font-mono truncate ".concat(muted),
63911
64030
  children: (row.widgetId || "").slice(0, 8)
63912
64031
  })]
63913
64032
  })]
@@ -63916,7 +64035,7 @@ function ProvidersTab(_ref5) {
63916
64035
  onChange: function onChange(e) {
63917
64036
  return onPerWidget(row.widgetId, selectedType, e.target.value);
63918
64037
  },
63919
- className: "bg-gray-800 border rounded px-2 py-1 text-xs min-w-[12rem] ".concat(needsAttention ? "border-red-400" : "border-gray-700"),
64038
+ className: "w-48 flex-shrink-0 rounded-lg border px-2 py-1 text-xs ".concat(fieldBg, " ").concat(needsAttention ? "border-amber-400" : hairline),
63920
64039
  children: [/*#__PURE__*/jsxRuntime.jsx("option", {
63921
64040
  value: "",
63922
64041
  children: "\u2014 none \u2014"
@@ -63933,7 +64052,7 @@ function ProvidersTab(_ref5) {
63933
64052
  })]
63934
64053
  })]
63935
64054
  }) : /*#__PURE__*/jsxRuntime.jsx("div", {
63936
- className: "flex-1 flex items-center justify-center text-sm opacity-60",
64055
+ className: "flex-1 flex items-center justify-center text-sm ".concat(muted),
63937
64056
  children: "Pick a provider type to bulk-assign or adjust per widget."
63938
64057
  })
63939
64058
  })]
@@ -63954,8 +64073,8 @@ function ProvidersTab(_ref5) {
63954
64073
  * package (no `config.id` / `config.package` / item.workspace hint).
63955
64074
  * Usually this is a stale layout item whose widget got uninstalled.
63956
64075
  */
63957
- function DependenciesTab(_ref9) {
63958
- var dependencies = _ref9.dependencies;
64076
+ function DependenciesTab(_ref0) {
64077
+ var dependencies = _ref0.dependencies;
63959
64078
  if (!dependencies || dependencies.length === 0) {
63960
64079
  return /*#__PURE__*/jsxRuntime.jsx("div", {
63961
64080
  className: "flex items-center justify-center h-full text-sm opacity-60 text-center",
@@ -64028,13 +64147,16 @@ function sameWiringEntry(a, b) {
64028
64147
  * adjusts wiring per handler from a single dropdown of all emitters'
64029
64148
  * (widget × event) pairs.
64030
64149
  */
64031
- function ListenersTab(_ref0) {
64150
+ function ListenersTab(_ref1) {
64032
64151
  var _receivers$;
64033
- var emitters = _ref0.emitters,
64034
- receivers = _ref0.receivers,
64035
- wiring = _ref0.wiring,
64036
- onAdd = _ref0.onAdd,
64037
- onRemove = _ref0.onRemove;
64152
+ var emitters = _ref1.emitters,
64153
+ receivers = _ref1.receivers,
64154
+ wiring = _ref1.wiring,
64155
+ onAdd = _ref1.onAdd,
64156
+ onRemove = _ref1.onRemove;
64157
+ var _useConfigTokens4 = useConfigTokens(),
64158
+ muted = _useConfigTokens4.muted,
64159
+ hairline = _useConfigTokens4.hairline;
64038
64160
  var _useState17 = React.useState(((_receivers$ = receivers[0]) === null || _receivers$ === void 0 ? void 0 : _receivers$.key) || null),
64039
64161
  _useState18 = _slicedToArray(_useState17, 2),
64040
64162
  selectedReceiverKey = _useState18[0],
@@ -64090,31 +64212,25 @@ function ListenersTab(_ref0) {
64090
64212
  className: "flex flex-row gap-3 flex-1 min-h-0",
64091
64213
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
64092
64214
  className: "w-56 flex-shrink-0 overflow-hidden flex flex-col",
64093
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
64094
- className: "px-3 py-2 text-xs font-semibold opacity-50 uppercase tracking-wider",
64215
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SectionLabel, {
64216
+ className: "px-3 mb-2",
64095
64217
  children: "Widgets"
64096
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsx("div", {
64097
- className: "overflow-y-auto flex-1",
64218
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
64219
+ className: "overflow-y-auto flex-1 flex flex-col gap-1",
64098
64220
  children: receivers.map(function (r) {
64099
- var isActive = r.key === selectedReceiverKey;
64100
- return /*#__PURE__*/jsxRuntime.jsxs("button", {
64101
- type: "button",
64221
+ return /*#__PURE__*/jsxRuntime.jsx(ConfigListRow, {
64222
+ title: r.label,
64223
+ subtitle: r.widgetRef || null,
64224
+ active: r.key === selectedReceiverKey,
64102
64225
  onClick: function onClick() {
64103
64226
  return setSelectedReceiverKey(r.key);
64104
- },
64105
- className: "w-full text-left px-3 py-2 border-l-2 ".concat(isActive ? "bg-indigo-900/30 border-indigo-400" : "border-transparent hover:bg-white/5"),
64106
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
64107
- className: "text-sm font-medium truncate",
64108
- children: r.label
64109
- }), r.widgetRef && /*#__PURE__*/jsxRuntime.jsx(DashReact.Caption, {
64110
- block: true,
64111
- className: "font-mono truncate mt-0.5",
64112
- title: r.widgetRef,
64113
- children: r.widgetRef
64114
- })]
64227
+ }
64115
64228
  }, r.key);
64116
64229
  })
64117
64230
  })]
64231
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
64232
+ "aria-hidden": true,
64233
+ className: "flex-shrink-0 border-r ".concat(hairline)
64118
64234
  }), selectedReceiver ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
64119
64235
  children: [/*#__PURE__*/jsxRuntime.jsx(HandlersColumn, {
64120
64236
  receiver: selectedReceiver,
@@ -64134,7 +64250,7 @@ function ListenersTab(_ref0) {
64134
64250
  onRemove: onRemove
64135
64251
  })]
64136
64252
  }) : /*#__PURE__*/jsxRuntime.jsx("div", {
64137
- className: "flex-1 min-w-0 flex items-center justify-center text-sm opacity-60",
64253
+ className: "flex-1 min-w-0 flex items-center justify-center text-sm ".concat(muted),
64138
64254
  children: "Pick a widget on the left to wire its handlers."
64139
64255
  })]
64140
64256
  })
@@ -64147,11 +64263,11 @@ function ListenersTab(_ref0) {
64147
64263
  * third column. Matches the left-column look from
64148
64264
  * PanelEditItemHandlers.
64149
64265
  */
64150
- function HandlersColumn(_ref10) {
64151
- var receiver = _ref10.receiver,
64152
- myWiring = _ref10.myWiring,
64153
- selectedHandler = _ref10.selectedHandler,
64154
- onSelectHandler = _ref10.onSelectHandler;
64266
+ function HandlersColumn(_ref11) {
64267
+ var receiver = _ref11.receiver,
64268
+ myWiring = _ref11.myWiring,
64269
+ selectedHandler = _ref11.selectedHandler,
64270
+ onSelectHandler = _ref11.onSelectHandler;
64155
64271
  var countsByHandler = React.useMemo(function () {
64156
64272
  var m = new Map();
64157
64273
  var _iterator9 = _createForOfIteratorHelper$9(myWiring),
@@ -64168,44 +64284,43 @@ function HandlersColumn(_ref10) {
64168
64284
  }
64169
64285
  return m;
64170
64286
  }, [myWiring]);
64287
+ var _useConfigTokens5 = useConfigTokens(),
64288
+ muted = _useConfigTokens5.muted,
64289
+ hairline = _useConfigTokens5.hairline;
64171
64290
  return (
64172
64291
  /*#__PURE__*/
64173
64292
  // Plain <div> wrapper — Card2 reads as washed-out against the
64174
64293
  // modal's dark chrome. See ListenersTab + ProvidersTab fix.
64175
- jsxRuntime.jsxs("div", {
64176
- className: "w-56 flex-shrink-0 overflow-hidden flex flex-col",
64177
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
64178
- className: "px-3 py-2 text-xs font-semibold opacity-50 uppercase tracking-wider",
64179
- children: "Event Handlers"
64180
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsx("div", {
64181
- className: "overflow-y-auto flex-1",
64182
- children: receiver.eventHandlers.length === 0 ? /*#__PURE__*/jsxRuntime.jsx("div", {
64183
- className: "text-xs opacity-50 text-center py-6 px-3",
64184
- children: "This widget declares no event handlers."
64185
- }) : receiver.eventHandlers.map(function (h) {
64186
- var isActive = h === selectedHandler;
64187
- var count = countsByHandler.get(h) || 0;
64188
- return /*#__PURE__*/jsxRuntime.jsxs("button", {
64189
- type: "button",
64190
- onClick: function onClick() {
64191
- return onSelectHandler(h);
64192
- },
64193
- className: "w-full text-left px-3 py-2 text-sm flex items-center justify-between gap-2 border-l-2 ".concat(isActive ? "bg-indigo-900/30 border-indigo-400" : "border-transparent hover:bg-white/5"),
64194
- children: [/*#__PURE__*/jsxRuntime.jsxs("span", {
64195
- className: "flex items-center gap-2 min-w-0",
64196
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
64197
- icon: "bolt",
64198
- className: "h-3 w-3 opacity-60 flex-shrink-0"
64199
- }), /*#__PURE__*/jsxRuntime.jsx("code", {
64200
- className: "truncate",
64201
- children: h
64202
- })]
64203
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
64204
- className: "text-xs opacity-60 flex-shrink-0",
64205
- children: count
64206
- })]
64207
- }, h);
64208
- })
64294
+ jsxRuntime.jsxs(jsxRuntime.Fragment, {
64295
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
64296
+ className: "w-56 flex-shrink-0 overflow-hidden flex flex-col",
64297
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SectionLabel, {
64298
+ className: "px-3 mb-2",
64299
+ children: "Event Handlers"
64300
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
64301
+ className: "overflow-y-auto flex-1 flex flex-col gap-1",
64302
+ children: receiver.eventHandlers.length === 0 ? /*#__PURE__*/jsxRuntime.jsx("div", {
64303
+ className: "text-xs text-center py-6 px-3 ".concat(muted),
64304
+ children: "This widget declares no event handlers."
64305
+ }) : receiver.eventHandlers.map(function (h) {
64306
+ var count = countsByHandler.get(h) || 0;
64307
+ return /*#__PURE__*/jsxRuntime.jsx(ConfigListRow, {
64308
+ title: h,
64309
+ mono: true,
64310
+ active: h === selectedHandler,
64311
+ onClick: function onClick() {
64312
+ return onSelectHandler(h);
64313
+ },
64314
+ badge: /*#__PURE__*/jsxRuntime.jsx("span", {
64315
+ className: "text-xs flex-shrink-0 ".concat(muted),
64316
+ children: count
64317
+ })
64318
+ }, h);
64319
+ })
64320
+ })]
64321
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
64322
+ "aria-hidden": true,
64323
+ className: "flex-shrink-0 border-r ".concat(hairline)
64209
64324
  })]
64210
64325
  })
64211
64326
  );
@@ -64217,13 +64332,16 @@ function HandlersColumn(_ref10) {
64217
64332
  * Checked = wired; toggling commits an add/remove. Mirrors the
64218
64333
  * right-column UX of PanelEditItemHandlers.
64219
64334
  */
64220
- function EventsColumn(_ref11) {
64221
- var receiver = _ref11.receiver,
64222
- handlerName = _ref11.handlerName,
64223
- myWiring = _ref11.myWiring,
64224
- emitters = _ref11.emitters,
64225
- onAdd = _ref11.onAdd,
64226
- onRemove = _ref11.onRemove;
64335
+ function EventsColumn(_ref12) {
64336
+ var receiver = _ref12.receiver,
64337
+ handlerName = _ref12.handlerName,
64338
+ myWiring = _ref12.myWiring,
64339
+ emitters = _ref12.emitters,
64340
+ onAdd = _ref12.onAdd,
64341
+ onRemove = _ref12.onRemove;
64342
+ var _useConfigTokens6 = useConfigTokens(),
64343
+ muted = _useConfigTokens6.muted,
64344
+ hairline = _useConfigTokens6.hairline;
64227
64345
  // Wired-for-this-handler: dedupe defensively (legacy workspaces
64228
64346
  // occasionally contain duplicate entries under the same handler).
64229
64347
  var wiredHere = React.useMemo(function () {
@@ -64260,7 +64378,7 @@ function EventsColumn(_ref11) {
64260
64378
  });
64261
64379
  if (!handlerName) {
64262
64380
  return /*#__PURE__*/jsxRuntime.jsx("div", {
64263
- className: "flex-1 min-w-0 flex items-center justify-center text-sm opacity-60",
64381
+ className: "flex-1 min-w-0 flex items-center justify-center text-sm ".concat(muted),
64264
64382
  children: "Select a handler to view available events."
64265
64383
  });
64266
64384
  }
@@ -64294,7 +64412,7 @@ function EventsColumn(_ref11) {
64294
64412
  jsxRuntime.jsxs("div", {
64295
64413
  className: "flex-1 min-w-0 overflow-hidden flex flex-col",
64296
64414
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
64297
- className: "flex-shrink-0 px-4 py-2 text-xs opacity-60",
64415
+ className: "flex-shrink-0 px-4 pb-3 text-xs border-b ".concat(muted, " ").concat(hairline),
64298
64416
  children: ["Check an event to fire ", /*#__PURE__*/jsxRuntime.jsx("code", {
64299
64417
  className: "text-xs",
64300
64418
  children: handlerName
@@ -64302,22 +64420,21 @@ function EventsColumn(_ref11) {
64302
64420
  className: "font-medium",
64303
64421
  children: receiver.label
64304
64422
  }), "."]
64305
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsx("div", {
64306
- className: "flex-1 overflow-y-auto p-4 space-y-5",
64423
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
64424
+ className: "flex-1 overflow-y-auto p-4 flex flex-col gap-3",
64307
64425
  children: emittersForList.length === 0 ? /*#__PURE__*/jsxRuntime.jsx("div", {
64308
- className: "text-sm opacity-60",
64426
+ className: "text-sm ".concat(muted),
64309
64427
  children: "No other widgets in this dashboard emit events."
64310
64428
  }) : emittersForList.map(function (e) {
64311
64429
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
64312
- className: "space-y-1",
64430
+ className: "rounded-lg border px-3 py-2 flex flex-col gap-1 ".concat(hairline),
64313
64431
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
64314
64432
  className: "flex flex-col gap-0.5 mb-1",
64315
64433
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
64316
64434
  className: "text-sm font-semibold",
64317
64435
  children: e.label
64318
- }), (e.widgetRef || e.component) && /*#__PURE__*/jsxRuntime.jsx(DashReact.Caption, {
64319
- block: true,
64320
- className: "font-mono truncate",
64436
+ }), (e.widgetRef || e.component) && /*#__PURE__*/jsxRuntime.jsx("div", {
64437
+ className: "text-xs font-mono truncate ".concat(muted),
64321
64438
  children: (e.widgetRef || e.component) + (e.itemId != null ? "[".concat(e.itemId, "]") : "")
64322
64439
  })]
64323
64440
  }), e.events.map(function (eventName) {