fix: address workbench inspector review findings
This commit is contained in:
67
.superpowers/sdd/task-4-report.md
Normal file
67
.superpowers/sdd/task-4-report.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Task 4 Report: Channel Content Templates And Object Inspector
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Implemented and committed the Task 4 workbench channel templates and object inspector.
|
||||||
|
|
||||||
|
## What Changed
|
||||||
|
|
||||||
|
- Added `ChannelContent.svelte`, which dispatches `ProjectWorkspace` data to the selected system or custom channel template.
|
||||||
|
- Added seven channel templates for overview, inbox, tasks, AI sessions, notes and sources, cron plans, and external custom links.
|
||||||
|
- Made all applicable records selectable through an `Inspect <title>` action that supplies an `InspectorItem` to the workbench.
|
||||||
|
- Added `ObjectInspector.svelte` with Discussion, Properties, and More tabs, including empty-state behavior and object properties.
|
||||||
|
- Wired the selected channel and selected inspector item into `ProjectWorkbench.svelte`.
|
||||||
|
- Added the required channel dispatcher test, including the task-to-inspector callback assertion.
|
||||||
|
- Kept visual-system CSS untouched for Task 5.
|
||||||
|
|
||||||
|
## TDD Evidence
|
||||||
|
|
||||||
|
1. Added `apps/web/src/features/workbench/ChannelContent.test.ts` before creating any production channel component.
|
||||||
|
2. Ran `npm test -- --run src/features/workbench/ChannelContent.test.ts` from `apps/web`.
|
||||||
|
3. Observed the expected red failure: Vite could not resolve `./ChannelContent.svelte` because it did not exist.
|
||||||
|
4. Implemented the dispatcher and channel components, then ran the focused channel and workbench tests.
|
||||||
|
5. Corrected the inspector tab semantics after the green run exposed Svelte accessibility warnings, then reran verification with no warnings.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
- `npm test -- --run src/features/workbench/ChannelContent.test.ts src/features/workbench/ProjectWorkbench.test.ts`
|
||||||
|
- Passed: 2 test files, 4 tests.
|
||||||
|
- `npm run build`
|
||||||
|
- Passed: Vite production build completed successfully.
|
||||||
|
- `git diff --check`
|
||||||
|
- Passed: no whitespace errors.
|
||||||
|
|
||||||
|
## Files Changed
|
||||||
|
|
||||||
|
- Created `apps/web/src/features/workbench/ChannelContent.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/ChannelContent.test.ts`
|
||||||
|
- Created `apps/web/src/features/workbench/ObjectInspector.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/OverviewChannel.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/InboxChannel.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/TasksChannel.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/AISessionsChannel.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/NotesSourcesChannel.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/CronChannel.svelte`
|
||||||
|
- Created `apps/web/src/features/workbench/channels/CustomLinkChannel.svelte`
|
||||||
|
- Modified `apps/web/src/features/workbench/ProjectWorkbench.svelte`
|
||||||
|
- Created this report: `.superpowers/sdd/task-4-report.md`
|
||||||
|
|
||||||
|
## Self-Review
|
||||||
|
|
||||||
|
- Confirmed every `WorkbenchChannel` type has a dedicated rendered template through the dispatcher.
|
||||||
|
- Confirmed the custom link uses the required `Open external channel` text and provides a copy-style action.
|
||||||
|
- Confirmed task inspection produces the exact task title required by the test.
|
||||||
|
- Confirmed the inspector remains visible through its existing `aria-label` and exposes semantic tab state using `role="tab"` with `aria-selected`.
|
||||||
|
- Confirmed no React, shadcn/ui dependency, or index.css modification was introduced.
|
||||||
|
- Confirmed unrelated existing `.superpowers/sdd` files were not staged.
|
||||||
|
|
||||||
|
## Concerns
|
||||||
|
|
||||||
|
- The copy URL and inspector More-tab actions are present as MVP UI controls; beyond writing the custom URL to the clipboard, they intentionally do not persist or mutate workbench data.
|
||||||
|
- Visual styling is limited to semantic class hooks by design; Task 5 owns the visual-system CSS work.
|
||||||
|
|
||||||
|
## Review Fixes
|
||||||
|
|
||||||
|
- Replaced the incomplete ARIA tabs pattern in `ObjectInspector.svelte` with ordinary pressed view-switcher buttons, removing tab and tablist roles that required a full tab-panel keyboard interaction model.
|
||||||
|
- Extended `ProjectWorkbench.test.ts` to select the Work Plan channel, inspect a task, and assert the rendered inspector title plus Properties values within the object inspector.
|
||||||
|
- Focused workbench coverage passed after the changes: 2 test files, 5 tests.
|
||||||
@@ -6,10 +6,10 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<aside class="object-inspector" aria-label="Object inspector">
|
<aside class="object-inspector" aria-label="Object inspector">
|
||||||
<div class="inspector-tabs" role="tablist" aria-label="Inspector tabs">
|
<div class="inspector-tabs">
|
||||||
<button role="tab" aria-selected={activeTab === 'discussion'} on:click={() => (activeTab = 'discussion')}>Discussion</button>
|
<button type="button" aria-pressed={activeTab === 'discussion'} on:click={() => (activeTab = 'discussion')}>Discussion</button>
|
||||||
<button role="tab" aria-selected={activeTab === 'properties'} on:click={() => (activeTab = 'properties')}>Properties</button>
|
<button type="button" aria-pressed={activeTab === 'properties'} on:click={() => (activeTab = 'properties')}>Properties</button>
|
||||||
<button role="tab" aria-selected={activeTab === 'more'} on:click={() => (activeTab = 'more')}>More</button>
|
<button type="button" aria-pressed={activeTab === 'more'} on:click={() => (activeTab = 'more')}>More</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if item}
|
{#if item}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import '@testing-library/jest-dom/vitest';
|
import '@testing-library/jest-dom/vitest';
|
||||||
import { fireEvent, render, screen } from '@testing-library/svelte';
|
import { fireEvent, render, screen, within } from '@testing-library/svelte';
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import ProjectWorkbench from './ProjectWorkbench.svelte';
|
import ProjectWorkbench from './ProjectWorkbench.svelte';
|
||||||
|
|
||||||
@@ -23,4 +23,24 @@ describe('ProjectWorkbench', () => {
|
|||||||
expect(screen.getByRole('button', { name: 'Project A2' })).toHaveAttribute('aria-pressed', 'true');
|
expect(screen.getByRole('button', { name: 'Project A2' })).toHaveAttribute('aria-pressed', 'true');
|
||||||
expect(screen.getByText('Ops Dashboard')).toBeInTheDocument();
|
expect(screen.getByText('Ops Dashboard')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows inspected task details in the inspector', async () => {
|
||||||
|
render(ProjectWorkbench, { props: { currentUser: { account: 'david@example.com' } } });
|
||||||
|
const inspector = screen.getByLabelText('Object inspector');
|
||||||
|
|
||||||
|
expect(within(inspector).getByRole('button', { name: 'Discussion' })).toHaveAttribute('aria-pressed', 'true');
|
||||||
|
|
||||||
|
await fireEvent.click(screen.getByRole('button', { name: 'Work Plan 8' }));
|
||||||
|
await fireEvent.click(screen.getByRole('button', { name: 'Inspect Confirm homepage information architecture' }));
|
||||||
|
|
||||||
|
expect(within(inspector).getByRole('heading', { name: 'Confirm homepage information architecture' })).toBeInTheDocument();
|
||||||
|
|
||||||
|
await fireEvent.click(within(inspector).getByRole('button', { name: 'Properties' }));
|
||||||
|
|
||||||
|
expect(within(inspector).getByRole('button', { name: 'Properties' })).toHaveAttribute('aria-pressed', 'true');
|
||||||
|
expect(within(inspector).getByText('Status')).toBeInTheDocument();
|
||||||
|
expect(within(inspector).getByText('Open')).toBeInTheDocument();
|
||||||
|
expect(within(inspector).getByText('Owner')).toBeInTheDocument();
|
||||||
|
expect(within(inspector).getByText('David')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user