feat(jobs): add dedicated workspace page
CI and Deploy / test (pull_request) Failing after 2m51s
CI and Deploy / deploy (pull_request) Has been skipped

Make /jobs/:id the canonical application workspace while preserving list state and compatibility links. Replace popup and expandable-row navigation with accessible whole-row routing and richer job details.
This commit is contained in:
cesnimda
2026-08-15 13:33:00 +02:00
parent 0dfaac18a1
commit 109745edb0
18 changed files with 310 additions and 266 deletions
@@ -93,7 +93,7 @@ function renderWithProviders(initialPath: string, routes: React.ReactNode) {
<I18nProvider>
<ConfirmProvider>
<PromptProvider>
<MemoryRouter initialEntries={[initialPath]} future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
<MemoryRouter initialEntries={[initialPath]}>
<Routes>{routes}</Routes>
</MemoryRouter>
</PromptProvider>
@@ -134,32 +134,32 @@ test('follow-up workflow signals route all overview surfaces to the same follow-
const dashboardRender = renderWithProviders('/dashboard', <>
<Route path="/dashboard" element={<><LocationIndicator /><DashboardView /></>} />
<Route path="/jobs" element={<LocationIndicator />} />
<Route path="/jobs/:id" element={<LocationIndicator />} />
</>);
await screen.findByText(/follow-up is due for this role/i);
fireEvent.click(await screen.findByRole('button', { name: /follow up/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs?open=42&tab=4&followMode=waiting-update'));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
dashboardRender.unmount();
setupApiMocks({ reminders: [job], jobs: [job] });
const remindersRender = renderWithProviders('/reminders', <>
<Route path="/reminders" element={<><LocationIndicator /><RemindersView /></>} />
<Route path="/jobs" element={<LocationIndicator />} />
<Route path="/jobs/:id" element={<LocationIndicator />} />
</>);
fireEvent.click(await screen.findByRole('button', { name: /follow up/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs?open=42&tab=4&followMode=waiting-update'));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
remindersRender.unmount();
setupApiMocks({ reminders: [job], jobs: [job] });
renderWithProviders('/table', <>
<Route path="/table" element={<><LocationIndicator /><JobTable refreshToken={0} pageSize={15} onPageSizeChange={() => {}} columns={{ status: true, dateApplied: true, daysSince: true, jobUrl: false }} onColumnsChange={() => {}} mode="jobs" /></>} />
<Route path="/jobs" element={<LocationIndicator />} />
<Route path="/jobs/:id" element={<LocationIndicator />} />
</>);
fireEvent.click(await screen.findByRole('button', { name: /backend developer — follow up signal/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs?open=42&tab=4&followMode=waiting-update'));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
});
test('package-work workflow signals route all overview surfaces to the shared tailored-cv workspace', async () => {
@@ -186,31 +186,31 @@ test('package-work workflow signals route all overview surfaces to the shared ta
const dashboardRender = renderWithProviders('/dashboard', <>
<Route path="/dashboard" element={<><LocationIndicator /><DashboardView /></>} />
<Route path="/jobs" element={<LocationIndicator />} />
<Route path="/jobs/:id" element={<LocationIndicator />} />
</>);
fireEvent.click(await screen.findByRole('button', { name: /build package/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs?open=43&tab=3'));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/43?section=cv'));
dashboardRender.unmount();
setupApiMocks({ reminders: [job], jobs: [job] });
const remindersRender = renderWithProviders('/reminders', <>
<Route path="/reminders" element={<><LocationIndicator /><RemindersView /></>} />
<Route path="/jobs" element={<LocationIndicator />} />
<Route path="/jobs/:id" element={<LocationIndicator />} />
</>);
fireEvent.click(await screen.findByRole('button', { name: /build package/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs?open=43&tab=3'));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/43?section=cv'));
remindersRender.unmount();
setupApiMocks({ reminders: [job], jobs: [job] });
renderWithProviders('/table', <>
<Route path="/table" element={<><LocationIndicator /><JobTable refreshToken={0} pageSize={15} onPageSizeChange={() => {}} columns={{ status: true, dateApplied: true, daysSince: true, jobUrl: false }} onColumnsChange={() => {}} mode="jobs" /></>} />
<Route path="/jobs" element={<LocationIndicator />} />
<Route path="/jobs/:id" element={<LocationIndicator />} />
</>);
fireEvent.click(await screen.findByRole('button', { name: /platform engineer — build package signal/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs?open=43&tab=3'));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/43?section=cv'));
});
test('job table readiness filter follows workflow signals instead of raw notes or cv text heuristics', async () => {