mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-09 18:32:52 +00:00
fix: truncate long sidebar stack names before trailing indicators clip (#1562)
Clamp the stack list width with ScrollArea block and min-w-0 on the row flex chain so long names ellipsize instead of pushing update dots past the sidebar edge. Add E2E layout coverage for trailing-indicator edge cases.
This commit is contained in:
@@ -205,7 +205,7 @@ export function StackList(props: StackListProps & StackListBulkProps) {
|
||||
<CommandItem
|
||||
value={file}
|
||||
onSelect={() => onSelectFile(file)}
|
||||
className="p-0 data-[selected=true]:bg-transparent"
|
||||
className="min-w-0 w-full p-0 data-[selected=true]:bg-transparent"
|
||||
>
|
||||
<StackRow
|
||||
file={file}
|
||||
|
||||
@@ -105,11 +105,11 @@ export function StackRow(props: StackRowProps) {
|
||||
<span className="flex-1 truncate font-mono text-sm min-w-0">{displayName}</span>
|
||||
|
||||
{/* Fixed trailing icon slot: update dot > check-failed > git pending */}
|
||||
<span className="w-3.5 h-3.5 flex items-center justify-center shrink-0">
|
||||
<span className="w-3.5 h-3.5 flex items-center justify-center shrink-0" data-testid="stack-row-trailing">
|
||||
{hasUpdate ? (
|
||||
<RowTooltip
|
||||
trigger={(
|
||||
<span className="relative inline-flex w-2 h-2">
|
||||
<span className="relative inline-flex w-2 h-2" data-testid="stack-trailing-update">
|
||||
<span className="absolute inset-0 rounded-full bg-update opacity-75 animate-ping" />
|
||||
<span className="relative w-2 h-2 rounded-full bg-update" />
|
||||
</span>
|
||||
@@ -118,12 +118,24 @@ export function StackRow(props: StackRowProps) {
|
||||
/>
|
||||
) : checkStatus === 'failed' ? (
|
||||
<RowTooltip
|
||||
trigger={<AlertCircle className="w-3 h-3 text-muted-foreground/70" strokeWidth={1.5} />}
|
||||
trigger={(
|
||||
<AlertCircle
|
||||
className="w-3 h-3 text-muted-foreground/70"
|
||||
strokeWidth={1.5}
|
||||
data-testid="stack-trailing-check-failed"
|
||||
/>
|
||||
)}
|
||||
label={lastError ? `Update check failed: ${lastError}` : 'Update check failed'}
|
||||
/>
|
||||
) : hasGitPending ? (
|
||||
<RowTooltip
|
||||
trigger={<GitBranch className="w-3 h-3 text-brand" strokeWidth={1.5} />}
|
||||
trigger={(
|
||||
<GitBranch
|
||||
className="w-3 h-3 text-brand"
|
||||
strokeWidth={1.5}
|
||||
data-testid="stack-trailing-git-pending"
|
||||
/>
|
||||
)}
|
||||
label="Git source update pending"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -95,7 +95,7 @@ export function StackSidebar(props: StackSidebarProps) {
|
||||
onClear={onClearSelection}
|
||||
/>
|
||||
)}
|
||||
<ScrollArea className="flex-1 px-2 pb-2">
|
||||
<ScrollArea block className="flex-1 px-2 pb-2">
|
||||
<div data-stacks-loaded={list.isLoading ? 'false' : 'true'}>
|
||||
<StackList {...list} bulkMode={bulkMode} selectedFiles={selectedFiles} onToggleSelect={onToggleSelect} />
|
||||
</div>
|
||||
|
||||
@@ -123,4 +123,11 @@ describe('StackRow', () => {
|
||||
expect(container.querySelector('[data-slot="cursor-container"]')).toBeNull();
|
||||
expect(container.querySelector('.bg-update')).toBeNull();
|
||||
});
|
||||
|
||||
it('constrains long stack names so trailing indicators stay in the row', () => {
|
||||
const longName = 'tick-grafana-docker-observability-stack';
|
||||
render(<StackRow {...base({ displayName: longName })} />);
|
||||
expect(screen.getByTestId('stack-row')).toHaveClass('min-w-0');
|
||||
expect(screen.getByText(longName)).toHaveClass('truncate');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export const sidebarRowBase = cn(
|
||||
'relative flex items-center gap-2 w-full px-2 py-1.5 rounded-md mb-0.5',
|
||||
'relative flex items-center gap-2 w-full min-w-0 px-2 py-1.5 rounded-md mb-0.5',
|
||||
// 44px tap target on touch viewports without changing desktop density.
|
||||
'max-md:min-h-11 max-md:py-2.5',
|
||||
'font-mono text-[13px] text-muted-foreground',
|
||||
|
||||
Reference in New Issue
Block a user