mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-18 22:36:19 +00:00
fix: make Reduced motion gate overlays, standardize the tab band, and polish fleet/snapshots (#1504)
* fix: address review feedback on motion, fleet band, and snapshots - Reduced motion now also skips the animate-ui overlay open/close animations (dialog, sheet, popover, dropdown-menu) via a shared useReducedTransition that zeroes the transition when reduced motion is active; MotionConfig alone only neutralized transform/layout, leaving the opacity/blur fade. - Fleet tab band: flatten the list's own pill band so the tabs sit in a single full-width band instead of a nested second band. - Fleet Overview: label the node-update button "Node Update"; the add-node button becomes a ChartNetwork icon that opens Settings > Nodes (outline style, matching the node-update button) instead of the add-node modal. - Blueprint deployments empty state: drive the serif headings from the theme heading-style token so Calm drops the italic. - Snapshots: move the per-stack Restore onto the stack header row (right side), matching the ghost action style. * feat: standardize the tab band on Security and add a tab hover state - Apply the Fleet full-width tab band to the Security page (single band, the list's pill background flattened so the tabs sit directly in it). - Add a hover highlight to tabs so the band reads as interactive, not flat; the active tab is unaffected. * fix: drive reduced-motion transitions from the app setting, not the OS query useReducedTransition called framer-motion's useReducedMotion(), which only reflects the OS prefers-reduced-motion media query and ignores our MotionConfig / appearance toggle, so dialogs kept animating with the setting on. Read the app's useReducedMotion selector instead. Verified: with the setting on, the dialog opacity snaps 0->1 in one frame; with it off, it ramps over the spring. * feat: standardize stack-detail body text to text-xs and add a log expand toggle - Bump the anatomy panel body text (rows, field values, warnings) and the structured log lines from 10/11/12px to text-xs (12px), leaving the uppercase kicker labels and the log level/source badges as-is. - Add an expand control next to the log download button that collapses the Command Center so the logs pane fills the left column; toggles back to restore.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Search, ArrowUpDown, AlertTriangle, Play, Square,
|
||||
LayoutGrid, Network, SlidersHorizontal, Plus, RefreshCcwDot,
|
||||
LayoutGrid, Network, SlidersHorizontal, ChartNetwork, RefreshCcwDot,
|
||||
} from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -259,25 +259,27 @@ export function OverviewToolbar({
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-9 w-9 p-0 shrink-0"
|
||||
className="h-9 gap-2 shrink-0"
|
||||
onClick={onCheckUpdates}
|
||||
disabled={checkingUpdates}
|
||||
title="Check for updates"
|
||||
aria-label="Check for updates"
|
||||
title="Check for node updates"
|
||||
aria-label="Check for node updates"
|
||||
>
|
||||
<RefreshCcwDot className={`w-4 h-4 ${checkingUpdates ? 'animate-spin' : ''}`} />
|
||||
Node Update
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{onAddNode && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-9 w-9 p-0 shrink-0"
|
||||
onClick={onAddNode}
|
||||
title="Add node"
|
||||
aria-label="Add node"
|
||||
title="Manage nodes"
|
||||
aria-label="Manage nodes"
|
||||
>
|
||||
<Plus className="w-4 h-4" strokeWidth={1.5} />
|
||||
<ChartNetwork className="w-4 h-4" strokeWidth={1.5} />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -82,32 +82,32 @@ describe('OverviewToolbar', () => {
|
||||
expect(screen.queryByText('Tags')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the Add node button and fires onAddNode when provided', () => {
|
||||
it('renders the manage-nodes button and fires onAddNode when provided', () => {
|
||||
const onAddNode = vi.fn();
|
||||
render(<OverviewToolbar {...props({ onAddNode })} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Add node' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Manage nodes' }));
|
||||
expect(onAddNode).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('omits the Add node button when onAddNode is not provided', () => {
|
||||
it('omits the manage-nodes button when onAddNode is not provided', () => {
|
||||
render(<OverviewToolbar {...props()} />);
|
||||
expect(screen.queryByRole('button', { name: 'Add node' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: 'Manage nodes' })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the Check Updates button and fires onCheckUpdates when provided', () => {
|
||||
const onCheckUpdates = vi.fn();
|
||||
render(<OverviewToolbar {...props({ onCheckUpdates })} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /Check for updates/ }));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Check for node updates/ }));
|
||||
expect(onCheckUpdates).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('omits the Check Updates button when onCheckUpdates is not provided', () => {
|
||||
render(<OverviewToolbar {...props()} />);
|
||||
expect(screen.queryByRole('button', { name: /Check for updates/ })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: /Check for node updates/ })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('disables the Check Updates button while a check is in flight', () => {
|
||||
render(<OverviewToolbar {...props({ onCheckUpdates: vi.fn(), checkingUpdates: true })} />);
|
||||
expect(screen.getByRole('button', { name: /Check for updates/ })).toBeDisabled();
|
||||
expect(screen.getByRole('button', { name: /Check for node updates/ })).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user