@trops/dash-core 0.1.594 → 0.1.596
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 +146 -20
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +146 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -60512,6 +60512,53 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60512
60512
|
|
|
60513
60513
|
// Snapshot of the workspace before editing — used to restore on Cancel
|
|
60514
60514
|
var originalWorkspaceRef = React.useRef(null);
|
|
60515
|
+
|
|
60516
|
+
// ─── Unsaved-changes guard (Phase 2B) ────────────────────────────
|
|
60517
|
+
// Single source of truth for "is the user mid-edit with un-saved
|
|
60518
|
+
// work?". A state variable — NOT a derived ref check — because the
|
|
60519
|
+
// useEffect that mirrors this to `globalThis.__dashboardIsDirty`
|
|
60520
|
+
// must re-run when the value changes, and `useRef` mutations don't
|
|
60521
|
+
// trigger re-renders.
|
|
60522
|
+
//
|
|
60523
|
+
// Mutations that flip it true:
|
|
60524
|
+
// - LayoutBuilder.onWorkspaceChange (widget drag/drop/swap/delete)
|
|
60525
|
+
// via `handleWorkspaceChange`
|
|
60526
|
+
// - Header title rename via `handleWorkspaceNameChange`
|
|
60527
|
+
// - Folder / theme changes via `handleWorkspaceFolderChange`,
|
|
60528
|
+
// `handleWorkspaceThemeChange`
|
|
60529
|
+
//
|
|
60530
|
+
// Mutations that reset to false:
|
|
60531
|
+
// - Successful save (`handleSaveWorkspaceComplete`)
|
|
60532
|
+
// - Cancel/discard (`performCancelEdit` + the discard modal path)
|
|
60533
|
+
// - Re-entering edit mode (`handleToggleEditMode` enter branch)
|
|
60534
|
+
//
|
|
60535
|
+
// Mirrored to `globalThis.__dashboardIsDirty` so the Electron main
|
|
60536
|
+
// process can poll synchronously during window close + app-quit
|
|
60537
|
+
// handlers without an IPC round-trip.
|
|
60538
|
+
//
|
|
60539
|
+
// A `pendingNavigation` object captures a navigation request that
|
|
60540
|
+
// arrived while dirty so the user can choose to discard or keep
|
|
60541
|
+
// editing. Shapes:
|
|
60542
|
+
// { kind: "open-workspace", workspace } — sidebar switch
|
|
60543
|
+
// { kind: "cancel-edit" } — Cancel button
|
|
60544
|
+
var _useState57 = React.useState(false),
|
|
60545
|
+
_useState58 = _slicedToArray(_useState57, 2),
|
|
60546
|
+
isDirty = _useState58[0],
|
|
60547
|
+
setIsDirty = _useState58[1];
|
|
60548
|
+
var _useState59 = React.useState(null),
|
|
60549
|
+
_useState60 = _slicedToArray(_useState59, 2),
|
|
60550
|
+
pendingNavigation = _useState60[0],
|
|
60551
|
+
setPendingNavigation = _useState60[1];
|
|
60552
|
+
React.useEffect(function () {
|
|
60553
|
+
if (typeof globalThis !== "undefined") {
|
|
60554
|
+
globalThis.__dashboardIsDirty = isDirty;
|
|
60555
|
+
}
|
|
60556
|
+
return function () {
|
|
60557
|
+
if (typeof globalThis !== "undefined") {
|
|
60558
|
+
globalThis.__dashboardIsDirty = false;
|
|
60559
|
+
}
|
|
60560
|
+
};
|
|
60561
|
+
}, [isDirty]);
|
|
60515
60562
|
React.useEffect(function () {
|
|
60516
60563
|
isLoadingWorkspaces === false && loadWorkspaces();
|
|
60517
60564
|
isLoadingMenuItems === false && loadMenuItems();
|
|
@@ -60599,10 +60646,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60599
60646
|
// We record the requested ID and open it once it appears in
|
|
60600
60647
|
// workspaceConfig — handles the case where the workspace was just
|
|
60601
60648
|
// created and the config reload is still in flight.
|
|
60602
|
-
var
|
|
60603
|
-
|
|
60604
|
-
pendingOpenWorkspaceId =
|
|
60605
|
-
setPendingOpenWorkspaceId =
|
|
60649
|
+
var _useState61 = React.useState(null),
|
|
60650
|
+
_useState62 = _slicedToArray(_useState61, 2),
|
|
60651
|
+
pendingOpenWorkspaceId = _useState62[0],
|
|
60652
|
+
setPendingOpenWorkspaceId = _useState62[1];
|
|
60606
60653
|
React.useEffect(function () {
|
|
60607
60654
|
var handler = function handler(e) {
|
|
60608
60655
|
var _e$detail2;
|
|
@@ -60859,6 +60906,29 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60859
60906
|
});
|
|
60860
60907
|
}
|
|
60861
60908
|
}
|
|
60909
|
+
|
|
60910
|
+
// Guarded variant of handleOpenTab for user-driven entry points
|
|
60911
|
+
// (sidebar dashboard list, recents). If the user is mid-edit with
|
|
60912
|
+
// unsaved changes AND the request would navigate to a DIFFERENT
|
|
60913
|
+
// workspace than the currently active tab, surface the discard
|
|
60914
|
+
// confirmation modal instead of switching immediately.
|
|
60915
|
+
//
|
|
60916
|
+
// Programmatic callers (post-create auto-open, popout init, the
|
|
60917
|
+
// wizard's create-then-open flow) keep calling `handleOpenTab`
|
|
60918
|
+
// directly — they only fire after an explicit save and have no
|
|
60919
|
+
// dirty state to lose.
|
|
60920
|
+
function handleOpenTabGuarded(workspaceItem) {
|
|
60921
|
+
if (!workspaceItem) return;
|
|
60922
|
+
var switchingAway = activeTabId && activeTabId !== workspaceItem.id;
|
|
60923
|
+
if (isDirty && switchingAway) {
|
|
60924
|
+
setPendingNavigation({
|
|
60925
|
+
kind: "open-workspace",
|
|
60926
|
+
workspace: workspaceItem
|
|
60927
|
+
});
|
|
60928
|
+
return;
|
|
60929
|
+
}
|
|
60930
|
+
handleOpenTab(workspaceItem);
|
|
60931
|
+
}
|
|
60862
60932
|
function handleCloseTab(tabId) {
|
|
60863
60933
|
setOpenTabs(function (prev) {
|
|
60864
60934
|
var remaining = prev.filter(function (tab) {
|
|
@@ -61000,6 +61070,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61000
61070
|
setPreviewMode(function () {
|
|
61001
61071
|
return false;
|
|
61002
61072
|
});
|
|
61073
|
+
// LayoutBuilder fired a mutation (widget drag/drop/swap/delete).
|
|
61074
|
+
// Mark the workspace dirty so the navigation + close guards fire.
|
|
61075
|
+
setIsDirty(true);
|
|
61003
61076
|
|
|
61004
61077
|
// Update the tab's workspace reference
|
|
61005
61078
|
if (activeTabId) {
|
|
@@ -61203,10 +61276,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61203
61276
|
}
|
|
61204
61277
|
|
|
61205
61278
|
// ─── Page State ──────────────────────────────────────────────────
|
|
61206
|
-
var
|
|
61207
|
-
|
|
61208
|
-
activePageId =
|
|
61209
|
-
setActivePageId =
|
|
61279
|
+
var _useState63 = React.useState(null),
|
|
61280
|
+
_useState64 = _slicedToArray(_useState63, 2),
|
|
61281
|
+
activePageId = _useState64[0],
|
|
61282
|
+
setActivePageId = _useState64[1];
|
|
61210
61283
|
|
|
61211
61284
|
// Page history stack for goBack() — pushes the previous page id
|
|
61212
61285
|
// whenever a navigation happens through navigateToPage().
|
|
@@ -61592,20 +61665,38 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61592
61665
|
}
|
|
61593
61666
|
function handleSaveMenuItemError(e, message) {
|
|
61594
61667
|
}
|
|
61668
|
+
|
|
61669
|
+
// Internal: the unguarded cancel-edit operation. Called both from
|
|
61670
|
+
// the direct Cancel button (when nothing is dirty) and from the
|
|
61671
|
+
// confirmation modal's Discard action.
|
|
61672
|
+
function performCancelEdit() {
|
|
61673
|
+
if (originalWorkspaceRef.current) {
|
|
61674
|
+
updateTabWorkspace(originalWorkspaceRef.current);
|
|
61675
|
+
}
|
|
61676
|
+
currentWorkspaceRef.current = null;
|
|
61677
|
+
originalWorkspaceRef.current = null;
|
|
61678
|
+
setIsDirty(false);
|
|
61679
|
+
setPreviewMode(true);
|
|
61680
|
+
}
|
|
61595
61681
|
function handleToggleEditMode() {
|
|
61596
61682
|
if (previewMode) {
|
|
61597
|
-
// Entering edit mode — snapshot the current workspace
|
|
61683
|
+
// Entering edit mode — snapshot the current workspace and
|
|
61684
|
+
// reset the dirty flag so we start from a clean slate.
|
|
61598
61685
|
originalWorkspaceRef.current = DashReact.deepCopy(workspaceSelected);
|
|
61686
|
+
setIsDirty(false);
|
|
61599
61687
|
setPreviewMode(false);
|
|
61600
|
-
|
|
61601
|
-
// Canceling edit mode — restore original workspace
|
|
61602
|
-
if (originalWorkspaceRef.current) {
|
|
61603
|
-
updateTabWorkspace(originalWorkspaceRef.current);
|
|
61604
|
-
}
|
|
61605
|
-
currentWorkspaceRef.current = null;
|
|
61606
|
-
originalWorkspaceRef.current = null;
|
|
61607
|
-
setPreviewMode(true);
|
|
61688
|
+
return;
|
|
61608
61689
|
}
|
|
61690
|
+
// Cancel path: prompt only if there are unsaved edits. The
|
|
61691
|
+
// `isDirty` value flips true the moment LayoutBuilder writes
|
|
61692
|
+
// anything into `currentWorkspaceRef`.
|
|
61693
|
+
if (isDirty) {
|
|
61694
|
+
setPendingNavigation({
|
|
61695
|
+
kind: "cancel-edit"
|
|
61696
|
+
});
|
|
61697
|
+
return;
|
|
61698
|
+
}
|
|
61699
|
+
performCancelEdit();
|
|
61609
61700
|
}
|
|
61610
61701
|
function handleWorkspaceNameChange(name) {
|
|
61611
61702
|
if (!workspaceSelected) return;
|
|
@@ -61614,6 +61705,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61614
61705
|
|
|
61615
61706
|
// Update the tab name and workspace reference
|
|
61616
61707
|
updateTabWorkspace(tempWorkspace);
|
|
61708
|
+
// Header rename counts as a workspace mutation; mark dirty so
|
|
61709
|
+
// navigation + close guards fire.
|
|
61710
|
+
setIsDirty(true);
|
|
61617
61711
|
}
|
|
61618
61712
|
function handleWorkspaceFolderChange(menuId) {
|
|
61619
61713
|
if (!workspaceSelected) return;
|
|
@@ -61777,6 +61871,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61777
61871
|
// Clear edit-mode refs — edits are now persisted
|
|
61778
61872
|
currentWorkspaceRef.current = null;
|
|
61779
61873
|
originalWorkspaceRef.current = null;
|
|
61874
|
+
setIsDirty(false);
|
|
61780
61875
|
setPreviewMode(function () {
|
|
61781
61876
|
return true;
|
|
61782
61877
|
});
|
|
@@ -61956,7 +62051,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61956
62051
|
recentDashboards: recentDashboards,
|
|
61957
62052
|
authStatus: authStatus,
|
|
61958
62053
|
authProfile: authProfile,
|
|
61959
|
-
onOpenWorkspace:
|
|
62054
|
+
onOpenWorkspace: handleOpenTabGuarded,
|
|
61960
62055
|
onNewDashboard: function onNewDashboard() {
|
|
61961
62056
|
return setIsLayoutPickerOpen(true);
|
|
61962
62057
|
},
|
|
@@ -62147,7 +62242,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
62147
62242
|
onReloadWorkspaces: loadWorkspaces,
|
|
62148
62243
|
onReloadMenuItems: loadMenuItems,
|
|
62149
62244
|
onOpenWorkspace: function onOpenWorkspace(ws) {
|
|
62150
|
-
|
|
62245
|
+
handleOpenTabGuarded(ws);
|
|
62151
62246
|
setIsAppSettingsOpen(false);
|
|
62152
62247
|
},
|
|
62153
62248
|
onOpenThemeEditor: function onOpenThemeEditor() {
|
|
@@ -62189,7 +62284,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
62189
62284
|
onSaveMenuItem: handleSaveNewMenuItem,
|
|
62190
62285
|
appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
|
|
62191
62286
|
onReloadWorkspaces: loadWorkspaces,
|
|
62192
|
-
onOpenWorkspace:
|
|
62287
|
+
onOpenWorkspace: handleOpenTabGuarded,
|
|
62193
62288
|
onOpenWizard: function onOpenWizard() {
|
|
62194
62289
|
return setIsWizardOpen(true);
|
|
62195
62290
|
}
|
|
@@ -62274,6 +62369,37 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
62274
62369
|
onOpenWizard: function onOpenWizard() {
|
|
62275
62370
|
return setIsWizardOpen(true);
|
|
62276
62371
|
}
|
|
62372
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.ConfirmationModal, {
|
|
62373
|
+
isOpen: Boolean(pendingNavigation),
|
|
62374
|
+
setIsOpen: function setIsOpen(open) {
|
|
62375
|
+
if (!open) setPendingNavigation(null);
|
|
62376
|
+
},
|
|
62377
|
+
title: "Discard unsaved changes?",
|
|
62378
|
+
message: (pendingNavigation === null || pendingNavigation === void 0 ? void 0 : pendingNavigation.kind) === "cancel-edit" ? "You have edits that haven't been saved. Discard them and exit edit mode?" : "You have edits that haven't been saved. Discard them and switch dashboards?",
|
|
62379
|
+
confirmLabel: "Discard changes",
|
|
62380
|
+
cancelLabel: "Keep editing",
|
|
62381
|
+
variant: "danger",
|
|
62382
|
+
onConfirm: function onConfirm() {
|
|
62383
|
+
var pending = pendingNavigation;
|
|
62384
|
+
// Clear the prompt first so the modal teardown doesn't race
|
|
62385
|
+
// a re-trigger from the same dirty-state read.
|
|
62386
|
+
setPendingNavigation(null);
|
|
62387
|
+
if (!pending) return;
|
|
62388
|
+
if (pending.kind === "cancel-edit") {
|
|
62389
|
+
performCancelEdit();
|
|
62390
|
+
} else if (pending.kind === "open-workspace") {
|
|
62391
|
+
// Clear edit refs + dirty flag before navigating so the
|
|
62392
|
+
// new workspace mount doesn't inherit dirty state.
|
|
62393
|
+
currentWorkspaceRef.current = null;
|
|
62394
|
+
originalWorkspaceRef.current = null;
|
|
62395
|
+
setIsDirty(false);
|
|
62396
|
+
setPreviewMode(true);
|
|
62397
|
+
handleOpenTab(pending.workspace);
|
|
62398
|
+
}
|
|
62399
|
+
},
|
|
62400
|
+
onCancel: function onCancel() {
|
|
62401
|
+
return setPendingNavigation(null);
|
|
62402
|
+
}
|
|
62277
62403
|
})]
|
|
62278
62404
|
});
|
|
62279
62405
|
};
|