Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions frontend/src/lib/features/collections/CollectionTree.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,14 @@
: []
);

// Leading hierarchy track holds indent + expander (+ test case badge). It is
// sized for the deepest visible row so the configured columns stay aligned.
let hierarchyWidth = $derived.by(() => {
const maxLevel = treeData.reduce((max, row) => Math.max(max, row.level), 0);
return maxLevel * 1.5 + 1.5 + (showTestCases ? 3 : 0);
});
// Leading hierarchy track holds the expander (+ test case badge); the depth
// indent is applied to the title cell so every child row shows its nesting.
let hierarchyWidth = $derived(1.5 + (showTestCases ? 3 : 0));
let indentColumnId = $derived(
listColumns.some((column) => column.field_identifier === 'title')
? 'title'
: listColumns[0]?.field_identifier
);
let gridTemplateColumns = $derived(`${hierarchyWidth}rem ${listGridTemplateColumns(listColumns)}`);
let gridMinWidth = $derived(`calc(${listGridMinWidth(listColumns)} + ${hierarchyWidth + 1}rem)`);
</script>
Expand Down Expand Up @@ -520,14 +522,17 @@
style="grid-template-columns: {gridTemplateColumns}; min-width: {gridMinWidth};"
>
<!-- Hierarchy Indent + Icon -->
<div class="flex items-center gap-1" style="padding-left: {getIndentLevel(item.level)}">
<div class="flex items-center gap-1">
<div class="w-4 h-4 rounded flex items-center justify-center bg-ds-accent-green">
<FileCheck class="w-2.5 h-2.5 text-white" />
</div>
</div>

{#each listColumns as column (column.field_identifier)}
<div class="min-w-0 overflow-hidden">
<div
class="min-w-0 overflow-hidden"
style={column.field_identifier === indentColumnId ? `padding-left: ${getIndentLevel(item.level)}` : undefined}
>
{#if column.field_identifier === 'key'}
<LinkComponent
href="#view-test-case"
Expand Down Expand Up @@ -560,7 +565,7 @@
style="grid-template-columns: {gridTemplateColumns}; min-width: {gridMinWidth}; border-top: 1px solid var(--ctx-border, var(--ds-border));{idx === 0 ? 'border-top: none;' : ''}"
>
<!-- Hierarchy Indent + Expand/Collapse + Test Case Count -->
<div class="flex items-center gap-1" style="padding-left: {getIndentLevel(item.level)}">
<div class="flex items-center gap-1">
{#if item.hasChildren}
<button
class="w-6 h-6 flex items-center justify-center rounded transition-colors cursor-pointer expand-btn"
Expand All @@ -586,7 +591,10 @@
</div>

{#each listColumns as column (column.field_identifier)}
<div class="min-w-0 overflow-hidden">
<div
class="min-w-0 overflow-hidden"
style={column.field_identifier === indentColumnId ? `padding-left: ${getIndentLevel(item.level)}` : undefined}
>
<ListCellRenderer
{item}
{column}
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/lib/features/items/ItemDetail.svelte
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<script module>
// Site title from index.html, captured once so nested item views (e.g. a modal
// over an item page) don't stack item titles on top of each other.
const siteTitle = typeof document !== 'undefined' ? document.title : '';
</script>

<script>
import { onMount, onDestroy, untrack } from 'svelte';
import { copyToClipboard } from '../../utils/clipboard.js';
Expand Down Expand Up @@ -67,6 +73,19 @@ import NativeSelect from '../../components/NativeSelect.svelte';
let item = $derived(itemDetailStore.item);
let workspace = $derived(itemDetailStore.workspace);

// Show "KEY-123 Title - <site title>" in the browser tab while the item is open;
// restore the previous title when the detail view closes.
const previousDocumentTitle = document.title;
$effect(() => {
if (!item?.workspace_item_number) return;
const k = item.workspace_key || workspace?.key;
const itemKey = k ? `${k}-${item.workspace_item_number}` : `ITEM-${item.workspace_item_number}`;
document.title = `${itemKey} ${item.title || ''}`.trim() + ` - ${siteTitle}`;
});
onDestroy(() => {
document.title = previousDocumentTitle;
});

// A reconcile request that arrives while the detail is loading must not be
// dropped: queue it and run once the in-flight load settles.
let reconcilePending = $state(false);
Expand Down
Loading