@trops/dash-core 0.1.469 → 0.1.471

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.esm.js CHANGED
@@ -14667,7 +14667,18 @@ function forEachWidget(workspace, visit) {
14667
14667
  _iterator2.f();
14668
14668
  }
14669
14669
  };
14670
- _walk(workspace.layout);
14670
+
14671
+ // Walk pages BEFORE workspace.layout. WorkspaceModel auto-migrates a
14672
+ // workspace with no persisted `pages` by aliasing pages[0].layout to
14673
+ // workspace.layout. After any per-page edit, pages[0].layout is
14674
+ // replaced with a new array (fresh) but workspace.layout is left
14675
+ // pointing at the original (stale) array. Walking layout first +
14676
+ // dedupe-by-stableId then visited the stale top-level item and
14677
+ // skipped the fresh page version, so the bulk-edit modal kept
14678
+ // reading pre-edit provider bindings. Walking pages first means the
14679
+ // fresh data wins; workspace.layout remains as a fallback for
14680
+ // widgets that only live there (e.g. AI-place writes that bypass
14681
+ // the page handler).
14671
14682
  if (Array.isArray(workspace.pages)) {
14672
14683
  var _iterator3 = _createForOfIteratorHelper$t(workspace.pages),
14673
14684
  _step3;
@@ -14682,6 +14693,7 @@ function forEachWidget(workspace, visit) {
14682
14693
  _iterator3.f();
14683
14694
  }
14684
14695
  }
14696
+ _walk(workspace.layout);
14685
14697
  _walk(workspace.sidebarLayout);
14686
14698
  }
14687
14699
 
@@ -52862,11 +52874,12 @@ var EditField = function EditField(_ref7) {
52862
52874
 
52863
52875
  function ownKeys$h(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; }
52864
52876
  function _objectSpread$h(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$h(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$h(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
52877
+ var GLOBAL_KEY = "__global__";
52865
52878
  var NotificationsSection = function NotificationsSection(_ref) {
52866
52879
  var _ref$workspaces = _ref.workspaces,
52867
52880
  workspaces = _ref$workspaces === void 0 ? [] : _ref$workspaces;
52868
- var appContext = useContext(AppContext);
52869
- appContext === null || appContext === void 0 ? void 0 : appContext.dashApi;
52881
+ useContext(AppContext);
52882
+
52870
52883
  var _useState = useState(true),
52871
52884
  _useState2 = _slicedToArray(_useState, 2),
52872
52885
  globalEnabled = _useState2[0],
@@ -52883,6 +52896,14 @@ var NotificationsSection = function NotificationsSection(_ref) {
52883
52896
  _useState8 = _slicedToArray(_useState7, 2),
52884
52897
  loading = _useState8[0],
52885
52898
  setLoading = _useState8[1];
52899
+ var _useState9 = useState(""),
52900
+ _useState0 = _slicedToArray(_useState9, 2),
52901
+ searchQuery = _useState0[0],
52902
+ setSearchQuery = _useState0[1];
52903
+ var _useState1 = useState(GLOBAL_KEY),
52904
+ _useState10 = _slicedToArray(_useState1, 2),
52905
+ selectedKey = _useState10[0],
52906
+ setSelectedKey = _useState10[1];
52886
52907
 
52887
52908
  // Load preferences on mount
52888
52909
  useEffect(function () {
@@ -52899,38 +52920,46 @@ var NotificationsSection = function NotificationsSection(_ref) {
52899
52920
  });
52900
52921
  }, []);
52901
52922
 
52902
- // Collect all widget instances with notifications from workspaces.
52903
- // Route through `ComponentManager.resolve` so a legacy layout
52904
- // referencing a bare component name still finds its registered
52905
- // scoped form (post-v0.1.432). Direct `componentMap[item.component]`
52906
- // returns undefined for bare names after the migration.
52907
- var widgetInstances = [];
52908
- workspaces.forEach(function (ws) {
52909
- var items = flattenLayout(ws.layout);
52910
- items.forEach(function (item) {
52911
- var _config$notifications;
52912
- var config = ComponentManager.resolve(item.component, item);
52913
- if ((config === null || config === void 0 || (_config$notifications = config.notifications) === null || _config$notifications === void 0 ? void 0 : _config$notifications.length) > 0) {
52914
- var _item$userPrefs;
52915
- widgetInstances.push({
52916
- uuid: item.uuid || item.uuidString,
52917
- componentName: item.component,
52918
- title: ((_item$userPrefs = item.userPrefs) === null || _item$userPrefs === void 0 ? void 0 : _item$userPrefs.title) || config.displayName || item.component,
52919
- workspaceName: ws.name || ws.id,
52920
- notifications: config.notifications,
52921
- "package": config["package"]
52922
- });
52923
- }
52923
+ // Collect every widget instance with notifications, alphabetized
52924
+ // by display title. Route through `ComponentManager.resolve` so a
52925
+ // legacy layout referencing a bare component name still finds the
52926
+ // registered scoped form.
52927
+ var widgetInstances = useMemo(function () {
52928
+ var out = [];
52929
+ workspaces.forEach(function (ws) {
52930
+ var items = flattenLayout(ws.layout);
52931
+ items.forEach(function (item) {
52932
+ var _config$notifications;
52933
+ var config = ComponentManager.resolve(item.component, item);
52934
+ if ((config === null || config === void 0 || (_config$notifications = config.notifications) === null || _config$notifications === void 0 ? void 0 : _config$notifications.length) > 0) {
52935
+ var _item$userPrefs;
52936
+ out.push({
52937
+ uuid: item.uuid || item.uuidString,
52938
+ componentName: item.component,
52939
+ title: ((_item$userPrefs = item.userPrefs) === null || _item$userPrefs === void 0 ? void 0 : _item$userPrefs.title) || config.displayName || item.component,
52940
+ workspaceName: ws.name || ws.id,
52941
+ notifications: config.notifications,
52942
+ "package": config["package"] || "Other"
52943
+ });
52944
+ }
52945
+ });
52924
52946
  });
52925
- });
52947
+ return out.sort(function (a, b) {
52948
+ return String(a.title).localeCompare(String(b.title), undefined, {
52949
+ sensitivity: "base"
52950
+ });
52951
+ });
52952
+ }, [workspaces]);
52926
52953
 
52927
- // Group by package
52928
- var grouped = {};
52929
- widgetInstances.forEach(function (wi) {
52930
- var pkg = wi["package"] || "Other";
52931
- if (!grouped[pkg]) grouped[pkg] = [];
52932
- grouped[pkg].push(wi);
52933
- });
52954
+ // Filter by search.
52955
+ var filteredInstances = useMemo(function () {
52956
+ var q = searchQuery.trim().toLowerCase();
52957
+ if (!q) return widgetInstances;
52958
+ return widgetInstances.filter(function (wi) {
52959
+ var hay = [wi.title, wi["package"], wi.workspaceName, wi.componentName].filter(Boolean).join(" ").toLowerCase();
52960
+ return hay.includes(q);
52961
+ });
52962
+ }, [widgetInstances, searchQuery]);
52934
52963
  function handleGlobalToggle(value) {
52935
52964
  var _window$mainApi2;
52936
52965
  setGlobalEnabled(value);
@@ -52964,16 +52993,85 @@ var NotificationsSection = function NotificationsSection(_ref) {
52964
52993
  children: "Loading notification preferences..."
52965
52994
  });
52966
52995
  }
52967
- return /*#__PURE__*/jsx("div", {
52968
- className: "flex-1 overflow-y-auto p-6",
52969
- children: /*#__PURE__*/jsxs("div", {
52970
- className: "flex flex-col space-y-6",
52971
- children: [/*#__PURE__*/jsxs("div", {
52996
+
52997
+ // ── Left list ──────────────────────────────────────────────────────
52998
+ var listContent = /*#__PURE__*/jsxs("div", {
52999
+ className: "flex flex-col h-full",
53000
+ children: [/*#__PURE__*/jsxs("div", {
53001
+ className: "flex flex-col gap-2 px-3 py-2 flex-shrink-0 border-b border-white/10",
53002
+ children: [/*#__PURE__*/jsx(SearchInput, {
53003
+ value: searchQuery,
53004
+ onChange: setSearchQuery,
53005
+ placeholder: "Search widgets...",
53006
+ inputClassName: "py-1.5 text-xs"
53007
+ }), /*#__PURE__*/jsxs("div", {
53008
+ className: "text-[10px] opacity-50 px-0.5",
53009
+ children: [filteredInstances.length, " of ", widgetInstances.length, " widget", widgetInstances.length === 1 ? "" : "s"]
53010
+ })]
53011
+ }), /*#__PURE__*/jsxs(Sidebar.Content, {
53012
+ children: [/*#__PURE__*/jsx(Sidebar.Item, {
53013
+ icon: /*#__PURE__*/jsx(FontAwesomeIcon, {
53014
+ icon: globalEnabled ? "bell" : "bell-slash",
53015
+ className: "h-3.5 w-3.5"
53016
+ }),
53017
+ active: selectedKey === GLOBAL_KEY,
53018
+ onClick: function onClick() {
53019
+ return setSelectedKey(GLOBAL_KEY);
53020
+ },
53021
+ children: /*#__PURE__*/jsxs("span", {
53022
+ className: "flex flex-col",
53023
+ children: [/*#__PURE__*/jsx("span", {
53024
+ className: "font-medium",
53025
+ children: "Global"
53026
+ }), /*#__PURE__*/jsx("span", {
53027
+ className: "text-[10px] opacity-40",
53028
+ children: "Master switch + Do Not Disturb"
53029
+ })]
53030
+ })
53031
+ }), filteredInstances.length === 0 && widgetInstances.length === 0 && /*#__PURE__*/jsx("div", {
53032
+ className: "px-3 py-2 text-xs opacity-50",
53033
+ children: "No widgets with notification support found. Add widgets that declare notifications to see per-type controls here."
53034
+ }), filteredInstances.length === 0 && widgetInstances.length > 0 && /*#__PURE__*/jsxs("div", {
53035
+ className: "px-3 py-2 text-xs opacity-50",
53036
+ children: ["No widgets match \"", searchQuery, "\"."]
53037
+ }), filteredInstances.map(function (wi) {
53038
+ var isActive = selectedKey === wi.uuid;
53039
+ return /*#__PURE__*/jsx(Sidebar.Item, {
53040
+ icon: /*#__PURE__*/jsx(FontAwesomeIcon, {
53041
+ icon: "bell",
53042
+ className: "h-3.5 w-3.5"
53043
+ }),
53044
+ active: isActive,
53045
+ onClick: function onClick() {
53046
+ return setSelectedKey(wi.uuid);
53047
+ },
53048
+ className: isActive ? "bg-white/10 opacity-100" : "",
53049
+ children: /*#__PURE__*/jsxs("span", {
53050
+ className: "flex flex-col",
53051
+ children: [/*#__PURE__*/jsx("span", {
53052
+ className: "font-medium truncate",
53053
+ children: wi.title
53054
+ }), /*#__PURE__*/jsxs("span", {
53055
+ className: "text-[10px] opacity-40 truncate",
53056
+ children: [wi["package"], wi.workspaceName ? " \xB7 ".concat(wi.workspaceName) : ""]
53057
+ })]
53058
+ })
53059
+ }, wi.uuid);
53060
+ })]
53061
+ })]
53062
+ });
53063
+
53064
+ // ── Right detail ───────────────────────────────────────────────────
53065
+ var detailContent;
53066
+ if (selectedKey === GLOBAL_KEY) {
53067
+ detailContent = /*#__PURE__*/jsxs("div", {
53068
+ className: "flex flex-col p-6 space-y-6",
53069
+ children: [/*#__PURE__*/jsx(SubHeading3, {
53070
+ title: "Global",
53071
+ padding: false
53072
+ }), /*#__PURE__*/jsxs("div", {
52972
53073
  className: "flex flex-col space-y-3",
52973
- children: [/*#__PURE__*/jsx(SubHeading3, {
52974
- title: "Global",
52975
- padding: false
52976
- }), /*#__PURE__*/jsxs("div", {
53074
+ children: [/*#__PURE__*/jsxs("div", {
52977
53075
  className: "flex flex-row items-center justify-between py-2",
52978
53076
  children: [/*#__PURE__*/jsxs("div", {
52979
53077
  className: "flex flex-col",
@@ -53004,49 +53102,59 @@ var NotificationsSection = function NotificationsSection(_ref) {
53004
53102
  onChange: handleDndToggle
53005
53103
  })]
53006
53104
  })]
53007
- }), Object.keys(grouped).length > 0 ? Object.entries(grouped).map(function (_ref2) {
53008
- var _ref3 = _slicedToArray(_ref2, 2),
53009
- pkg = _ref3[0],
53010
- widgets = _ref3[1];
53011
- return /*#__PURE__*/jsxs("div", {
53012
- className: "flex flex-col space-y-3",
53105
+ })]
53106
+ });
53107
+ } else {
53108
+ var wi = widgetInstances.find(function (w) {
53109
+ return w.uuid === selectedKey;
53110
+ });
53111
+ if (!wi) {
53112
+ detailContent = /*#__PURE__*/jsx("div", {
53113
+ className: "flex-1 p-6 text-sm opacity-50",
53114
+ children: "Select a widget on the left to configure its notifications."
53115
+ });
53116
+ } else {
53117
+ detailContent = /*#__PURE__*/jsxs("div", {
53118
+ className: "flex flex-col p-6 space-y-4",
53119
+ children: [/*#__PURE__*/jsxs("div", {
53120
+ className: "flex flex-col space-y-1",
53013
53121
  children: [/*#__PURE__*/jsx(SubHeading3, {
53014
- title: pkg,
53122
+ title: wi.title,
53015
53123
  padding: false
53016
- }), widgets.map(function (wi) {
53124
+ }), /*#__PURE__*/jsxs("span", {
53125
+ className: "text-xs opacity-50",
53126
+ children: [wi["package"], wi.workspaceName ? " \xB7 ".concat(wi.workspaceName) : ""]
53127
+ })]
53128
+ }), /*#__PURE__*/jsx("div", {
53129
+ className: "flex flex-col space-y-3",
53130
+ children: wi.notifications.map(function (notif) {
53017
53131
  return /*#__PURE__*/jsxs("div", {
53018
- className: "flex flex-col space-y-2 pl-2 border-l-2 border-white/10",
53019
- children: [/*#__PURE__*/jsx("span", {
53020
- className: "text-sm font-medium opacity-80",
53021
- children: wi.title
53022
- }), wi.notifications.map(function (notif) {
53023
- return /*#__PURE__*/jsxs("div", {
53024
- className: "flex flex-row items-center justify-between py-1 pl-2",
53025
- children: [/*#__PURE__*/jsxs("div", {
53026
- className: "flex flex-col",
53027
- children: [/*#__PURE__*/jsx("span", {
53028
- className: "text-sm",
53029
- children: notif.displayName
53030
- }), notif.description && /*#__PURE__*/jsx("span", {
53031
- className: "text-xs opacity-50",
53032
- children: notif.description
53033
- })]
53034
- }), /*#__PURE__*/jsx(Switch, {
53035
- checked: getTypeEnabled(wi.uuid, notif.key, notif.defaultEnabled),
53036
- onChange: function onChange(value) {
53037
- return handleTypeToggle(wi.uuid, notif.key, value);
53038
- }
53039
- })]
53040
- }, notif.key);
53132
+ className: "flex flex-row items-center justify-between py-1",
53133
+ children: [/*#__PURE__*/jsxs("div", {
53134
+ className: "flex flex-col",
53135
+ children: [/*#__PURE__*/jsx("span", {
53136
+ className: "text-sm",
53137
+ children: notif.displayName
53138
+ }), notif.description && /*#__PURE__*/jsx("span", {
53139
+ className: "text-xs opacity-50",
53140
+ children: notif.description
53141
+ })]
53142
+ }), /*#__PURE__*/jsx(Switch, {
53143
+ checked: getTypeEnabled(wi.uuid, notif.key, notif.defaultEnabled),
53144
+ onChange: function onChange(value) {
53145
+ return handleTypeToggle(wi.uuid, notif.key, value);
53146
+ }
53041
53147
  })]
53042
- }, wi.uuid);
53043
- })]
53044
- }, pkg);
53045
- }) : /*#__PURE__*/jsx("div", {
53046
- className: "text-sm opacity-50",
53047
- children: "No widgets with notification support found. Add widgets that declare notifications to see per-type controls here."
53048
- })]
53049
- })
53148
+ }, notif.key);
53149
+ })
53150
+ })]
53151
+ });
53152
+ }
53153
+ }
53154
+ return /*#__PURE__*/jsx(SectionLayout, {
53155
+ listContent: listContent,
53156
+ detailContent: detailContent,
53157
+ emptyDetailMessage: "Select a widget to configure notifications"
53050
53158
  });
53051
53159
  };
53052
53160