@trops/dash-core 0.1.225 → 0.1.227

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
@@ -5897,6 +5897,29 @@ var WizardDiscoverStep = function WizardDiscoverStep(_ref) {
5897
5897
  payload: prov
5898
5898
  });
5899
5899
  }, [dispatch]);
5900
+
5901
+ // Tab state (DASH-185)
5902
+ var _useState = React.useState("dashboards"),
5903
+ _useState2 = _slicedToArray(_useState, 2),
5904
+ activeTab = _useState2[0],
5905
+ setActiveTab = _useState2[1];
5906
+
5907
+ // Clear selection handler (DASH-186)
5908
+ var hasSelection = state.selectedDashboard !== null || state.selectedWidgets.length > 0;
5909
+ var handleClearSelection = React.useCallback(function () {
5910
+ dispatch({
5911
+ type: "SET_SELECTED_DASHBOARD",
5912
+ payload: null
5913
+ });
5914
+ dispatch({
5915
+ type: "SET_SELECTED_WIDGETS",
5916
+ payload: []
5917
+ });
5918
+ dispatch({
5919
+ type: "SET_PATH",
5920
+ payload: null
5921
+ });
5922
+ }, [dispatch]);
5900
5923
  var hasResults = filteredDashboards.length > 0 || filteredWidgets.length > 0;
5901
5924
  var hasActiveFilters = filters.categories.length > 0 || filters.providers.length > 0;
5902
5925
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -5942,8 +5965,43 @@ var WizardDiscoverStep = function WizardDiscoverStep(_ref) {
5942
5965
  })
5943
5966
  })]
5944
5967
  })]
5968
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
5969
+ className: "flex items-center justify-between",
5970
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
5971
+ className: "flex gap-1",
5972
+ children: [/*#__PURE__*/jsxRuntime.jsxs("button", {
5973
+ type: "button",
5974
+ className: "px-4 py-2 text-sm font-medium rounded-t transition-colors ".concat(activeTab === "dashboards" ? "bg-gray-800 text-blue-400 border-b-2 border-blue-400" : "text-gray-400 hover:text-gray-200"),
5975
+ onClick: function onClick() {
5976
+ return setActiveTab("dashboards");
5977
+ },
5978
+ children: ["Dashboards (", filteredDashboards.length, ")"]
5979
+ }), /*#__PURE__*/jsxRuntime.jsxs("button", {
5980
+ type: "button",
5981
+ className: "px-4 py-2 text-sm font-medium rounded-t transition-colors ".concat(activeTab === "widgets" ? "bg-gray-800 text-blue-400 border-b-2 border-blue-400" : "text-gray-400 hover:text-gray-200"),
5982
+ onClick: function onClick() {
5983
+ return setActiveTab("widgets");
5984
+ },
5985
+ children: ["Widgets (", filteredWidgets.length, ")", state.selectedWidgets.length > 0 && /*#__PURE__*/jsxRuntime.jsx("span", {
5986
+ className: "ml-1.5",
5987
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Tag3, {
5988
+ text: "".concat(state.selectedWidgets.length, " selected")
5989
+ })
5990
+ })]
5991
+ })]
5992
+ }), hasSelection && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
5993
+ onClick: handleClearSelection,
5994
+ title: "Clear Selection",
5995
+ textSize: "text-xs",
5996
+ padding: "py-1 px-3",
5997
+ backgroundColor: "bg-gray-700",
5998
+ textColor: "text-gray-400",
5999
+ hoverTextColor: "hover:text-white",
6000
+ hoverBackgroundColor: "hover:bg-gray-600",
6001
+ icon: "xmark"
6002
+ })]
5945
6003
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
5946
- className: "flex flex-col gap-6 mt-2",
6004
+ className: "flex flex-col gap-6",
5947
6005
  children: isLoading ? /*#__PURE__*/jsxRuntime.jsxs("div", {
5948
6006
  className: "flex flex-col items-center justify-center gap-2 py-12 text-gray-400",
5949
6007
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
@@ -5973,12 +6031,9 @@ var WizardDiscoverStep = function WizardDiscoverStep(_ref) {
5973
6031
  children: "Try removing some filters to see more results."
5974
6032
  })]
5975
6033
  }) : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
5976
- children: [filteredDashboards.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6034
+ children: [activeTab === "dashboards" && filteredDashboards.length > 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
5977
6035
  className: "flex flex-col gap-3",
5978
- children: [/*#__PURE__*/jsxRuntime.jsxs("h4", {
5979
- className: "text-sm font-semibold text-gray-300 flex items-center gap-2",
5980
- children: ["Dashboards (", filteredDashboards.length, " result", filteredDashboards.length !== 1 ? "s" : "", ")"]
5981
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
6036
+ children: /*#__PURE__*/jsxRuntime.jsx("div", {
5982
6037
  className: "grid grid-cols-3 gap-3",
5983
6038
  children: filteredDashboards.map(function (dash) {
5984
6039
  var isSelected = state.selectedDashboard && state.selectedDashboard.name === dash.name;
@@ -6034,15 +6089,18 @@ var WizardDiscoverStep = function WizardDiscoverStep(_ref) {
6034
6089
  })]
6035
6090
  }, dash.name);
6036
6091
  })
6092
+ })
6093
+ }), activeTab === "dashboards" && filteredDashboards.length === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6094
+ className: "flex flex-col items-center justify-center gap-2 py-12 text-gray-500",
6095
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6096
+ icon: "grid-2",
6097
+ fixedWidth: true
6098
+ }), /*#__PURE__*/jsxRuntime.jsx("p", {
6099
+ children: "No dashboards match your search."
6037
6100
  })]
6038
- }), filteredWidgets.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6101
+ }), activeTab === "widgets" && filteredWidgets.length > 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
6039
6102
  className: "flex flex-col gap-3",
6040
- children: [/*#__PURE__*/jsxRuntime.jsxs("h4", {
6041
- className: "text-sm font-semibold text-gray-300 flex items-center gap-2",
6042
- children: ["Widgets (", filteredWidgets.length, " result", filteredWidgets.length !== 1 ? "s" : "", ")", state.selectedWidgets.length > 0 && /*#__PURE__*/jsxRuntime.jsx(DashReact.Tag3, {
6043
- text: "".concat(state.selectedWidgets.length, " selected")
6044
- })]
6045
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
6103
+ children: /*#__PURE__*/jsxRuntime.jsx("div", {
6046
6104
  className: "grid grid-cols-3 gap-3",
6047
6105
  children: filteredWidgets.map(function (widget) {
6048
6106
  var checked = isWidgetSelected(widget);
@@ -6081,6 +6139,14 @@ var WizardDiscoverStep = function WizardDiscoverStep(_ref) {
6081
6139
  })]
6082
6140
  }, widget.key);
6083
6141
  })
6142
+ })
6143
+ }), activeTab === "widgets" && filteredWidgets.length === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6144
+ className: "flex flex-col items-center justify-center gap-2 py-12 text-gray-500",
6145
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6146
+ icon: "puzzle-piece",
6147
+ fixedWidth: true
6148
+ }), /*#__PURE__*/jsxRuntime.jsx("p", {
6149
+ children: "No widgets match your search."
6084
6150
  })]
6085
6151
  })]
6086
6152
  })
@@ -6118,442 +6184,6 @@ function applyFilters(items, filters, mode) {
6118
6184
 
6119
6185
  function ownKeys$B(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; }
6120
6186
  function _objectSpread$B(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$B(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$B(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6121
- var TOTAL_STEPS = 3; // Steps 0-2: Discover, Layout, Customize
6122
-
6123
- var initialState = {
6124
- step: 0,
6125
- filters: {
6126
- categories: [],
6127
- providers: [],
6128
- query: ""
6129
- },
6130
- selectedWidgets: [],
6131
- selectedDashboard: null,
6132
- layout: {
6133
- templateKey: null,
6134
- widgetOrder: []
6135
- },
6136
- customization: {
6137
- name: "",
6138
- menuId: null,
6139
- theme: null
6140
- },
6141
- path: null
6142
- };
6143
- function wizardReducer(state, action) {
6144
- switch (action.type) {
6145
- case "SET_STEP":
6146
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6147
- step: action.payload
6148
- });
6149
- case "SET_FILTERS":
6150
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6151
- filters: _objectSpread$B(_objectSpread$B({}, state.filters), action.payload)
6152
- });
6153
- case "TOGGLE_FILTER_CATEGORY":
6154
- {
6155
- var categories = state.filters.categories.includes(action.payload) ? state.filters.categories.filter(function (c) {
6156
- return c !== action.payload;
6157
- }) : [].concat(_toConsumableArray(state.filters.categories), [action.payload]);
6158
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6159
- filters: _objectSpread$B(_objectSpread$B({}, state.filters), {}, {
6160
- categories: categories
6161
- })
6162
- });
6163
- }
6164
- case "TOGGLE_FILTER_PROVIDER":
6165
- {
6166
- var providers = state.filters.providers.includes(action.payload) ? state.filters.providers.filter(function (p) {
6167
- return p !== action.payload;
6168
- }) : [].concat(_toConsumableArray(state.filters.providers), [action.payload]);
6169
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6170
- filters: _objectSpread$B(_objectSpread$B({}, state.filters), {}, {
6171
- providers: providers
6172
- })
6173
- });
6174
- }
6175
- case "SET_SEARCH_QUERY":
6176
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6177
- filters: _objectSpread$B(_objectSpread$B({}, state.filters), {}, {
6178
- query: action.payload
6179
- })
6180
- });
6181
- case "SET_SELECTED_WIDGETS":
6182
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6183
- selectedWidgets: action.payload
6184
- });
6185
- case "TOGGLE_WIDGET":
6186
- {
6187
- var exists = state.selectedWidgets.some(function (w) {
6188
- return w.name === action.payload.name;
6189
- });
6190
- var selectedWidgets = exists ? state.selectedWidgets.filter(function (w) {
6191
- return w.name !== action.payload.name;
6192
- }) : [].concat(_toConsumableArray(state.selectedWidgets), [action.payload]);
6193
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6194
- selectedWidgets: selectedWidgets
6195
- });
6196
- }
6197
- case "SET_SELECTED_DASHBOARD":
6198
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6199
- selectedDashboard: action.payload
6200
- });
6201
- case "SET_PATH":
6202
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6203
- path: action.payload
6204
- });
6205
- case "SET_LAYOUT":
6206
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6207
- layout: action.payload
6208
- });
6209
- case "REORDER_WIDGETS":
6210
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6211
- layout: _objectSpread$B(_objectSpread$B({}, state.layout), {}, {
6212
- widgetOrder: action.payload
6213
- })
6214
- });
6215
- case "SET_CUSTOMIZATION":
6216
- return _objectSpread$B(_objectSpread$B({}, state), {}, {
6217
- customization: _objectSpread$B(_objectSpread$B({}, state.customization), action.payload)
6218
- });
6219
- case "RESET":
6220
- return _objectSpread$B({}, initialState);
6221
- default:
6222
- return state;
6223
- }
6224
- }
6225
- function widgetCountToTemplate(count) {
6226
- if (count <= 1) return "single";
6227
- if (count === 2) return "two-columns";
6228
- if (count === 3) return "three-columns";
6229
- if (count === 4) return "two-by-two";
6230
- if (count <= 6) return "two-by-three";
6231
- return "three-by-three";
6232
- }
6233
- function getCanProceed(state) {
6234
- switch (state.step) {
6235
- case 0:
6236
- return state.selectedDashboard !== null || state.selectedWidgets.length > 0;
6237
- case 1:
6238
- return state.layout.templateKey !== null;
6239
- case 2:
6240
- return state.customization.name.trim().length > 0;
6241
- default:
6242
- return false;
6243
- }
6244
- }
6245
- var useWizardState = function useWizardState() {
6246
- var _useReducer = React.useReducer(wizardReducer, initialState),
6247
- _useReducer2 = _slicedToArray(_useReducer, 2),
6248
- state = _useReducer2[0],
6249
- dispatch = _useReducer2[1];
6250
- var canProceed = React.useMemo(function () {
6251
- return getCanProceed(state);
6252
- }, [state]);
6253
- var selectedCount = React.useMemo(function () {
6254
- return state.selectedWidgets.length;
6255
- }, [state.selectedWidgets]);
6256
- var isPrebuiltPath = state.path === "prebuilt";
6257
- var isCustomPath = state.path === "custom";
6258
- var nextStep = React.useCallback(function () {
6259
- if (getCanProceed(state) && state.step < TOTAL_STEPS - 1) {
6260
- dispatch({
6261
- type: "SET_STEP",
6262
- payload: state.step + 1
6263
- });
6264
- }
6265
- }, [state]);
6266
- var prevStep = React.useCallback(function () {
6267
- if (state.step > 0) {
6268
- dispatch({
6269
- type: "SET_STEP",
6270
- payload: state.step - 1
6271
- });
6272
- }
6273
- }, [state.step]);
6274
- var goToStep = React.useCallback(function (n) {
6275
- if (n >= 0 && n < TOTAL_STEPS) {
6276
- dispatch({
6277
- type: "SET_STEP",
6278
- payload: n
6279
- });
6280
- }
6281
- }, []);
6282
- return {
6283
- state: state,
6284
- dispatch: dispatch,
6285
- nextStep: nextStep,
6286
- prevStep: prevStep,
6287
- goToStep: goToStep,
6288
- canProceed: canProceed,
6289
- selectedCount: selectedCount,
6290
- isPrebuiltPath: isPrebuiltPath,
6291
- isCustomPath: isCustomPath,
6292
- widgetCountToTemplate: widgetCountToTemplate
6293
- };
6294
- };
6295
-
6296
- var WizardLayoutPreviewStep = function WizardLayoutPreviewStep(_ref) {
6297
- var state = _ref.state,
6298
- dispatch = _ref.dispatch;
6299
- var isPrebuilt = state.path === "prebuilt";
6300
-
6301
- // Auto-select template and populate widget order on mount / widget change
6302
- React.useEffect(function () {
6303
- if (isPrebuilt) return;
6304
- var templateKey = widgetCountToTemplate(state.selectedWidgets.length);
6305
- var template = layoutTemplates.find(function (t) {
6306
- return t.id === templateKey;
6307
- });
6308
- if (!template) return;
6309
-
6310
- // Only update if template changed or widget order is empty
6311
- if (state.layout.templateKey !== templateKey || state.layout.widgetOrder.length === 0) {
6312
- var widgetOrder = state.selectedWidgets.map(function (w) {
6313
- return w.name || w.key;
6314
- });
6315
- dispatch({
6316
- type: "SET_LAYOUT",
6317
- payload: {
6318
- templateKey: templateKey,
6319
- widgetOrder: widgetOrder
6320
- }
6321
- });
6322
- }
6323
- }, [isPrebuilt, state.selectedWidgets, state.layout.templateKey, state.layout.widgetOrder.length, dispatch]);
6324
- if (isPrebuilt) {
6325
- return /*#__PURE__*/jsxRuntime.jsx(PrebuiltPreview, {
6326
- dashboard: state.selectedDashboard
6327
- });
6328
- }
6329
- var template = layoutTemplates.find(function (t) {
6330
- return t.id === state.layout.templateKey;
6331
- });
6332
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
6333
- className: "flex flex-col gap-4",
6334
- children: [/*#__PURE__*/jsxRuntime.jsx("h3", {
6335
- className: "text-lg font-semibold text-gray-200",
6336
- children: "Preview your layout"
6337
- }), /*#__PURE__*/jsxRuntime.jsx("p", {
6338
- className: "text-sm text-gray-400",
6339
- children: "Drag widgets to rearrange their placement in the grid."
6340
- }), template ? /*#__PURE__*/jsxRuntime.jsx(LayoutGrid, {
6341
- template: template,
6342
- widgetOrder: state.layout.widgetOrder,
6343
- widgets: state.selectedWidgets,
6344
- dispatch: dispatch
6345
- }) : /*#__PURE__*/jsxRuntime.jsxs("div", {
6346
- className: "flex flex-col items-center justify-center gap-2 py-12 text-gray-500",
6347
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6348
- icon: "grid-2",
6349
- fixedWidth: true
6350
- }), /*#__PURE__*/jsxRuntime.jsx("p", {
6351
- children: "No layout template available."
6352
- })]
6353
- })]
6354
- });
6355
- };
6356
-
6357
- // --- Pre-built dashboard preview ---
6358
-
6359
- var PrebuiltPreview = function PrebuiltPreview(_ref2) {
6360
- var dashboard = _ref2.dashboard;
6361
- if (!dashboard) {
6362
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
6363
- className: "flex flex-col gap-4",
6364
- children: [/*#__PURE__*/jsxRuntime.jsx("h3", {
6365
- className: "text-lg font-semibold text-gray-200",
6366
- children: "Dashboard preview"
6367
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6368
- className: "flex flex-col items-center justify-center gap-2 py-12 text-gray-500",
6369
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6370
- icon: "box-open",
6371
- fixedWidth: true
6372
- }), /*#__PURE__*/jsxRuntime.jsx("p", {
6373
- children: "No dashboard selected."
6374
- })]
6375
- })]
6376
- });
6377
- }
6378
- var widgets = dashboard.widgets || [];
6379
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
6380
- className: "flex flex-col gap-4",
6381
- children: [/*#__PURE__*/jsxRuntime.jsx("h3", {
6382
- className: "text-lg font-semibold text-gray-200",
6383
- children: "Dashboard preview"
6384
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6385
- className: "rounded-lg border border-gray-700/50 bg-gray-800/50 p-4 flex flex-col gap-3",
6386
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
6387
- className: "flex items-center gap-2",
6388
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6389
- icon: resolveIcon(dashboard.icon || "grid-2"),
6390
- fixedWidth: true,
6391
- className: "text-blue-400"
6392
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
6393
- className: "text-base font-semibold text-gray-200",
6394
- children: dashboard.displayName || dashboard.name
6395
- })]
6396
- }), dashboard.description && /*#__PURE__*/jsxRuntime.jsx("p", {
6397
- className: "text-sm text-gray-400",
6398
- children: dashboard.description
6399
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6400
- className: "flex flex-col gap-1.5",
6401
- children: [/*#__PURE__*/jsxRuntime.jsxs("span", {
6402
- className: "text-xs font-semibold text-gray-400 uppercase tracking-wide",
6403
- children: ["Includes ", widgets.length, " widget", widgets.length !== 1 ? "s" : "", ":"]
6404
- }), /*#__PURE__*/jsxRuntime.jsx("ul", {
6405
- className: "flex flex-col gap-1",
6406
- children: widgets.map(function (w, i) {
6407
- return /*#__PURE__*/jsxRuntime.jsxs("li", {
6408
- className: "flex items-center gap-2 text-sm text-gray-300",
6409
- children: [w.icon && /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6410
- icon: resolveIcon(w.icon),
6411
- fixedWidth: true,
6412
- className: "text-gray-500 text-xs"
6413
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
6414
- children: w.displayName || w.name
6415
- })]
6416
- }, w.name || i);
6417
- })
6418
- })]
6419
- })]
6420
- })]
6421
- });
6422
- };
6423
-
6424
- // --- Drag-reorder grid ---
6425
-
6426
- var LayoutGrid = function LayoutGrid(_ref3) {
6427
- var template = _ref3.template,
6428
- widgetOrder = _ref3.widgetOrder,
6429
- widgets = _ref3.widgets,
6430
- dispatch = _ref3.dispatch;
6431
- var _useState = React.useState(null),
6432
- _useState2 = _slicedToArray(_useState, 2),
6433
- dragIndex = _useState2[0],
6434
- setDragIndex = _useState2[1];
6435
- var _useState3 = React.useState(null),
6436
- _useState4 = _slicedToArray(_useState3, 2),
6437
- dragOverIndex = _useState4[0],
6438
- setDragOverIndex = _useState4[1];
6439
- var dragRef = React.useRef(null);
6440
- var totalCells = template.previewCells.length;
6441
-
6442
- // Build cell contents: widget names for filled cells, null for empty
6443
- var cellContents = template.previewCells.map(function (_, i) {
6444
- var widgetId = widgetOrder[i] || null;
6445
- if (!widgetId) return null;
6446
- var widget = widgets.find(function (w) {
6447
- return (w.name || w.key) === widgetId;
6448
- });
6449
- return widget || {
6450
- name: widgetId
6451
- };
6452
- });
6453
- var handleDragStart = React.useCallback(function (e, index) {
6454
- setDragIndex(index);
6455
- dragRef.current = index;
6456
- e.dataTransfer.effectAllowed = "move";
6457
- e.dataTransfer.setData("text/plain", String(index));
6458
- }, []);
6459
- var handleDragOver = React.useCallback(function (e, index) {
6460
- e.preventDefault();
6461
- e.dataTransfer.dropEffect = "move";
6462
- setDragOverIndex(index);
6463
- }, []);
6464
- var handleDragLeave = React.useCallback(function () {
6465
- setDragOverIndex(null);
6466
- }, []);
6467
- var handleDrop = React.useCallback(function (e, dropIndex) {
6468
- e.preventDefault();
6469
- var fromIndex = dragRef.current;
6470
- setDragIndex(null);
6471
- setDragOverIndex(null);
6472
- dragRef.current = null;
6473
- if (fromIndex === null || fromIndex === dropIndex) return;
6474
-
6475
- // Swap the two positions in widgetOrder
6476
- var newOrder = _toConsumableArray(widgetOrder);
6477
- // Pad array to cover all cells
6478
- while (newOrder.length < totalCells) {
6479
- newOrder.push(null);
6480
- }
6481
- var temp = newOrder[fromIndex];
6482
- newOrder[fromIndex] = newOrder[dropIndex];
6483
- newOrder[dropIndex] = temp;
6484
-
6485
- // Trim trailing nulls
6486
- while (newOrder.length > 0 && newOrder[newOrder.length - 1] === null) {
6487
- newOrder.pop();
6488
- }
6489
- dispatch({
6490
- type: "REORDER_WIDGETS",
6491
- payload: newOrder
6492
- });
6493
- }, [widgetOrder, totalCells, dispatch]);
6494
- var handleDragEnd = React.useCallback(function () {
6495
- setDragIndex(null);
6496
- setDragOverIndex(null);
6497
- dragRef.current = null;
6498
- }, []);
6499
- return /*#__PURE__*/jsxRuntime.jsx("div", {
6500
- className: "gap-3 p-4",
6501
- style: {
6502
- display: "grid",
6503
- gridTemplateRows: "repeat(".concat(template.rows, ", 1fr)"),
6504
- gridTemplateColumns: "repeat(".concat(template.cols, ", 1fr)")
6505
- },
6506
- children: template.previewCells.map(function (cell, i) {
6507
- var content = cellContents[i];
6508
- var isDragging = dragIndex === i;
6509
- var isDragOver = dragOverIndex === i;
6510
- var hasWidget = content !== null;
6511
- var cellStyle = {};
6512
- if (cell.rowSpan) cellStyle.gridRow = "span ".concat(cell.rowSpan);
6513
- if (cell.colSpan) cellStyle.gridColumn = "span ".concat(cell.colSpan);
6514
- var cellClasses = ["rounded-lg border transition-all flex items-center justify-center min-h-[60px]", hasWidget ? "border-gray-600 bg-gray-800/80 cursor-grab" : "border-dashed border-gray-700 bg-gray-800/30", isDragging ? "opacity-50 scale-95" : "", isDragOver ? "ring-2 ring-blue-400 border-blue-400" : ""].filter(Boolean).join(" ");
6515
- return /*#__PURE__*/jsxRuntime.jsx("div", {
6516
- className: cellClasses,
6517
- style: cellStyle,
6518
- draggable: hasWidget,
6519
- onDragStart: hasWidget ? function (e) {
6520
- return handleDragStart(e, i);
6521
- } : undefined,
6522
- onDragOver: function onDragOver(e) {
6523
- return handleDragOver(e, i);
6524
- },
6525
- onDragLeave: handleDragLeave,
6526
- onDrop: function onDrop(e) {
6527
- return handleDrop(e, i);
6528
- },
6529
- onDragEnd: handleDragEnd,
6530
- children: hasWidget ? /*#__PURE__*/jsxRuntime.jsxs("div", {
6531
- className: "flex items-center gap-2 px-3 py-2 text-sm text-gray-300",
6532
- children: [content.icon && /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6533
- icon: resolveIcon(content.icon),
6534
- fixedWidth: true,
6535
- className: "text-gray-400 text-xs"
6536
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
6537
- className: "truncate",
6538
- children: content.displayName || content.name || content.key
6539
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6540
- icon: "grip-vertical",
6541
- className: "text-gray-600 ml-auto"
6542
- })]
6543
- }) : /*#__PURE__*/jsxRuntime.jsx("div", {
6544
- className: "text-gray-600",
6545
- children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6546
- icon: "plus",
6547
- fixedWidth: true
6548
- })
6549
- })
6550
- }, "".concat(cell.row, "-").concat(cell.col));
6551
- })
6552
- });
6553
- };
6554
-
6555
- function ownKeys$A(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; }
6556
- function _objectSpread$A(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$A(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$A(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6557
6187
  var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6558
6188
  var _state$selectedDashbo, _state$selectedDashbo2;
6559
6189
  var state = _ref.state,
@@ -6568,7 +6198,9 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6568
6198
  onInstallDashboard = _ref$onInstallDashboa === void 0 ? null : _ref$onInstallDashboa,
6569
6199
  _ref$onOpenDashboard = _ref.onOpenDashboard,
6570
6200
  onOpenDashboard = _ref$onOpenDashboard === void 0 ? null : _ref$onOpenDashboard,
6571
- appId = _ref.appId;
6201
+ appId = _ref.appId,
6202
+ _ref$createHandlerRef = _ref.createHandlerRef,
6203
+ createHandlerRef = _ref$createHandlerRef === void 0 ? null : _ref$createHandlerRef;
6572
6204
  var _useContext = React.useContext(DashReact.ThemeContext),
6573
6205
  themes = _useContext.themes,
6574
6206
  appThemeKey = _useContext.themeKey;
@@ -6593,9 +6225,9 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6593
6225
 
6594
6226
  // Creation state
6595
6227
  var _useState9 = React.useState(false),
6596
- _useState0 = _slicedToArray(_useState9, 2);
6597
- _useState0[0];
6598
- var setCreating = _useState0[1];
6228
+ _useState0 = _slicedToArray(_useState9, 2),
6229
+ creating = _useState0[0],
6230
+ setCreating = _useState0[1];
6599
6231
  var _useState1 = React.useState(null),
6600
6232
  _useState10 = _slicedToArray(_useState1, 2),
6601
6233
  error = _useState10[0],
@@ -6604,9 +6236,15 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6604
6236
  _useState12 = _slicedToArray(_useState11, 2),
6605
6237
  createdDashboard = _useState12[0],
6606
6238
  setCreatedDashboard = _useState12[1];
6239
+
6240
+ // Sub-step state (DASH-188): 0 = Name, 1 = Folder, 2 = Theme
6241
+ var _useState13 = React.useState(0),
6242
+ _useState14 = _slicedToArray(_useState13, 2),
6243
+ subStep = _useState14[0],
6244
+ setSubStep = _useState14[1];
6607
6245
  var isPrebuilt = state.path === "prebuilt";
6608
6246
 
6609
- // Initialize customization defaults on mount
6247
+ // Initialize customization defaults when stepping into this step
6610
6248
  React.useEffect(function () {
6611
6249
  setLocalMenuItems(menuItems);
6612
6250
  var updates = {};
@@ -6624,6 +6262,10 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6624
6262
  })[0]) === null || _Object$entries$sort$ === void 0 ? void 0 : _Object$entries$sort$[0];
6625
6263
  updates.theme = appThemeKey || fallback || null;
6626
6264
  }
6265
+ // Auto-populate name from selected dashboard (DASH-184)
6266
+ if (!state.customization.name && state.selectedDashboard) {
6267
+ updates.name = state.selectedDashboard.displayName || state.selectedDashboard.name || "";
6268
+ }
6627
6269
  if (Object.keys(updates).length > 0) {
6628
6270
  dispatch({
6629
6271
  type: "SET_CUSTOMIZATION",
@@ -6631,65 +6273,10 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6631
6273
  });
6632
6274
  }
6633
6275
  // eslint-disable-next-line react-hooks/exhaustive-deps
6634
- }, []);
6635
- var handleNameChange = React.useCallback(function (val) {
6636
- dispatch({
6637
- type: "SET_CUSTOMIZATION",
6638
- payload: {
6639
- name: val
6640
- }
6641
- });
6642
- }, [dispatch]);
6643
- var handleMenuSelect = React.useCallback(function (id) {
6644
- dispatch({
6645
- type: "SET_CUSTOMIZATION",
6646
- payload: {
6647
- menuId: id
6648
- }
6649
- });
6650
- setIsCreatingFolder(false);
6651
- setNewFolderName("");
6652
- setNewFolderIcon(null);
6653
- }, [dispatch]);
6654
- var handleThemeSelect = React.useCallback(function (key) {
6655
- dispatch({
6656
- type: "SET_CUSTOMIZATION",
6657
- payload: {
6658
- theme: key
6659
- }
6660
- });
6661
- }, [dispatch]);
6662
- function handleCancelNewFolder() {
6663
- setIsCreatingFolder(false);
6664
- setNewFolderName("");
6665
- setNewFolderIcon(null);
6666
- }
6667
- function handleSaveNewFolder() {
6668
- if (!newFolderName.trim() || !newFolderIcon) return;
6669
- var newItem = {
6670
- id: Date.now(),
6671
- name: newFolderName.trim(),
6672
- icon: newFolderIcon
6673
- };
6674
- setLocalMenuItems(function (prev) {
6675
- return [].concat(_toConsumableArray(prev), [newItem]);
6676
- });
6677
- dispatch({
6678
- type: "SET_CUSTOMIZATION",
6679
- payload: {
6680
- menuId: newItem.id
6681
- }
6682
- });
6683
- if (onSaveMenuItem) {
6684
- onSaveMenuItem(newItem);
6685
- }
6686
- setIsCreatingFolder(false);
6687
- setNewFolderName("");
6688
- setNewFolderIcon(null);
6689
- }
6276
+ }, [state.step, state.selectedDashboard]);
6690
6277
 
6691
- // --- Create logic ---
6692
- React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
6278
+ // --- Create logic (DASH-191: moved above useEffect so ref captures actual function) ---
6279
+ var handleCreate = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
6693
6280
  var _state$customization, name, menuId, theme, result, _window$mainApi, installResult, updatedWorkspace, _window$mainApi2, template, layoutObj, widgetOrder, cells, _loop, i, workspace, _t;
6694
6281
  return _regeneratorRuntime.wrap(function (_context2) {
6695
6282
  while (1) switch (_context2.prev = _context2.next) {
@@ -6731,7 +6318,7 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6731
6318
  _context2.next = 6;
6732
6319
  break;
6733
6320
  }
6734
- updatedWorkspace = _objectSpread$A(_objectSpread$A({}, installResult.workspace), {}, {
6321
+ updatedWorkspace = _objectSpread$B(_objectSpread$B({}, installResult.workspace), {}, {
6735
6322
  name: name.trim(),
6736
6323
  menuId: menuId || 1,
6737
6324
  themeKey: theme
@@ -6840,6 +6427,72 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6840
6427
  }, _callee, null, [[1, 16, 17, 18]]);
6841
6428
  })), [state, isPrebuilt, onInstallDashboard, onCreateWorkspace, appId]);
6842
6429
 
6430
+ // Expose handleCreate and creating state to parent via ref (DASH-183)
6431
+ React.useEffect(function () {
6432
+ if (createHandlerRef) {
6433
+ createHandlerRef.current = {
6434
+ handleCreate: handleCreate,
6435
+ creating: creating
6436
+ };
6437
+ }
6438
+ }, [createHandlerRef, handleCreate, creating]);
6439
+ var handleNameChange = React.useCallback(function (val) {
6440
+ dispatch({
6441
+ type: "SET_CUSTOMIZATION",
6442
+ payload: {
6443
+ name: val
6444
+ }
6445
+ });
6446
+ }, [dispatch]);
6447
+ var handleMenuSelect = React.useCallback(function (id) {
6448
+ dispatch({
6449
+ type: "SET_CUSTOMIZATION",
6450
+ payload: {
6451
+ menuId: id
6452
+ }
6453
+ });
6454
+ setIsCreatingFolder(false);
6455
+ setNewFolderName("");
6456
+ setNewFolderIcon(null);
6457
+ setSubStep(2); // Auto-advance to Theme
6458
+ }, [dispatch]);
6459
+ var handleThemeSelect = React.useCallback(function (key) {
6460
+ dispatch({
6461
+ type: "SET_CUSTOMIZATION",
6462
+ payload: {
6463
+ theme: key
6464
+ }
6465
+ });
6466
+ }, [dispatch]);
6467
+ function handleCancelNewFolder() {
6468
+ setIsCreatingFolder(false);
6469
+ setNewFolderName("");
6470
+ setNewFolderIcon(null);
6471
+ }
6472
+ function handleSaveNewFolder() {
6473
+ if (!newFolderName.trim() || !newFolderIcon) return;
6474
+ var newItem = {
6475
+ id: Date.now(),
6476
+ name: newFolderName.trim(),
6477
+ icon: newFolderIcon
6478
+ };
6479
+ setLocalMenuItems(function (prev) {
6480
+ return [].concat(_toConsumableArray(prev), [newItem]);
6481
+ });
6482
+ dispatch({
6483
+ type: "SET_CUSTOMIZATION",
6484
+ payload: {
6485
+ menuId: newItem.id
6486
+ }
6487
+ });
6488
+ if (onSaveMenuItem) {
6489
+ onSaveMenuItem(newItem);
6490
+ }
6491
+ setIsCreatingFolder(false);
6492
+ setNewFolderName("");
6493
+ setNewFolderIcon(null);
6494
+ }
6495
+
6843
6496
  // --- Success state ---
6844
6497
  if (createdDashboard) {
6845
6498
  return /*#__PURE__*/jsxRuntime.jsx("div", {
@@ -6894,18 +6547,44 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6894
6547
  return item.id === state.customization.menuId;
6895
6548
  });
6896
6549
  var selectedTheme = themes && state.customization.theme ? themes[state.customization.theme] : null;
6550
+ var SUB_STEPS = [{
6551
+ label: "Name",
6552
+ icon: "input-text"
6553
+ }, {
6554
+ label: "Folder",
6555
+ icon: "folder"
6556
+ }, {
6557
+ label: "Theme",
6558
+ icon: "palette"
6559
+ }];
6897
6560
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
6898
6561
  className: "flex flex-col gap-4",
6899
6562
  children: [/*#__PURE__*/jsxRuntime.jsx("h3", {
6900
6563
  className: "text-lg font-semibold text-gray-200",
6901
6564
  children: "Customize your dashboard"
6902
- }), /*#__PURE__*/jsxRuntime.jsx("p", {
6903
- className: "text-sm text-gray-400",
6904
- children: "Name your dashboard, choose a folder, and pick a theme."
6565
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
6566
+ className: "flex items-center gap-2 mb-2",
6567
+ children: SUB_STEPS.map(function (s, i) {
6568
+ return /*#__PURE__*/jsxRuntime.jsxs(React.Fragment, {
6569
+ children: [i > 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
6570
+ className: "flex-1 h-px ".concat(i <= subStep ? "bg-blue-500" : "bg-gray-700")
6571
+ }), /*#__PURE__*/jsxRuntime.jsxs("button", {
6572
+ type: "button",
6573
+ className: "flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-colors ".concat(i === subStep ? "bg-blue-600 text-white" : i < subStep ? "bg-blue-900/50 text-blue-300 cursor-pointer" : "bg-gray-800 text-gray-500"),
6574
+ onClick: function onClick() {
6575
+ return setSubStep(i);
6576
+ },
6577
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
6578
+ icon: s.icon,
6579
+ fixedWidth: true
6580
+ }), s.label]
6581
+ })]
6582
+ }, s.label);
6583
+ })
6905
6584
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6906
6585
  className: "flex flex-col gap-6",
6907
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
6908
- className: "flex flex-col gap-2",
6586
+ children: [subStep === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6587
+ className: "flex flex-col gap-3",
6909
6588
  children: [/*#__PURE__*/jsxRuntime.jsxs("label", {
6910
6589
  className: "flex items-center gap-2 text-sm font-semibold text-gray-300",
6911
6590
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
@@ -6917,9 +6596,25 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
6917
6596
  onChange: handleNameChange,
6918
6597
  placeholder: "My Dashboard",
6919
6598
  autoFocus: true
6599
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
6600
+ className: "flex justify-end mt-2",
6601
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
6602
+ onClick: function onClick() {
6603
+ return setSubStep(1);
6604
+ },
6605
+ title: "Next",
6606
+ textSize: "text-sm",
6607
+ padding: "py-1.5 px-4",
6608
+ backgroundColor: state.customization.name.trim() ? "bg-blue-600" : "bg-gray-700",
6609
+ textColor: state.customization.name.trim() ? "text-white" : "text-gray-500",
6610
+ hoverTextColor: state.customization.name.trim() ? "hover:text-white" : "hover:text-gray-500",
6611
+ hoverBackgroundColor: state.customization.name.trim() ? "hover:bg-blue-500" : "hover:bg-gray-700",
6612
+ disabled: !state.customization.name.trim(),
6613
+ icon: "arrow-right"
6614
+ })
6920
6615
  })]
6921
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
6922
- className: "flex flex-col gap-2",
6616
+ }), subStep === 1 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6617
+ className: "flex flex-col gap-3",
6923
6618
  children: [/*#__PURE__*/jsxRuntime.jsxs("label", {
6924
6619
  className: "flex items-center gap-2 text-sm font-semibold text-gray-300",
6925
6620
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
@@ -7010,9 +6705,24 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
7010
6705
  })
7011
6706
  }, item.id);
7012
6707
  })]
6708
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
6709
+ className: "flex justify-end mt-2",
6710
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
6711
+ onClick: function onClick() {
6712
+ return setSubStep(2);
6713
+ },
6714
+ title: "Next",
6715
+ textSize: "text-sm",
6716
+ padding: "py-1.5 px-4",
6717
+ backgroundColor: "bg-blue-600",
6718
+ textColor: "text-white",
6719
+ hoverTextColor: "hover:text-white",
6720
+ hoverBackgroundColor: "hover:bg-blue-500",
6721
+ icon: "arrow-right"
6722
+ })
7013
6723
  })]
7014
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
7015
- className: "flex flex-col gap-2",
6724
+ }), subStep === 2 && /*#__PURE__*/jsxRuntime.jsxs("div", {
6725
+ className: "flex flex-col gap-3",
7016
6726
  children: [/*#__PURE__*/jsxRuntime.jsxs("label", {
7017
6727
  className: "flex items-center gap-2 text-sm font-semibold text-gray-300",
7018
6728
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
@@ -7159,12 +6869,202 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
7159
6869
  });
7160
6870
  };
7161
6871
 
6872
+ function ownKeys$A(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; }
6873
+ function _objectSpread$A(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$A(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$A(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6874
+ var TOTAL_STEPS = 2; // Steps 0-1: Discover, Customize
6875
+
6876
+ var initialState = {
6877
+ step: 0,
6878
+ filters: {
6879
+ categories: [],
6880
+ providers: [],
6881
+ query: ""
6882
+ },
6883
+ selectedWidgets: [],
6884
+ selectedDashboard: null,
6885
+ layout: {
6886
+ templateKey: null,
6887
+ widgetOrder: []
6888
+ },
6889
+ customization: {
6890
+ name: "",
6891
+ menuId: null,
6892
+ theme: null
6893
+ },
6894
+ path: null
6895
+ };
6896
+ function wizardReducer(state, action) {
6897
+ switch (action.type) {
6898
+ case "SET_STEP":
6899
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6900
+ step: action.payload
6901
+ });
6902
+ case "SET_FILTERS":
6903
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6904
+ filters: _objectSpread$A(_objectSpread$A({}, state.filters), action.payload)
6905
+ });
6906
+ case "TOGGLE_FILTER_CATEGORY":
6907
+ {
6908
+ var categories = state.filters.categories.includes(action.payload) ? state.filters.categories.filter(function (c) {
6909
+ return c !== action.payload;
6910
+ }) : [].concat(_toConsumableArray(state.filters.categories), [action.payload]);
6911
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6912
+ filters: _objectSpread$A(_objectSpread$A({}, state.filters), {}, {
6913
+ categories: categories
6914
+ })
6915
+ });
6916
+ }
6917
+ case "TOGGLE_FILTER_PROVIDER":
6918
+ {
6919
+ var providers = state.filters.providers.includes(action.payload) ? state.filters.providers.filter(function (p) {
6920
+ return p !== action.payload;
6921
+ }) : [].concat(_toConsumableArray(state.filters.providers), [action.payload]);
6922
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6923
+ filters: _objectSpread$A(_objectSpread$A({}, state.filters), {}, {
6924
+ providers: providers
6925
+ })
6926
+ });
6927
+ }
6928
+ case "SET_SEARCH_QUERY":
6929
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6930
+ filters: _objectSpread$A(_objectSpread$A({}, state.filters), {}, {
6931
+ query: action.payload
6932
+ })
6933
+ });
6934
+ case "SET_SELECTED_WIDGETS":
6935
+ {
6936
+ var templateKey = widgetCountToTemplate(action.payload.length);
6937
+ var widgetOrder = action.payload.map(function (w) {
6938
+ return w.name || w.key;
6939
+ });
6940
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6941
+ selectedWidgets: action.payload,
6942
+ layout: {
6943
+ templateKey: templateKey,
6944
+ widgetOrder: widgetOrder
6945
+ }
6946
+ });
6947
+ }
6948
+ case "TOGGLE_WIDGET":
6949
+ {
6950
+ var exists = state.selectedWidgets.some(function (w) {
6951
+ return w.name === action.payload.name;
6952
+ });
6953
+ var selectedWidgets = exists ? state.selectedWidgets.filter(function (w) {
6954
+ return w.name !== action.payload.name;
6955
+ }) : [].concat(_toConsumableArray(state.selectedWidgets), [action.payload]);
6956
+ var toggleTemplateKey = widgetCountToTemplate(selectedWidgets.length);
6957
+ var toggleWidgetOrder = selectedWidgets.map(function (w) {
6958
+ return w.name || w.key;
6959
+ });
6960
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6961
+ selectedWidgets: selectedWidgets,
6962
+ layout: {
6963
+ templateKey: toggleTemplateKey,
6964
+ widgetOrder: toggleWidgetOrder
6965
+ }
6966
+ });
6967
+ }
6968
+ case "SET_SELECTED_DASHBOARD":
6969
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6970
+ selectedDashboard: action.payload
6971
+ });
6972
+ case "SET_PATH":
6973
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6974
+ path: action.payload
6975
+ });
6976
+ case "SET_LAYOUT":
6977
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6978
+ layout: action.payload
6979
+ });
6980
+ case "REORDER_WIDGETS":
6981
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6982
+ layout: _objectSpread$A(_objectSpread$A({}, state.layout), {}, {
6983
+ widgetOrder: action.payload
6984
+ })
6985
+ });
6986
+ case "SET_CUSTOMIZATION":
6987
+ return _objectSpread$A(_objectSpread$A({}, state), {}, {
6988
+ customization: _objectSpread$A(_objectSpread$A({}, state.customization), action.payload)
6989
+ });
6990
+ case "RESET":
6991
+ return _objectSpread$A({}, initialState);
6992
+ default:
6993
+ return state;
6994
+ }
6995
+ }
6996
+ function widgetCountToTemplate(count) {
6997
+ if (count <= 1) return "single";
6998
+ if (count === 2) return "two-columns";
6999
+ if (count === 3) return "three-columns";
7000
+ if (count === 4) return "two-by-two";
7001
+ if (count <= 6) return "two-by-three";
7002
+ return "three-by-three";
7003
+ }
7004
+ function getCanProceed(state) {
7005
+ switch (state.step) {
7006
+ case 0:
7007
+ return state.selectedDashboard !== null || state.selectedWidgets.length > 0;
7008
+ case 1:
7009
+ return state.customization.name.trim().length > 0;
7010
+ default:
7011
+ return false;
7012
+ }
7013
+ }
7014
+ var useWizardState = function useWizardState() {
7015
+ var _useReducer = React.useReducer(wizardReducer, initialState),
7016
+ _useReducer2 = _slicedToArray(_useReducer, 2),
7017
+ state = _useReducer2[0],
7018
+ dispatch = _useReducer2[1];
7019
+ var canProceed = React.useMemo(function () {
7020
+ return getCanProceed(state);
7021
+ }, [state]);
7022
+ var selectedCount = React.useMemo(function () {
7023
+ return state.selectedWidgets.length;
7024
+ }, [state.selectedWidgets]);
7025
+ var isPrebuiltPath = state.path === "prebuilt";
7026
+ var isCustomPath = state.path === "custom";
7027
+ var nextStep = React.useCallback(function () {
7028
+ if (getCanProceed(state) && state.step < TOTAL_STEPS - 1) {
7029
+ dispatch({
7030
+ type: "SET_STEP",
7031
+ payload: state.step + 1
7032
+ });
7033
+ }
7034
+ }, [state]);
7035
+ var prevStep = React.useCallback(function () {
7036
+ if (state.step > 0) {
7037
+ dispatch({
7038
+ type: "SET_STEP",
7039
+ payload: state.step - 1
7040
+ });
7041
+ }
7042
+ }, [state.step]);
7043
+ var goToStep = React.useCallback(function (n) {
7044
+ if (n >= 0 && n < TOTAL_STEPS) {
7045
+ dispatch({
7046
+ type: "SET_STEP",
7047
+ payload: n
7048
+ });
7049
+ }
7050
+ }, []);
7051
+ return {
7052
+ state: state,
7053
+ dispatch: dispatch,
7054
+ nextStep: nextStep,
7055
+ prevStep: prevStep,
7056
+ goToStep: goToStep,
7057
+ canProceed: canProceed,
7058
+ selectedCount: selectedCount,
7059
+ isPrebuiltPath: isPrebuiltPath,
7060
+ isCustomPath: isCustomPath,
7061
+ widgetCountToTemplate: widgetCountToTemplate
7062
+ };
7063
+ };
7064
+
7162
7065
  var STEP_LABELS = [{
7163
7066
  label: "Discover",
7164
7067
  description: "Search & select"
7165
- }, {
7166
- label: "Layout",
7167
- description: "Arrange your widgets"
7168
7068
  }, {
7169
7069
  label: "Customize",
7170
7070
  description: "Name, folder & theme"
@@ -7178,6 +7078,7 @@ var STEP_LABELS = [{
7178
7078
  * Resets wizard state cleanly on close.
7179
7079
  */
7180
7080
  var DashboardWizardModal = function DashboardWizardModal(_ref) {
7081
+ var _createHandlerRef$cur, _createHandlerRef$cur2;
7181
7082
  var open = _ref.open,
7182
7083
  setIsOpen = _ref.setIsOpen,
7183
7084
  _ref$menuItems = _ref.menuItems,
@@ -7193,14 +7094,13 @@ var DashboardWizardModal = function DashboardWizardModal(_ref) {
7193
7094
  _ref$onReloadWorkspac = _ref.onReloadWorkspaces,
7194
7095
  onReloadWorkspaces = _ref$onReloadWorkspac === void 0 ? null : _ref$onReloadWorkspac,
7195
7096
  appId = _ref.appId;
7097
+ var createHandlerRef = React.useRef(null);
7196
7098
  var _useWizardState = useWizardState(),
7197
7099
  state = _useWizardState.state,
7198
7100
  dispatch = _useWizardState.dispatch,
7199
7101
  nextStep = _useWizardState.nextStep,
7200
7102
  prevStep = _useWizardState.prevStep,
7201
- goToStep = _useWizardState.goToStep,
7202
- canProceed = _useWizardState.canProceed,
7203
- isPrebuiltPath = _useWizardState.isPrebuiltPath;
7103
+ canProceed = _useWizardState.canProceed;
7204
7104
 
7205
7105
  // Reset wizard state when modal opens
7206
7106
  React.useEffect(function () {
@@ -7216,30 +7116,16 @@ var DashboardWizardModal = function DashboardWizardModal(_ref) {
7216
7116
  var handleStepChange = React.useCallback(function (newStep) {
7217
7117
  // Stepper only allows going backwards; forward is via Next button
7218
7118
  if (newStep < state.step) {
7219
- goToStep(newStep);
7119
+ prevStep();
7220
7120
  }
7221
- }, [state.step, goToStep]);
7222
-
7223
- // Skip layout step for prebuilt path
7121
+ }, [state.step, prevStep]);
7224
7122
  var handleNext = React.useCallback(function () {
7225
7123
  if (!canProceed) return;
7226
- if (state.step === 0 && isPrebuiltPath) {
7227
- // Skip layout step (1), go straight to customize (2)
7228
- goToStep(2);
7229
- } else {
7230
- nextStep();
7231
- }
7232
- }, [canProceed, state.step, isPrebuiltPath, goToStep, nextStep]);
7233
- var handleBack = React.useCallback(function () {
7234
- if (state.step === 2 && isPrebuiltPath) {
7235
- // Skip back over layout step (1), go to discover (0)
7236
- goToStep(0);
7237
- } else {
7238
- prevStep();
7239
- }
7240
- }, [state.step, isPrebuiltPath, goToStep, prevStep]);
7241
- var isLastStep = state.step === 2;
7242
- state.step === 2 && state._created;
7124
+ nextStep();
7125
+ }, [canProceed, nextStep]);
7126
+ var isLastStep = state.step === 1;
7127
+ var isCreating = (_createHandlerRef$cur = (_createHandlerRef$cur2 = createHandlerRef.current) === null || _createHandlerRef$cur2 === void 0 ? void 0 : _createHandlerRef$cur2.creating) !== null && _createHandlerRef$cur !== void 0 ? _createHandlerRef$cur : false;
7128
+ var canCreate = canProceed && !isCreating;
7243
7129
  return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
7244
7130
  isOpen: open,
7245
7131
  setIsOpen: setIsOpen,
@@ -7289,16 +7175,6 @@ var DashboardWizardModal = function DashboardWizardModal(_ref) {
7289
7175
  }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
7290
7176
  label: STEP_LABELS[1].label,
7291
7177
  description: STEP_LABELS[1].description,
7292
- children: /*#__PURE__*/jsxRuntime.jsx("div", {
7293
- className: "flex-1 min-h-0 overflow-y-auto",
7294
- children: /*#__PURE__*/jsxRuntime.jsx(WizardLayoutPreviewStep, {
7295
- state: state,
7296
- dispatch: dispatch
7297
- })
7298
- })
7299
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
7300
- label: STEP_LABELS[2].label,
7301
- description: STEP_LABELS[2].description,
7302
7178
  children: /*#__PURE__*/jsxRuntime.jsx("div", {
7303
7179
  className: "flex-1 min-h-0 overflow-y-auto",
7304
7180
  children: /*#__PURE__*/jsxRuntime.jsx(WizardCustomizeStep, {
@@ -7313,14 +7189,15 @@ var DashboardWizardModal = function DashboardWizardModal(_ref) {
7313
7189
  if (_onOpenDashboard) _onOpenDashboard(ws);
7314
7190
  if (onReloadWorkspaces) onReloadWorkspaces();
7315
7191
  },
7316
- appId: appId
7192
+ appId: appId,
7193
+ createHandlerRef: createHandlerRef
7317
7194
  })
7318
7195
  })
7319
7196
  })]
7320
7197
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
7321
7198
  className: "flex flex-row justify-between items-center pt-4 mt-4 border-t border-gray-700/50",
7322
7199
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
7323
- onClick: state.step === 0 ? handleClose : handleBack,
7200
+ onClick: state.step === 0 ? handleClose : prevStep,
7324
7201
  title: state.step === 0 ? "Cancel" : "Back",
7325
7202
  textSize: "text-sm",
7326
7203
  padding: "py-2 px-4",
@@ -7331,7 +7208,21 @@ var DashboardWizardModal = function DashboardWizardModal(_ref) {
7331
7208
  }), /*#__PURE__*/jsxRuntime.jsxs("span", {
7332
7209
  className: "text-xs text-gray-500",
7333
7210
  children: ["Step ", state.step + 1, " of ", STEP_LABELS.length]
7334
- }), !isLastStep ? /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
7211
+ }), isLastStep ? /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
7212
+ onClick: function onClick() {
7213
+ var _createHandlerRef$cur3, _createHandlerRef$cur4;
7214
+ return (_createHandlerRef$cur3 = createHandlerRef.current) === null || _createHandlerRef$cur3 === void 0 || (_createHandlerRef$cur4 = _createHandlerRef$cur3.handleCreate) === null || _createHandlerRef$cur4 === void 0 ? void 0 : _createHandlerRef$cur4.call(_createHandlerRef$cur3);
7215
+ },
7216
+ title: isCreating ? "Creating..." : "Create Dashboard",
7217
+ textSize: "text-sm",
7218
+ padding: "py-2 px-4",
7219
+ backgroundColor: canCreate ? "bg-green-600" : "bg-gray-700",
7220
+ textColor: canCreate ? "text-white" : "text-gray-500",
7221
+ hoverTextColor: canCreate ? "hover:text-white" : "hover:text-gray-500",
7222
+ hoverBackgroundColor: canCreate ? "hover:bg-green-500" : "hover:bg-gray-700",
7223
+ disabled: !canCreate,
7224
+ icon: isCreating ? "spinner" : "plus"
7225
+ }) : /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
7335
7226
  onClick: handleNext,
7336
7227
  title: "Next",
7337
7228
  textSize: "text-sm",
@@ -7342,7 +7233,7 @@ var DashboardWizardModal = function DashboardWizardModal(_ref) {
7342
7233
  hoverBackgroundColor: canProceed ? "hover:bg-blue-500" : "hover:bg-gray-700",
7343
7234
  disabled: !canProceed,
7344
7235
  icon: "arrow-right"
7345
- }) : /*#__PURE__*/jsxRuntime.jsx("div", {})]
7236
+ })]
7346
7237
  })]
7347
7238
  })]
7348
7239
  })
@@ -48233,6 +48124,10 @@ var DashboardStageInner = function DashboardStageInner(_ref2) {
48233
48124
  handleOpenTab(newWorkspace);
48234
48125
  setSidebarCollapsed(true);
48235
48126
  setPreviewMode(false);
48127
+ return {
48128
+ success: true,
48129
+ workspace: newWorkspace
48130
+ };
48236
48131
  } catch (e) {
48237
48132
  }
48238
48133
  }
@@ -50441,7 +50336,6 @@ exports.WidgetProviderWrapper = WidgetProviderWrapper;
50441
50336
  exports.WidgetSidebar = WidgetSidebar;
50442
50337
  exports.WizardCustomizeStep = WizardCustomizeStep;
50443
50338
  exports.WizardDiscoverStep = WizardDiscoverStep;
50444
- exports.WizardLayoutPreviewStep = WizardLayoutPreviewStep;
50445
50339
  exports.Workspace = Workspace;
50446
50340
  exports.WorkspaceContext = WorkspaceContext;
50447
50341
  exports.WorkspaceFooter = WorkspaceFooter;