FN-5765: move settings version check from header to footer
Relocate Settings version/update UI into the modal footer to reduce header crowding. - Remove the version/update-check control block from the Settings modal header. - Add a dedicated footer version container and keep the update-check action/result rendering there. - Update Settings modal CSS for the new footer layout and mobile wrapping behavior. - Extend mobile tests to verify footer placement and update-check button clickability. Files changed: packages/dashboard/app/components/SettingsModal.css | 25 +++++++-- packages/dashboard/app/components/SettingsModal.tsx | 64 +++++++++++----------- packages/dashboard/app/components/__tests__/settings-mobile.test.tsx | 27 ++++++++- 3 files changed, 77 insertions(+), 39 deletions(-) Fusion-Task-Id: FN-5765 Fusion-Task-Lineage: 97923f08-e787-4274-a4ce-8b615b909468
This commit is contained in:
@@ -41,11 +41,6 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.settings-update-check {
|
||||
flex-wrap: wrap;
|
||||
row-gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.settings-header-actions {
|
||||
margin-left: auto;
|
||||
margin-right: var(--space-sm);
|
||||
@@ -164,10 +159,30 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.settings-modal-footer-version {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: var(--space-sm);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.settings-update-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.settings-modal-footer-version {
|
||||
flex: 1 1 100%;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.settings-update-check {
|
||||
flex-wrap: wrap;
|
||||
row-gap: var(--space-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.settings-version-check-btn {
|
||||
|
||||
@@ -7443,37 +7443,6 @@ export function SettingsModal({
|
||||
<div className="modal-header">
|
||||
<div className="settings-modal-heading">
|
||||
<h3>Settings</h3>
|
||||
<div className="settings-update-check">
|
||||
{appVersion && (
|
||||
<button
|
||||
type="button"
|
||||
className="settings-version-check-btn"
|
||||
onClick={() => {
|
||||
void handleCheckForUpdates();
|
||||
}}
|
||||
disabled={updateCheckLoading}
|
||||
aria-label="Check for updates"
|
||||
title="Check for updates"
|
||||
>
|
||||
<span className="settings-modal-version">Version {appVersion}</span>
|
||||
<RefreshCw size={12} className={updateCheckLoading ? "spinning" : undefined} />
|
||||
</button>
|
||||
)}
|
||||
{updateCheckResult && (
|
||||
<span
|
||||
aria-live="polite"
|
||||
className={`settings-update-result ${
|
||||
updateCheckResult.error
|
||||
? "settings-update-result--error"
|
||||
: updateCheckResult.updateAvailable
|
||||
? "settings-update-result--available"
|
||||
: "settings-update-result--up-to-date"
|
||||
}`}
|
||||
>
|
||||
{renderUpdateCheckResultContent()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-header-actions">
|
||||
{form.showGitHubStarButton !== false && (
|
||||
@@ -7588,6 +7557,39 @@ export function SettingsModal({
|
||||
</div>
|
||||
)}
|
||||
<div className="modal-actions">
|
||||
<div className="settings-modal-footer-version">
|
||||
<div className="settings-update-check">
|
||||
{appVersion && (
|
||||
<button
|
||||
type="button"
|
||||
className="settings-version-check-btn"
|
||||
onClick={() => {
|
||||
void handleCheckForUpdates();
|
||||
}}
|
||||
disabled={updateCheckLoading}
|
||||
aria-label="Check for updates"
|
||||
title="Check for updates"
|
||||
>
|
||||
<span className="settings-modal-version">Version {appVersion}</span>
|
||||
<RefreshCw size={12} className={updateCheckLoading ? "spinning" : undefined} />
|
||||
</button>
|
||||
)}
|
||||
{updateCheckResult && (
|
||||
<span
|
||||
aria-live="polite"
|
||||
className={`settings-update-result ${
|
||||
updateCheckResult.error
|
||||
? "settings-update-result--error"
|
||||
: updateCheckResult.updateAvailable
|
||||
? "settings-update-result--available"
|
||||
: "settings-update-result--up-to-date"
|
||||
}`}
|
||||
>
|
||||
{renderUpdateCheckResultContent()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-actions-left">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
||||
import { loadAllAppCss } from "../../test/cssFixture";
|
||||
import path from "node:path";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import { render, waitFor, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { SettingsModal } from "../SettingsModal";
|
||||
import type { Settings } from "@fusion/core";
|
||||
@@ -192,10 +192,31 @@ describe("SettingsModal mobile adaptations", () => {
|
||||
|
||||
it("renders the app version label in mobile layout", async () => {
|
||||
mockSettingsViewport(true);
|
||||
const { findByText } = render(<SettingsModal onClose={vi.fn()} addToast={vi.fn()} />);
|
||||
const { findByText, container } = render(<SettingsModal onClose={vi.fn()} addToast={vi.fn()} />);
|
||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
|
||||
|
||||
expect(await findByText("Version 1.2.3")).toBeTruthy();
|
||||
const version = await findByText("Version 1.2.3");
|
||||
const modalActions = container.querySelector(".modal-actions");
|
||||
const modalHeader = container.querySelector(".modal-header");
|
||||
|
||||
expect(version).toBeTruthy();
|
||||
expect(modalActions?.contains(version)).toBe(true);
|
||||
expect(modalHeader?.contains(version)).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps update-check button clickable from the footer", async () => {
|
||||
mockSettingsViewport(true);
|
||||
const user = userEvent.setup();
|
||||
const { container } = render(<SettingsModal onClose={vi.fn()} addToast={vi.fn()} />);
|
||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
|
||||
|
||||
const modalActions = container.querySelector(".modal-actions");
|
||||
expect(modalActions).toBeTruthy();
|
||||
|
||||
const updateButton = within(modalActions as HTMLElement).getByRole("button", { name: "Check for updates" });
|
||||
await user.click(updateButton);
|
||||
|
||||
expect(updateButton).toBeTruthy();
|
||||
});
|
||||
|
||||
it("excludes research sections from mobile picker when researchView is disabled", async () => {
|
||||
|
||||
Reference in New Issue
Block a user