Skip to content

v0.4.2 pre-release#91

Merged
kryptodrex merged 81 commits intodevelopfrom
v0.4.2
Mar 26, 2026
Merged

v0.4.2 pre-release#91
kryptodrex merged 81 commits intodevelopfrom
v0.4.2

Conversation

@kryptodrex
Copy link
Copy Markdown
Owner

This pull request introduces several user experience improvements, interface refinements, and bug fixes across the application, with a focus on plan saving behavior, UI clarity, and code cleanup. The most significant updates include automatic plan saving on close, a more compact and responsive plan header, new menu actions, and enhanced status indicators. Additionally, several bug fixes and optimizations are included to ensure a smoother user experience.

User Experience & Workflow Improvements

  • Plans now automatically save when closed, prompting the user only if the plan is new or unsaved, reducing the risk of data loss and streamlining the save process. [1] [2] [3] [4] [5]
  • Added a "Copy Plan" option to the application menu with a keyboard shortcut for quick duplication of plans.
  • Improved the "Pay Details" menu action for clarity and renamed it from "Pay Options."

UI & Layout Enhancements

  • The plan header has been reorganized to reduce clutter, with header actions now adapting between full buttons and compact dropdowns based on window size. [1] [2] [3]
  • Increased icon line widths for better visibility and made the view mode selector more compact, removing unnecessary modals.
  • Introduced a new TransientStatusIndicator for consistent, accessible status messages (such as zoom and undo/redo), replacing ad-hoc elements. [1] [2]

Bug Fixes & Quality Improvements

  • Fixed issues with demo plan generation, UI alignment, and new plan creation view modes.
  • Updated the content security policy in index.html for improved security.
  • Bumped the application version to 0.4.2.

Codebase Cleanup

  • Removed outdated or completed tasks from the app_updates/v0.4.1-fixes.md file to keep documentation current.
  • Refactored view mode state handling for clarity and maintainability, removing unnecessary logic related to favorites. [1] [2] [3] [4]

These changes collectively improve the application's usability, reliability, and maintainability.

Restructure the ViewModeSelector markup and styles: remove the extra wrapper, move the settings button out of the option loop, ensure buttons use proper keys and className logic, and adjust CSS (selector height, reduced padding, font-size tweaks, and settings icon styling). Improve copy and formatting in ViewModeSettingsModal and tidy the checkbox disable expression. Increase MAX_VISIBLE_FAVORITE_VIEW_MODES from 3 to 6 to allow pinning more view modes.
Adjust header layout and button sizing: align items in .header-btn-group, set .header-btn-secondary to height: fit-content, and remove redundant .view-mode-selector-wrap rules. Add a null/undefined guard in PlanDashboard.tsx so sanitizeFavoriteViewModes is only called when viewModeFavorites is present (pass undefined otherwise) to avoid potential runtime errors.
Remove supplemental quarterly insertion and refactor syncFavoritesForCadence to accept an optional previousCadenceMode. The new logic removes a prior non-default cadence (so stale cadence tabs don't linger), preserves permanent defaults (monthly/yearly), and inserts the new cadence in canonical order while respecting MAX_VISIBLE_FAVORITE_VIEW_MODES. Also update buildViewModeSelectorOptions to stop auto-adding supplemental modes and expand unit tests to cover the new behaviors.
Change default payCadenceLabel from 'Your Pay Frequency' to 'Pay Frequency' to simplify the displayed label. Add padding to .view-mode-settings-button for improved spacing/alignment. Update unit test to look up the cadence button with a case-insensitive regex (/Weekly\s*Pay Frequency/i) so it matches the adjusted label and tolerant spacing/casing.
Introduce a Pay Settings modal and UI flow, plus cadence-aware initialization for view-mode favorites.

Changes include:
- Import new icons and PaySettingsModal component; add Banknote header button to open pay details and simplify "Copy Plan" label to "Copy".
- Add showPaySettingsModal state and wire menu events (openPayOptions) and app actions to open the modal. Subscribe/unsubscribe to a new copy menu event.
- Remove the old paySettingsSearchRequestKey prop/flow and instead show the PaySettingsModal directly; clear pending field highlights when opening/closing.
- When a plan has no stored viewModeFavorites, pick the pay-frequency cadence as the initial displayMode and persist initial favorites (using syncFavoritesForCadence and DEFAULT_FAVORITE_VIEW_MODES) via updateBudgetSettings so the favorites modal reflects the cadence.
- Guard favorites-change effect to no-op when favorites aren't stored yet to avoid clobbering the cadence initializer.
- Update effect dependencies and minor wiring changes to ensure displayMode stays valid and integration with existing tab logic.

This consolidates pay settings UX into a modal and ensures new plans get a sensible initial tab based on the user's chosen pay frequency.
Introduce a new TransientStatusIndicator component for transient, accessible status messages. Adds component implementation (props: message, variant, topRem, rightRem, zoomFactor), corresponding CSS for positioning, visual variants and responsive behavior, and an index export. Also updates the shared components barrel to export the new component.
Implement save-before-close behavior and refine UI/UX across the dashboard and app.

- electron/main.ts: Replace async message box with a modal save prompt (showMessageBoxSync) that offers Save / Don't Save / Cancel; attempt a programmatic save via webContents before closing, show an error box if the save fails, and preserve window state. Improves protection against data loss when closing windows with unsaved changes.

- src/App.tsx: Replace two ad-hoc zoom/undo status divs with the new TransientStatusIndicator component to centralize transient status rendering and account for zoom factor and variants.

- src/components/PlanDashboard/PlanDashboard.css: Tighten header action spacing (gap adjustments), align items center, and tweak responsive layout/order for header button groups to improve compactness and alignment.

- src/components/PlanDashboard/PlanDashboard.tsx: Refactor save logic into performSave() returning a boolean so callers (including the close handler) can detect success; provide handleSave wrapper for explicit save actions. Remove duplicated Save/Copy buttons from the header and adjust the Settings button disabled condition to not depend on loading. Update imports accordingly.

These changes aim to prevent accidental data loss, simplify transient status handling, and tighten the dashboard header layout and save flow for programmatic use.
Introduce a previewable view mode selector and wire it into several tab views. Replaced the CompactViewModeSelector with a new ViewModeButton, added previewDisplayMode state and handleDisplayModePreview to allow temporary previewing of modes (effectiveDisplayMode used when rendering). Passed a viewModeControl prop into PayBreakdown, BillsManager, LoansManager, TaxBreakdown and SavingsManager so the selector can be rendered in each tab header. Also updated multiple tabs to use effectiveDisplayMode instead of the persistent displayMode, adjusted a header label in PayBreakdown (After-Tax -> Take Home Pay), and made a small CSS whitespace tweak.
Copilot AI review requested due to automatic review settings March 26, 2026 23:32
@kryptodrex kryptodrex linked an issue Mar 26, 2026 that may be closed by this pull request
16 tasks
@github-actions
Copy link
Copy Markdown

Version Update Detected

Version has been correctly bumped from 0.4.1 to 0.4.2

@kryptodrex kryptodrex merged commit cee396b into develop Mar 26, 2026
3 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares the v0.4.2 pre-release by updating versioning, improving close/save workflow and menu actions, and refreshing several UI primitives (headers, view-mode controls, transient status messaging) to reduce clutter and improve responsiveness.

Changes:

  • Add app-version injection (__APP_VERSION__) and use it in About/Feedback contexts; bump version to 0.4.2.
  • Rework view-mode controls (remove favorites modal/logic, add new header controls + compact action menus across tab views).
  • UI/UX refinements and bug fixes (demo data generation adjustments, glossary term updates, icon/styling tweaks, CSP update).

Reviewed changes

Copilot reviewed 73 out of 74 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
vite.config.ts Load env via loadEnv, define __APP_VERSION__, and update Electron main env defines.
version Bump app version to 0.4.2.
src/vite-env.d.ts Declare __APP_VERSION__ for TypeScript.
src/utils/viewModePreferences.ts Remove favorites-related utilities; keep selectable modes list.
src/utils/viewModePreferences.test.ts Remove tests for removed favorites utilities.
src/utils/tabManagement.ts Rename Metrics tab label to “Yearly Metrics”.
src/utils/tabManagement.test.ts Update tab label expectation to match “Yearly Metrics”.
src/utils/searchRegistry.ts Suppress duplicate-registration warning in dev (StrictMode/HMR).
src/utils/searchModules/paySettingsSearchModule.ts Rename search result category to “Pay Details”.
src/utils/searchModules/paySettingsSearchModule.test.ts Update fixtures to “Pay Details” naming.
src/utils/planSearch.ts Update doc comment to “Pay Details”.
src/utils/demoDataGenerator.ts Adjust demo salary distribution, bills mix, tax thresholds, and loan safety cap.
src/utils/demoDataGenerator.test.ts Add regression test around loan/bill expense cap behavior.
src/types/settings.ts Remove viewModeFavorites from settings types.
src/index.css Increase icon stroke width CSS variable.
src/data/glossary.ts Update “discretionary” term naming/definitions.
src/constants/events.ts Add copyPlan menu event; remove viewModeFavoritesChanged.
src/constants/appearancePresets.ts Small copy tweak (“original” look).
src/constants/appMeta.ts Add APP_NAME / APP_VERSION constants.
src/components/views/SetupWizard/SetupWizard.tsx Change currency dropdown display format.
src/components/tabViews/TaxBreakdown/TaxBreakdown.tsx Add responsive header actions (compact action menu) + viewModeControl slot.
src/components/tabViews/TaxBreakdown/TaxBreakdown.css Style action menu layout for Tax Breakdown header.
src/components/tabViews/SavingsManager/SavingsManager.tsx Rename title and add viewModeControl slot to header.
src/components/tabViews/PayBreakdown/PayBreakdown.tsx Remove embedded PaySettings modal usage; accept viewModeControl + open-pay-details callback; copy tweaks.
src/components/tabViews/PayBreakdown/PayBreakdown.test.tsx Remove PaySettingsModal-related test/mocks.
src/components/tabViews/LoansManager/LoansManager.tsx Add viewModeControl slot and refine empty-state + button copy/icons.
src/components/tabViews/KeyMetrics/KeyMetrics.tsx Rename header to “Yearly Metrics” and add “Pay Details” header action.
src/components/tabViews/BillsManager/BillsManager.tsx Add compact “Add Expense” action menu + viewModeControl slot; revise empty-state and discretionary labels.
src/components/tabViews/BillsManager/BillsManager.css Add styling for compact action menu behavior.
src/components/modals/ViewModeSettingsModal/index.ts Remove ViewMode favorites modal export.
src/components/modals/ViewModeSettingsModal/ViewModeSettingsModal.tsx Remove ViewMode favorites modal implementation.
src/components/modals/ViewModeSettingsModal/ViewModeSettingsModal.css Remove ViewMode favorites modal styling.
src/components/modals/SettingsModal/SettingsModal.tsx Add header icon.
src/components/modals/SettingsModal/SettingsModal.css Adjust preset grid responsiveness (more columns + breakpoints).
src/components/modals/PaySettingsModal/PaySettingsModal.tsx Rename/retitle to “Pay Details”, add header icon + info box, and remove favorites syncing.
src/components/modals/PaySettingsModal/PaySettingsModal.css Update comment to “Pay Details”.
src/components/modals/GlossaryModal/GlossaryModal.tsx Add header icon.
src/components/modals/FeedbackModal/FeedbackModal.tsx Add header icon; remove screenshot attachment flow; comment out some UI.
src/components/modals/AccountsModal/AccountsModal.tsx Add header icon.
src/components/modals/AboutModal/AboutModal.tsx Use APP_NAME/APP_VERSION and add header icon; copy tweaks.
src/components/_shared/layout/ViewModeSelector/ViewModeSelector.tsx Simplify selector to use all selectable modes (remove favorites/settings button).
src/components/_shared/layout/ViewModeSelector/ViewModeSelector.test.tsx Update tests for new default options behavior.
src/components/_shared/layout/ViewModeSelector/ViewModeSelector.css Compact selector styling adjustments.
src/components/_shared/layout/ViewModeButton/index.ts Export new ViewModeButton.
src/components/_shared/layout/ViewModeButton/ViewModeButton.tsx Add new view-mode dropdown/preview control for headers.
src/components/_shared/layout/ViewModeButton/ViewModeButton.css Styling for new ViewModeButton.
src/components/_shared/layout/PageHeader/PageHeader.css Add inset focus rings to avoid sticky-header outline clipping.
src/components/_shared/layout/Modal/Modal.tsx Support headerIcon prop in Modal header.
src/components/_shared/layout/Modal/Modal.css Layout for modal header icon/title row.
src/components/_shared/layout/CompactViewModeSelector/index.ts Export new compact selector component.
src/components/_shared/layout/CompactViewModeSelector/CompactViewModeSelector.tsx Add compact hover/cycle view-mode selector with floating panel.
src/components/_shared/layout/CompactViewModeSelector/CompactViewModeSelector.css Styling for compact selector.
src/components/_shared/index.ts Export new shared primitives (ActionMenuButton, ViewModeButton, Compact selector, TransientStatusIndicator).
src/components/_shared/feedback/TransientStatusIndicator/index.ts Export TransientStatusIndicator.
src/components/_shared/feedback/TransientStatusIndicator/TransientStatusIndicator.tsx Add reusable fixed-position status indicator (zoom/undo/redo).
src/components/_shared/feedback/TransientStatusIndicator/TransientStatusIndicator.css Styling for status indicator + mobile behavior.
src/components/_shared/controls/ActionMenuButton/index.ts Export ActionMenuButton.
src/components/_shared/controls/ActionMenuButton/ActionMenuButton.tsx Add reusable dropdown action menu button.
src/components/_shared/controls/ActionMenuButton/ActionMenuButton.css Styling for ActionMenuButton.
src/components/PlanDashboard/PlanTabs/TabManagementModal.tsx Switch to Modal headerIcon prop instead of custom header markup.
src/components/PlanDashboard/PlanTabs/PlanTabs.tsx Minor formatting/clarity update to toggle icon rendering.
src/components/PlanDashboard/PlanTabs/PlanTabs.css Increase toggle icon size/stroke for visibility.
src/components/PlanDashboard/PlanHistoryOverlay/PlanHistoryOverlay.css Raise overlay z-index.
src/components/PlanDashboard/PlanDashboard.tsx Introduce view-mode preview state + new header controls; route pay-details open via modal; add copy-plan menu handler; use app version in feedback context.
src/components/PlanDashboard/PlanDashboard.css Header layout spacing tweaks for new controls.
src/App.tsx Replace ad-hoc zoom/undo overlays with TransientStatusIndicator.
package.json Bump app version to 0.4.2.
index.html Add CSP meta tag.
electron/main.ts Add “Copy Plan” menu item; rename “Pay Options” to “Pay Details”; adjust close/save prompting flow.
app_updates/v0.4.1-fixes.md Remove outdated internal checklist doc.
RELEASE_NOTES.md Update release notes for v0.4.2 items.

Comment on lines +37 to 41
const salaryOptions = [32000, 38000, 45000, 52000, 60000, 70000, 82000, 92000, 98000, 110000, 130000, 210000];
const variance = randomBetween(0.88, 1.12);
annualSalary = salaryOptions[Math.floor(Math.random() * salaryOptions.length)];
annualGrossPay = annualSalary;
annualGrossPay = annualSalary * variance;
}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

annualGrossPay is randomized with a variance multiplier, but the returned paySettings.annualSalary stays unadjusted. This makes the demo plan internally inconsistent (the UI will compute gross/net from paySettings.annualSalary, while taxes/bills/loans were generated off the larger/smaller annualGrossPay). Consider either applying the variance to annualSalary (so annualSalary matches annualGrossPay) or removing the variance and keeping gross derived directly from annualSalary.

Copilot uses AI. Check for mistakes.
Comment on lines +150 to +152
const monthlyAmount = billTemplate.basePercent == 0
? roundToCents(billTemplate.baseAmount * variance)
: roundToCents(monthlyGross * billTemplate.basePercent * variance);
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid loose equality here. billTemplate.basePercent is a number, so using === 0 is clearer and prevents unexpected coercions if this ever changes (e.g., parsed from JSON).

Copilot uses AI. Check for mistakes.
Comment on lines +212 to +252
<div
ref={panelRef}
className="view-mode-button__panel"
data-placement={placement}
role="menu"
aria-label="Select amount display mode"
onMouseLeave={clearPreview}
>
<div className="view-mode-button__hint">Hover to preview. Click to keep.</div>
<div className="view-mode-button__options">
{resolvedOptions.map((option) => {
const isActive = option.value === activeMode;
const isCommitted = option.value === committedMode;
const isHighlighted = option.value === highlightedValue;

return (
<button
key={option.value}
type="button"
className={`view-mode-button__option${isActive ? ' view-mode-button__option--active' : ''}${isCommitted ? ' view-mode-button__option--selected' : ''}`}
onMouseEnter={() => handlePreview(option.value)}
onFocus={() => handlePreview(option.value)}
onClick={() => handleCommit(option.value)}
role="menuitemradio"
aria-checked={isCommitted}
>
<span className="view-mode-button__option-main">
<span className="view-mode-button__option-label">{option.label}</span>
{isHighlighted && (
<span className="view-mode-button__option-badge">
<span className="view-mode-button__dot" aria-hidden="true" />
{highlightedLabel}
</span>
)}
</span>
{isCommitted && <Check className="ui-icon ui-icon-sm view-mode-button__check" aria-hidden="true" />}
</button>
);
})}
</div>
</div>
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dropdown panel and option buttons are always rendered (even when expanded is false) and the options have no tabIndex/aria-hidden gating. This makes the hidden menu items reachable via keyboard navigation/screen readers and can trap focus on invisible elements. Render the panel only when expanded, or add hidden/aria-hidden={!expanded} and ensure the option buttons are removed from the tab order when collapsed.

Suggested change
<div
ref={panelRef}
className="view-mode-button__panel"
data-placement={placement}
role="menu"
aria-label="Select amount display mode"
onMouseLeave={clearPreview}
>
<div className="view-mode-button__hint">Hover to preview. Click to keep.</div>
<div className="view-mode-button__options">
{resolvedOptions.map((option) => {
const isActive = option.value === activeMode;
const isCommitted = option.value === committedMode;
const isHighlighted = option.value === highlightedValue;
return (
<button
key={option.value}
type="button"
className={`view-mode-button__option${isActive ? ' view-mode-button__option--active' : ''}${isCommitted ? ' view-mode-button__option--selected' : ''}`}
onMouseEnter={() => handlePreview(option.value)}
onFocus={() => handlePreview(option.value)}
onClick={() => handleCommit(option.value)}
role="menuitemradio"
aria-checked={isCommitted}
>
<span className="view-mode-button__option-main">
<span className="view-mode-button__option-label">{option.label}</span>
{isHighlighted && (
<span className="view-mode-button__option-badge">
<span className="view-mode-button__dot" aria-hidden="true" />
{highlightedLabel}
</span>
)}
</span>
{isCommitted && <Check className="ui-icon ui-icon-sm view-mode-button__check" aria-hidden="true" />}
</button>
);
})}
</div>
</div>
{expanded && (
<div
ref={panelRef}
className="view-mode-button__panel"
data-placement={placement}
role="menu"
aria-label="Select amount display mode"
onMouseLeave={clearPreview}
>
<div className="view-mode-button__hint">Hover to preview. Click to keep.</div>
<div className="view-mode-button__options">
{resolvedOptions.map((option) => {
const isActive = option.value === activeMode;
const isCommitted = option.value === committedMode;
const isHighlighted = option.value === highlightedValue;
return (
<button
key={option.value}
type="button"
className={`view-mode-button__option${isActive ? ' view-mode-button__option--active' : ''}${isCommitted ? ' view-mode-button__option--selected' : ''}`}
onMouseEnter={() => handlePreview(option.value)}
onFocus={() => handlePreview(option.value)}
onClick={() => handleCommit(option.value)}
role="menuitemradio"
aria-checked={isCommitted}
>
<span className="view-mode-button__option-main">
<span className="view-mode-button__option-label">{option.label}</span>
{isHighlighted && (
<span className="view-mode-button__option-badge">
<span className="view-mode-button__dot" aria-hidden="true" />
{highlightedLabel}
</span>
)}
</span>
{isCommitted && <Check className="ui-icon ui-icon-sm view-mode-button__check" aria-hidden="true" />}
</button>
);
})}
</div>
</div>
)}

Copilot uses AI. Check for mistakes.
Comment on lines +401 to 402
{`${curr.name} (${curr.symbol})`}
</option>
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option label no longer includes the currency code (e.g., USD vs CAD both show "$"), which makes selecting the correct currency ambiguous. Consider including the ISO code in the label (e.g., "US Dollar ($) — USD").

Copilot uses AI. Check for mistakes.
Comment on lines 217 to +232
@@ -262,13 +223,13 @@ const FeedbackModal: React.FC<FeedbackModalProps> = ({ isOpen, onClose, context,
/>
Include environment diagnostics (tab, plan metadata, browser info)
</label>
</div>
</div> */}

<FormGroup label="Screenshot (optional)">
{/* <FormGroup label="Screenshot (optional)">
<input type="file" accept="image/*" onChange={handleScreenshotChange} />
{screenshot && <small className="helper-text">Attached: {screenshot.fileName}</small>}
{screenshotError && <small className="error">{screenshotError}</small>}
</FormGroup>
</FormGroup> */}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Large sections of UI are now commented out (diagnostics checkbox + screenshot attachment), but related state/logic (includeDiagnostics, payload shape, etc.) remains. This leaves dead/commented code paths that are easy to drift and harder to maintain. Prefer either fully removing the unused feature (and associated state) or re-enabling it behind a proper feature flag/config instead of commented JSX.

Copilot uses AI. Check for mistakes.
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http://localhost:* ws://localhost:* https://* wss://*; object-src 'none'; base-uri 'self'"
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CSP currently allows connect-src https://* wss://*, which largely negates the value of restricting network egress and makes it harder to reason about where the renderer can send data. If the app only needs a small set of endpoints (or only needs broad access in dev), consider tightening connect-src to self + explicit domains and/or conditionally using a more permissive CSP only in development.

Suggested change
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http://localhost:* ws://localhost:* https://* wss://*; object-src 'none'; base-uri 'self'"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http://localhost:* ws://localhost:*; object-src 'none'; base-uri 'self'"

Copilot uses AI. Check for mistakes.
Comment on lines +1224 to 1232
// Show "Do you want to save?" dialog for unsaved plans
const response = dialog.showMessageBoxSync(window, {
type: 'question',
buttons: ['Save', "Don't Save", 'Cancel'],
defaultId: 0,
cancelId: 2,
title: 'Unsaved Changes',
message: 'You have unsaved changes',
detail: 'Do you want to save your plan before closing this window?',
title: 'Save Plan?',
message: 'This plan has unsaved changes. Do you want to save before closing?',
});
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dialog.showMessageBoxSync blocks the Electron main process event loop while the dialog is open. Since this runs on window close, it can still freeze other windows/menus and makes shutdown behavior less responsive. Prefer using the async dialog.showMessageBox(...) API and awaiting it (as before) to avoid blocking the main process thread.

Copilot uses AI. Check for mistakes.
Comment on lines 1221 to 1232
);

if (hasUnsaved) {
const result = await dialog.showMessageBox(window, {
type: 'warning',
// Show "Do you want to save?" dialog for unsaved plans
const response = dialog.showMessageBoxSync(window, {
type: 'question',
buttons: ['Save', "Don't Save", 'Cancel'],
defaultId: 0,
cancelId: 2,
title: 'Unsaved Changes',
message: 'You have unsaved changes',
detail: 'Do you want to save your plan before closing this window?',
title: 'Save Plan?',
message: 'This plan has unsaved changes. Do you want to save before closing?',
});
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description/release notes say plans should auto-save on close (prompting only when the plan is new/unsaved), but this flow still always prompts whenever __hasUnsavedChanges is true. If the intended behavior is “silent save when a filePath exists”, consider checking for filePath (or exposing that from the renderer) and attempting __requestSaveBeforeClose() automatically, only falling back to a prompt when there’s no save path or when the save attempt fails.

Copilot uses AI. Check for mistakes.
ref={panelRef}
className={`cvms__panel cvms__panel--${panelLayout} cvms__panel--align-${panelAlignment}`}
role="listbox"
aria-label="Select view mode"
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When expanded is false, the listbox panel remains in the DOM with role="listbox" but is only visually hidden (opacity/pointer-events). Even though the options are removed from tab order, assistive tech can still encounter the collapsed listbox. Consider adding aria-hidden={!expanded} / hidden on the panel (and/or conditionally rendering it) so the collapsed UI isn’t announced.

Suggested change
aria-label="Select view mode"
aria-label="Select view mode"
aria-hidden={!expanded}
hidden={!expanded}

Copilot uses AI. Check for mistakes.
Comment on lines 320 to 325
<Dropdown value={editCurrency} onChange={(e) => setEditCurrency(e.target.value)}>
{CURRENCIES.map((currency) => (
<option key={currency.code} value={currency.code}>
{currency.symbol} - {currency.name} ({currency.code})
{currency.name} ({currency.symbol})
</option>
))}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dropdown label drops the currency code, which can be ambiguous for currencies sharing a symbol (USD/CAD/AUD, etc.). Consider including the ISO code in the visible label to prevent users selecting the wrong currency.

Copilot uses AI. Check for mistakes.
@kryptodrex kryptodrex deleted the v0.4.2 branch April 9, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v0.4.2 Fixes

2 participants