@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.esm.js
CHANGED
|
@@ -60494,6 +60494,53 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60494
60494
|
|
|
60495
60495
|
// Snapshot of the workspace before editing — used to restore on Cancel
|
|
60496
60496
|
var originalWorkspaceRef = useRef(null);
|
|
60497
|
+
|
|
60498
|
+
// ─── Unsaved-changes guard (Phase 2B) ────────────────────────────
|
|
60499
|
+
// Single source of truth for "is the user mid-edit with un-saved
|
|
60500
|
+
// work?". A state variable — NOT a derived ref check — because the
|
|
60501
|
+
// useEffect that mirrors this to `globalThis.__dashboardIsDirty`
|
|
60502
|
+
// must re-run when the value changes, and `useRef` mutations don't
|
|
60503
|
+
// trigger re-renders.
|
|
60504
|
+
//
|
|
60505
|
+
// Mutations that flip it true:
|
|
60506
|
+
// - LayoutBuilder.onWorkspaceChange (widget drag/drop/swap/delete)
|
|
60507
|
+
// via `handleWorkspaceChange`
|
|
60508
|
+
// - Header title rename via `handleWorkspaceNameChange`
|
|
60509
|
+
// - Folder / theme changes via `handleWorkspaceFolderChange`,
|
|
60510
|
+
// `handleWorkspaceThemeChange`
|
|
60511
|
+
//
|
|
60512
|
+
// Mutations that reset to false:
|
|
60513
|
+
// - Successful save (`handleSaveWorkspaceComplete`)
|
|
60514
|
+
// - Cancel/discard (`performCancelEdit` + the discard modal path)
|
|
60515
|
+
// - Re-entering edit mode (`handleToggleEditMode` enter branch)
|
|
60516
|
+
//
|
|
60517
|
+
// Mirrored to `globalThis.__dashboardIsDirty` so the Electron main
|
|
60518
|
+
// process can poll synchronously during window close + app-quit
|
|
60519
|
+
// handlers without an IPC round-trip.
|
|
60520
|
+
//
|
|
60521
|
+
// A `pendingNavigation` object captures a navigation request that
|
|
60522
|
+
// arrived while dirty so the user can choose to discard or keep
|
|
60523
|
+
// editing. Shapes:
|
|
60524
|
+
// { kind: "open-workspace", workspace } — sidebar switch
|
|
60525
|
+
// { kind: "cancel-edit" } — Cancel button
|
|
60526
|
+
var _useState57 = useState(false),
|
|
60527
|
+
_useState58 = _slicedToArray(_useState57, 2),
|
|
60528
|
+
isDirty = _useState58[0],
|
|
60529
|
+
setIsDirty = _useState58[1];
|
|
60530
|
+
var _useState59 = useState(null),
|
|
60531
|
+
_useState60 = _slicedToArray(_useState59, 2),
|
|
60532
|
+
pendingNavigation = _useState60[0],
|
|
60533
|
+
setPendingNavigation = _useState60[1];
|
|
60534
|
+
useEffect(function () {
|
|
60535
|
+
if (typeof globalThis !== "undefined") {
|
|
60536
|
+
globalThis.__dashboardIsDirty = isDirty;
|
|
60537
|
+
}
|
|
60538
|
+
return function () {
|
|
60539
|
+
if (typeof globalThis !== "undefined") {
|
|
60540
|
+
globalThis.__dashboardIsDirty = false;
|
|
60541
|
+
}
|
|
60542
|
+
};
|
|
60543
|
+
}, [isDirty]);
|
|
60497
60544
|
useEffect(function () {
|
|
60498
60545
|
isLoadingWorkspaces === false && loadWorkspaces();
|
|
60499
60546
|
isLoadingMenuItems === false && loadMenuItems();
|
|
@@ -60581,10 +60628,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60581
60628
|
// We record the requested ID and open it once it appears in
|
|
60582
60629
|
// workspaceConfig — handles the case where the workspace was just
|
|
60583
60630
|
// created and the config reload is still in flight.
|
|
60584
|
-
var
|
|
60585
|
-
|
|
60586
|
-
pendingOpenWorkspaceId =
|
|
60587
|
-
setPendingOpenWorkspaceId =
|
|
60631
|
+
var _useState61 = useState(null),
|
|
60632
|
+
_useState62 = _slicedToArray(_useState61, 2),
|
|
60633
|
+
pendingOpenWorkspaceId = _useState62[0],
|
|
60634
|
+
setPendingOpenWorkspaceId = _useState62[1];
|
|
60588
60635
|
useEffect(function () {
|
|
60589
60636
|
var handler = function handler(e) {
|
|
60590
60637
|
var _e$detail2;
|
|
@@ -60841,6 +60888,29 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60841
60888
|
});
|
|
60842
60889
|
}
|
|
60843
60890
|
}
|
|
60891
|
+
|
|
60892
|
+
// Guarded variant of handleOpenTab for user-driven entry points
|
|
60893
|
+
// (sidebar dashboard list, recents). If the user is mid-edit with
|
|
60894
|
+
// unsaved changes AND the request would navigate to a DIFFERENT
|
|
60895
|
+
// workspace than the currently active tab, surface the discard
|
|
60896
|
+
// confirmation modal instead of switching immediately.
|
|
60897
|
+
//
|
|
60898
|
+
// Programmatic callers (post-create auto-open, popout init, the
|
|
60899
|
+
// wizard's create-then-open flow) keep calling `handleOpenTab`
|
|
60900
|
+
// directly — they only fire after an explicit save and have no
|
|
60901
|
+
// dirty state to lose.
|
|
60902
|
+
function handleOpenTabGuarded(workspaceItem) {
|
|
60903
|
+
if (!workspaceItem) return;
|
|
60904
|
+
var switchingAway = activeTabId && activeTabId !== workspaceItem.id;
|
|
60905
|
+
if (isDirty && switchingAway) {
|
|
60906
|
+
setPendingNavigation({
|
|
60907
|
+
kind: "open-workspace",
|
|
60908
|
+
workspace: workspaceItem
|
|
60909
|
+
});
|
|
60910
|
+
return;
|
|
60911
|
+
}
|
|
60912
|
+
handleOpenTab(workspaceItem);
|
|
60913
|
+
}
|
|
60844
60914
|
function handleCloseTab(tabId) {
|
|
60845
60915
|
setOpenTabs(function (prev) {
|
|
60846
60916
|
var remaining = prev.filter(function (tab) {
|
|
@@ -60982,6 +61052,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
60982
61052
|
setPreviewMode(function () {
|
|
60983
61053
|
return false;
|
|
60984
61054
|
});
|
|
61055
|
+
// LayoutBuilder fired a mutation (widget drag/drop/swap/delete).
|
|
61056
|
+
// Mark the workspace dirty so the navigation + close guards fire.
|
|
61057
|
+
setIsDirty(true);
|
|
60985
61058
|
|
|
60986
61059
|
// Update the tab's workspace reference
|
|
60987
61060
|
if (activeTabId) {
|
|
@@ -61185,10 +61258,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61185
61258
|
}
|
|
61186
61259
|
|
|
61187
61260
|
// ─── Page State ──────────────────────────────────────────────────
|
|
61188
|
-
var
|
|
61189
|
-
|
|
61190
|
-
activePageId =
|
|
61191
|
-
setActivePageId =
|
|
61261
|
+
var _useState63 = useState(null),
|
|
61262
|
+
_useState64 = _slicedToArray(_useState63, 2),
|
|
61263
|
+
activePageId = _useState64[0],
|
|
61264
|
+
setActivePageId = _useState64[1];
|
|
61192
61265
|
|
|
61193
61266
|
// Page history stack for goBack() — pushes the previous page id
|
|
61194
61267
|
// whenever a navigation happens through navigateToPage().
|
|
@@ -61574,20 +61647,38 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61574
61647
|
}
|
|
61575
61648
|
function handleSaveMenuItemError(e, message) {
|
|
61576
61649
|
}
|
|
61650
|
+
|
|
61651
|
+
// Internal: the unguarded cancel-edit operation. Called both from
|
|
61652
|
+
// the direct Cancel button (when nothing is dirty) and from the
|
|
61653
|
+
// confirmation modal's Discard action.
|
|
61654
|
+
function performCancelEdit() {
|
|
61655
|
+
if (originalWorkspaceRef.current) {
|
|
61656
|
+
updateTabWorkspace(originalWorkspaceRef.current);
|
|
61657
|
+
}
|
|
61658
|
+
currentWorkspaceRef.current = null;
|
|
61659
|
+
originalWorkspaceRef.current = null;
|
|
61660
|
+
setIsDirty(false);
|
|
61661
|
+
setPreviewMode(true);
|
|
61662
|
+
}
|
|
61577
61663
|
function handleToggleEditMode() {
|
|
61578
61664
|
if (previewMode) {
|
|
61579
|
-
// Entering edit mode — snapshot the current workspace
|
|
61665
|
+
// Entering edit mode — snapshot the current workspace and
|
|
61666
|
+
// reset the dirty flag so we start from a clean slate.
|
|
61580
61667
|
originalWorkspaceRef.current = deepCopy(workspaceSelected);
|
|
61668
|
+
setIsDirty(false);
|
|
61581
61669
|
setPreviewMode(false);
|
|
61582
|
-
|
|
61583
|
-
// Canceling edit mode — restore original workspace
|
|
61584
|
-
if (originalWorkspaceRef.current) {
|
|
61585
|
-
updateTabWorkspace(originalWorkspaceRef.current);
|
|
61586
|
-
}
|
|
61587
|
-
currentWorkspaceRef.current = null;
|
|
61588
|
-
originalWorkspaceRef.current = null;
|
|
61589
|
-
setPreviewMode(true);
|
|
61670
|
+
return;
|
|
61590
61671
|
}
|
|
61672
|
+
// Cancel path: prompt only if there are unsaved edits. The
|
|
61673
|
+
// `isDirty` value flips true the moment LayoutBuilder writes
|
|
61674
|
+
// anything into `currentWorkspaceRef`.
|
|
61675
|
+
if (isDirty) {
|
|
61676
|
+
setPendingNavigation({
|
|
61677
|
+
kind: "cancel-edit"
|
|
61678
|
+
});
|
|
61679
|
+
return;
|
|
61680
|
+
}
|
|
61681
|
+
performCancelEdit();
|
|
61591
61682
|
}
|
|
61592
61683
|
function handleWorkspaceNameChange(name) {
|
|
61593
61684
|
if (!workspaceSelected) return;
|
|
@@ -61596,6 +61687,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61596
61687
|
|
|
61597
61688
|
// Update the tab name and workspace reference
|
|
61598
61689
|
updateTabWorkspace(tempWorkspace);
|
|
61690
|
+
// Header rename counts as a workspace mutation; mark dirty so
|
|
61691
|
+
// navigation + close guards fire.
|
|
61692
|
+
setIsDirty(true);
|
|
61599
61693
|
}
|
|
61600
61694
|
function handleWorkspaceFolderChange(menuId) {
|
|
61601
61695
|
if (!workspaceSelected) return;
|
|
@@ -61759,6 +61853,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61759
61853
|
// Clear edit-mode refs — edits are now persisted
|
|
61760
61854
|
currentWorkspaceRef.current = null;
|
|
61761
61855
|
originalWorkspaceRef.current = null;
|
|
61856
|
+
setIsDirty(false);
|
|
61762
61857
|
setPreviewMode(function () {
|
|
61763
61858
|
return true;
|
|
61764
61859
|
});
|
|
@@ -61938,7 +62033,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61938
62033
|
recentDashboards: recentDashboards,
|
|
61939
62034
|
authStatus: authStatus,
|
|
61940
62035
|
authProfile: authProfile,
|
|
61941
|
-
onOpenWorkspace:
|
|
62036
|
+
onOpenWorkspace: handleOpenTabGuarded,
|
|
61942
62037
|
onNewDashboard: function onNewDashboard() {
|
|
61943
62038
|
return setIsLayoutPickerOpen(true);
|
|
61944
62039
|
},
|
|
@@ -62129,7 +62224,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
62129
62224
|
onReloadWorkspaces: loadWorkspaces,
|
|
62130
62225
|
onReloadMenuItems: loadMenuItems,
|
|
62131
62226
|
onOpenWorkspace: function onOpenWorkspace(ws) {
|
|
62132
|
-
|
|
62227
|
+
handleOpenTabGuarded(ws);
|
|
62133
62228
|
setIsAppSettingsOpen(false);
|
|
62134
62229
|
},
|
|
62135
62230
|
onOpenThemeEditor: function onOpenThemeEditor() {
|
|
@@ -62171,7 +62266,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
62171
62266
|
onSaveMenuItem: handleSaveNewMenuItem,
|
|
62172
62267
|
appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
|
|
62173
62268
|
onReloadWorkspaces: loadWorkspaces,
|
|
62174
|
-
onOpenWorkspace:
|
|
62269
|
+
onOpenWorkspace: handleOpenTabGuarded,
|
|
62175
62270
|
onOpenWizard: function onOpenWizard() {
|
|
62176
62271
|
return setIsWizardOpen(true);
|
|
62177
62272
|
}
|
|
@@ -62256,6 +62351,37 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
62256
62351
|
onOpenWizard: function onOpenWizard() {
|
|
62257
62352
|
return setIsWizardOpen(true);
|
|
62258
62353
|
}
|
|
62354
|
+
}), /*#__PURE__*/jsx(ConfirmationModal, {
|
|
62355
|
+
isOpen: Boolean(pendingNavigation),
|
|
62356
|
+
setIsOpen: function setIsOpen(open) {
|
|
62357
|
+
if (!open) setPendingNavigation(null);
|
|
62358
|
+
},
|
|
62359
|
+
title: "Discard unsaved changes?",
|
|
62360
|
+
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?",
|
|
62361
|
+
confirmLabel: "Discard changes",
|
|
62362
|
+
cancelLabel: "Keep editing",
|
|
62363
|
+
variant: "danger",
|
|
62364
|
+
onConfirm: function onConfirm() {
|
|
62365
|
+
var pending = pendingNavigation;
|
|
62366
|
+
// Clear the prompt first so the modal teardown doesn't race
|
|
62367
|
+
// a re-trigger from the same dirty-state read.
|
|
62368
|
+
setPendingNavigation(null);
|
|
62369
|
+
if (!pending) return;
|
|
62370
|
+
if (pending.kind === "cancel-edit") {
|
|
62371
|
+
performCancelEdit();
|
|
62372
|
+
} else if (pending.kind === "open-workspace") {
|
|
62373
|
+
// Clear edit refs + dirty flag before navigating so the
|
|
62374
|
+
// new workspace mount doesn't inherit dirty state.
|
|
62375
|
+
currentWorkspaceRef.current = null;
|
|
62376
|
+
originalWorkspaceRef.current = null;
|
|
62377
|
+
setIsDirty(false);
|
|
62378
|
+
setPreviewMode(true);
|
|
62379
|
+
handleOpenTab(pending.workspace);
|
|
62380
|
+
}
|
|
62381
|
+
},
|
|
62382
|
+
onCancel: function onCancel() {
|
|
62383
|
+
return setPendingNavigation(null);
|
|
62384
|
+
}
|
|
62259
62385
|
})]
|
|
62260
62386
|
});
|
|
62261
62387
|
};
|