@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.js CHANGED
@@ -14685,7 +14685,18 @@ function forEachWidget(workspace, visit) {
14685
14685
  _iterator2.f();
14686
14686
  }
14687
14687
  };
14688
- _walk(workspace.layout);
14688
+
14689
+ // Walk pages BEFORE workspace.layout. WorkspaceModel auto-migrates a
14690
+ // workspace with no persisted `pages` by aliasing pages[0].layout to
14691
+ // workspace.layout. After any per-page edit, pages[0].layout is
14692
+ // replaced with a new array (fresh) but workspace.layout is left
14693
+ // pointing at the original (stale) array. Walking layout first +
14694
+ // dedupe-by-stableId then visited the stale top-level item and
14695
+ // skipped the fresh page version, so the bulk-edit modal kept
14696
+ // reading pre-edit provider bindings. Walking pages first means the
14697
+ // fresh data wins; workspace.layout remains as a fallback for
14698
+ // widgets that only live there (e.g. AI-place writes that bypass
14699
+ // the page handler).
14689
14700
  if (Array.isArray(workspace.pages)) {
14690
14701
  var _iterator3 = _createForOfIteratorHelper$t(workspace.pages),
14691
14702
  _step3;
@@ -14700,6 +14711,7 @@ function forEachWidget(workspace, visit) {
14700
14711
  _iterator3.f();
14701
14712
  }
14702
14713
  }
14714
+ _walk(workspace.layout);
14703
14715
  _walk(workspace.sidebarLayout);
14704
14716
  }
14705
14717
 
@@ -52880,11 +52892,12 @@ var EditField = function EditField(_ref7) {
52880
52892
 
52881
52893
  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; }
52882
52894
  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; }
52895
+ var GLOBAL_KEY = "__global__";
52883
52896
  var NotificationsSection = function NotificationsSection(_ref) {
52884
52897
  var _ref$workspaces = _ref.workspaces,
52885
52898
  workspaces = _ref$workspaces === void 0 ? [] : _ref$workspaces;
52886
- var appContext = React.useContext(AppContext);
52887
- appContext === null || appContext === void 0 ? void 0 : appContext.dashApi;
52899
+ React.useContext(AppContext);
52900
+
52888
52901
  var _useState = React.useState(true),
52889
52902
  _useState2 = _slicedToArray(_useState, 2),
52890
52903
  globalEnabled = _useState2[0],
@@ -52901,6 +52914,14 @@ var NotificationsSection = function NotificationsSection(_ref) {
52901
52914
  _useState8 = _slicedToArray(_useState7, 2),
52902
52915
  loading = _useState8[0],
52903
52916
  setLoading = _useState8[1];
52917
+ var _useState9 = React.useState(""),
52918
+ _useState0 = _slicedToArray(_useState9, 2),
52919
+ searchQuery = _useState0[0],
52920
+ setSearchQuery = _useState0[1];
52921
+ var _useState1 = React.useState(GLOBAL_KEY),
52922
+ _useState10 = _slicedToArray(_useState1, 2),
52923
+ selectedKey = _useState10[0],
52924
+ setSelectedKey = _useState10[1];
52904
52925
 
52905
52926
  // Load preferences on mount
52906
52927
  React.useEffect(function () {
@@ -52917,38 +52938,46 @@ var NotificationsSection = function NotificationsSection(_ref) {
52917
52938
  });
52918
52939
  }, []);
52919
52940
 
52920
- // Collect all widget instances with notifications from workspaces.
52921
- // Route through `ComponentManager.resolve` so a legacy layout
52922
- // referencing a bare component name still finds its registered
52923
- // scoped form (post-v0.1.432). Direct `componentMap[item.component]`
52924
- // returns undefined for bare names after the migration.
52925
- var widgetInstances = [];
52926
- workspaces.forEach(function (ws) {
52927
- var items = flattenLayout(ws.layout);
52928
- items.forEach(function (item) {
52929
- var _config$notifications;
52930
- var config = ComponentManager.resolve(item.component, item);
52931
- if ((config === null || config === void 0 || (_config$notifications = config.notifications) === null || _config$notifications === void 0 ? void 0 : _config$notifications.length) > 0) {
52932
- var _item$userPrefs;
52933
- widgetInstances.push({
52934
- uuid: item.uuid || item.uuidString,
52935
- componentName: item.component,
52936
- title: ((_item$userPrefs = item.userPrefs) === null || _item$userPrefs === void 0 ? void 0 : _item$userPrefs.title) || config.displayName || item.component,
52937
- workspaceName: ws.name || ws.id,
52938
- notifications: config.notifications,
52939
- "package": config["package"]
52940
- });
52941
- }
52941
+ // Collect every widget instance with notifications, alphabetized
52942
+ // by display title. Route through `ComponentManager.resolve` so a
52943
+ // legacy layout referencing a bare component name still finds the
52944
+ // registered scoped form.
52945
+ var widgetInstances = React.useMemo(function () {
52946
+ var out = [];
52947
+ workspaces.forEach(function (ws) {
52948
+ var items = flattenLayout(ws.layout);
52949
+ items.forEach(function (item) {
52950
+ var _config$notifications;
52951
+ var config = ComponentManager.resolve(item.component, item);
52952
+ if ((config === null || config === void 0 || (_config$notifications = config.notifications) === null || _config$notifications === void 0 ? void 0 : _config$notifications.length) > 0) {
52953
+ var _item$userPrefs;
52954
+ out.push({
52955
+ uuid: item.uuid || item.uuidString,
52956
+ componentName: item.component,
52957
+ title: ((_item$userPrefs = item.userPrefs) === null || _item$userPrefs === void 0 ? void 0 : _item$userPrefs.title) || config.displayName || item.component,
52958
+ workspaceName: ws.name || ws.id,
52959
+ notifications: config.notifications,
52960
+ "package": config["package"] || "Other"
52961
+ });
52962
+ }
52963
+ });
52942
52964
  });
52943
- });
52965
+ return out.sort(function (a, b) {
52966
+ return String(a.title).localeCompare(String(b.title), undefined, {
52967
+ sensitivity: "base"
52968
+ });
52969
+ });
52970
+ }, [workspaces]);
52944
52971
 
52945
- // Group by package
52946
- var grouped = {};
52947
- widgetInstances.forEach(function (wi) {
52948
- var pkg = wi["package"] || "Other";
52949
- if (!grouped[pkg]) grouped[pkg] = [];
52950
- grouped[pkg].push(wi);
52951
- });
52972
+ // Filter by search.
52973
+ var filteredInstances = React.useMemo(function () {
52974
+ var q = searchQuery.trim().toLowerCase();
52975
+ if (!q) return widgetInstances;
52976
+ return widgetInstances.filter(function (wi) {
52977
+ var hay = [wi.title, wi["package"], wi.workspaceName, wi.componentName].filter(Boolean).join(" ").toLowerCase();
52978
+ return hay.includes(q);
52979
+ });
52980
+ }, [widgetInstances, searchQuery]);
52952
52981
  function handleGlobalToggle(value) {
52953
52982
  var _window$mainApi2;
52954
52983
  setGlobalEnabled(value);
@@ -52982,16 +53011,85 @@ var NotificationsSection = function NotificationsSection(_ref) {
52982
53011
  children: "Loading notification preferences..."
52983
53012
  });
52984
53013
  }
52985
- return /*#__PURE__*/jsxRuntime.jsx("div", {
52986
- className: "flex-1 overflow-y-auto p-6",
52987
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
52988
- className: "flex flex-col space-y-6",
52989
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
53014
+
53015
+ // ── Left list ──────────────────────────────────────────────────────
53016
+ var listContent = /*#__PURE__*/jsxRuntime.jsxs("div", {
53017
+ className: "flex flex-col h-full",
53018
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
53019
+ className: "flex flex-col gap-2 px-3 py-2 flex-shrink-0 border-b border-white/10",
53020
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SearchInput, {
53021
+ value: searchQuery,
53022
+ onChange: setSearchQuery,
53023
+ placeholder: "Search widgets...",
53024
+ inputClassName: "py-1.5 text-xs"
53025
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
53026
+ className: "text-[10px] opacity-50 px-0.5",
53027
+ children: [filteredInstances.length, " of ", widgetInstances.length, " widget", widgetInstances.length === 1 ? "" : "s"]
53028
+ })]
53029
+ }), /*#__PURE__*/jsxRuntime.jsxs(DashReact.Sidebar.Content, {
53030
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Sidebar.Item, {
53031
+ icon: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
53032
+ icon: globalEnabled ? "bell" : "bell-slash",
53033
+ className: "h-3.5 w-3.5"
53034
+ }),
53035
+ active: selectedKey === GLOBAL_KEY,
53036
+ onClick: function onClick() {
53037
+ return setSelectedKey(GLOBAL_KEY);
53038
+ },
53039
+ children: /*#__PURE__*/jsxRuntime.jsxs("span", {
53040
+ className: "flex flex-col",
53041
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
53042
+ className: "font-medium",
53043
+ children: "Global"
53044
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
53045
+ className: "text-[10px] opacity-40",
53046
+ children: "Master switch + Do Not Disturb"
53047
+ })]
53048
+ })
53049
+ }), filteredInstances.length === 0 && widgetInstances.length === 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
53050
+ className: "px-3 py-2 text-xs opacity-50",
53051
+ children: "No widgets with notification support found. Add widgets that declare notifications to see per-type controls here."
53052
+ }), filteredInstances.length === 0 && widgetInstances.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
53053
+ className: "px-3 py-2 text-xs opacity-50",
53054
+ children: ["No widgets match \"", searchQuery, "\"."]
53055
+ }), filteredInstances.map(function (wi) {
53056
+ var isActive = selectedKey === wi.uuid;
53057
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.Sidebar.Item, {
53058
+ icon: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
53059
+ icon: "bell",
53060
+ className: "h-3.5 w-3.5"
53061
+ }),
53062
+ active: isActive,
53063
+ onClick: function onClick() {
53064
+ return setSelectedKey(wi.uuid);
53065
+ },
53066
+ className: isActive ? "bg-white/10 opacity-100" : "",
53067
+ children: /*#__PURE__*/jsxRuntime.jsxs("span", {
53068
+ className: "flex flex-col",
53069
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
53070
+ className: "font-medium truncate",
53071
+ children: wi.title
53072
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
53073
+ className: "text-[10px] opacity-40 truncate",
53074
+ children: [wi["package"], wi.workspaceName ? " \xB7 ".concat(wi.workspaceName) : ""]
53075
+ })]
53076
+ })
53077
+ }, wi.uuid);
53078
+ })]
53079
+ })]
53080
+ });
53081
+
53082
+ // ── Right detail ───────────────────────────────────────────────────
53083
+ var detailContent;
53084
+ if (selectedKey === GLOBAL_KEY) {
53085
+ detailContent = /*#__PURE__*/jsxRuntime.jsxs("div", {
53086
+ className: "flex flex-col p-6 space-y-6",
53087
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SubHeading3, {
53088
+ title: "Global",
53089
+ padding: false
53090
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
52990
53091
  className: "flex flex-col space-y-3",
52991
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SubHeading3, {
52992
- title: "Global",
52993
- padding: false
52994
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
53092
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
52995
53093
  className: "flex flex-row items-center justify-between py-2",
52996
53094
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
52997
53095
  className: "flex flex-col",
@@ -53022,49 +53120,59 @@ var NotificationsSection = function NotificationsSection(_ref) {
53022
53120
  onChange: handleDndToggle
53023
53121
  })]
53024
53122
  })]
53025
- }), Object.keys(grouped).length > 0 ? Object.entries(grouped).map(function (_ref2) {
53026
- var _ref3 = _slicedToArray(_ref2, 2),
53027
- pkg = _ref3[0],
53028
- widgets = _ref3[1];
53029
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
53030
- className: "flex flex-col space-y-3",
53123
+ })]
53124
+ });
53125
+ } else {
53126
+ var wi = widgetInstances.find(function (w) {
53127
+ return w.uuid === selectedKey;
53128
+ });
53129
+ if (!wi) {
53130
+ detailContent = /*#__PURE__*/jsxRuntime.jsx("div", {
53131
+ className: "flex-1 p-6 text-sm opacity-50",
53132
+ children: "Select a widget on the left to configure its notifications."
53133
+ });
53134
+ } else {
53135
+ detailContent = /*#__PURE__*/jsxRuntime.jsxs("div", {
53136
+ className: "flex flex-col p-6 space-y-4",
53137
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
53138
+ className: "flex flex-col space-y-1",
53031
53139
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SubHeading3, {
53032
- title: pkg,
53140
+ title: wi.title,
53033
53141
  padding: false
53034
- }), widgets.map(function (wi) {
53142
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
53143
+ className: "text-xs opacity-50",
53144
+ children: [wi["package"], wi.workspaceName ? " \xB7 ".concat(wi.workspaceName) : ""]
53145
+ })]
53146
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
53147
+ className: "flex flex-col space-y-3",
53148
+ children: wi.notifications.map(function (notif) {
53035
53149
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
53036
- className: "flex flex-col space-y-2 pl-2 border-l-2 border-white/10",
53037
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
53038
- className: "text-sm font-medium opacity-80",
53039
- children: wi.title
53040
- }), wi.notifications.map(function (notif) {
53041
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
53042
- className: "flex flex-row items-center justify-between py-1 pl-2",
53043
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
53044
- className: "flex flex-col",
53045
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
53046
- className: "text-sm",
53047
- children: notif.displayName
53048
- }), notif.description && /*#__PURE__*/jsxRuntime.jsx("span", {
53049
- className: "text-xs opacity-50",
53050
- children: notif.description
53051
- })]
53052
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Switch, {
53053
- checked: getTypeEnabled(wi.uuid, notif.key, notif.defaultEnabled),
53054
- onChange: function onChange(value) {
53055
- return handleTypeToggle(wi.uuid, notif.key, value);
53056
- }
53057
- })]
53058
- }, notif.key);
53150
+ className: "flex flex-row items-center justify-between py-1",
53151
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
53152
+ className: "flex flex-col",
53153
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
53154
+ className: "text-sm",
53155
+ children: notif.displayName
53156
+ }), notif.description && /*#__PURE__*/jsxRuntime.jsx("span", {
53157
+ className: "text-xs opacity-50",
53158
+ children: notif.description
53159
+ })]
53160
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Switch, {
53161
+ checked: getTypeEnabled(wi.uuid, notif.key, notif.defaultEnabled),
53162
+ onChange: function onChange(value) {
53163
+ return handleTypeToggle(wi.uuid, notif.key, value);
53164
+ }
53059
53165
  })]
53060
- }, wi.uuid);
53061
- })]
53062
- }, pkg);
53063
- }) : /*#__PURE__*/jsxRuntime.jsx("div", {
53064
- className: "text-sm opacity-50",
53065
- children: "No widgets with notification support found. Add widgets that declare notifications to see per-type controls here."
53066
- })]
53067
- })
53166
+ }, notif.key);
53167
+ })
53168
+ })]
53169
+ });
53170
+ }
53171
+ }
53172
+ return /*#__PURE__*/jsxRuntime.jsx(SectionLayout, {
53173
+ listContent: listContent,
53174
+ detailContent: detailContent,
53175
+ emptyDetailMessage: "Select a widget to configure notifications"
53068
53176
  });
53069
53177
  };
53070
53178