Skip to content
Merged
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
1 change: 1 addition & 0 deletions docs/site-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This file is generated by `npm run sitemap:update`. Run `npm run sitemap:check`
- `/privacy` - Privacy and data-processing governance draft. Source: `src/app/privacy/page.tsx`.
- `/reference/colour-coding` - Route discovered from app directory Source: `src/app/reference/colour-coding/page.tsx`.
- `/services` - Services home and search surface. Source: `src/app/services/page.tsx`.
- `/tools` - Route discovered from app directory Source: `src/app/tools/page.tsx`.

## Mode/query routes

Expand Down
2 changes: 1 addition & 1 deletion scripts/ensure-local-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const printUrlOnly = process.argv.slice(2).includes("--print-url");
const debugEnabled = process.env.ENSURE_DEBUG === "1";
const startupLockStaleMs = 3 * 60 * 1000;
const readyStableMs = 5 * 1000;
const readinessPaths = ["/", "/applications"];
const readinessPaths = ["/", "/applications", "/tools"];

function debug(message) {
if (debugEnabled) console.error(`[ensure-local-server] ${message}`);
Expand Down
32 changes: 15 additions & 17 deletions src/app/applications/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import type { Metadata } from "next";

import { ApplicationsLauncherPage } from "@/components/applications-launcher-page";

export const metadata: Metadata = {
title: "Applications - Clinical KB",
description: "Launch Clinical KB applications, workflows, and connected clinical tools.",
};
import { redirect } from "next/navigation";

type ApplicationsPageProps = {
searchParams?: Promise<{
q?: string | string[];
}>;
searchParams?: Promise<Record<string, string | string[] | undefined>>;
};

function firstSearchParam(value: string | string[] | undefined) {
return Array.isArray(value) ? value[0] : value;
function forwardedSearchParams(params: Record<string, string | string[] | undefined>) {
const forwarded = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
for (const item of Array.isArray(value) ? value : [value]) {
if (item !== undefined) forwarded.append(key, item);
}
}
return forwarded.toString();
}

export default async function ApplicationsRoute({ searchParams }: ApplicationsPageProps) {
// "Tools" is the canonical name and /tools the canonical route (PT-11); this
// legacy route only forwards old links and browser history.
export default async function ApplicationsRedirect({ searchParams }: ApplicationsPageProps) {
const params = searchParams ? await searchParams : {};
const query = firstSearchParam(params.q)?.trim();

return query ? <ApplicationsLauncherPage key={query} query={query} /> : <ApplicationsLauncherPage />;
const query = forwardedSearchParams(params);
redirect(query ? `/tools?${query}` : "/tools");
Comment thread
BigSimmo marked this conversation as resolved.
}
6 changes: 3 additions & 3 deletions src/app/applications/error.tsx → src/app/tools/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export default function ErrorBoundary({ error, reset }: { error: Error & { diges
<RouteErrorBoundary
error={error}
reset={reset}
title="Failed to load applications"
description="An unexpected error occurred while loading the applications launcher."
logLabel="Unhandled runtime error captured in applications segment:"
title="Failed to load tools"
description="An unexpected error occurred while loading the tools launcher."
logLabel="Unhandled runtime error captured in tools segment:"
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ReactNode } from "react";

import { GlobalSearchShell } from "@/components/clinical-dashboard/global-search-shell";

export default function ApplicationsLayout({ children }: { children: ReactNode }) {
export default function ToolsLayout({ children }: { children: ReactNode }) {
return (
<GlobalSearchShell initialMode="tools" desktopSearchPlacement="hero">
{children}
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions src/app/tools/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Metadata } from "next";

import { ApplicationsLauncherPage } from "@/components/applications-launcher-page";

export const metadata: Metadata = {
title: "Tools - Clinical KB",
description: "Launch Clinical KB tools, workflows, and connected clinical applications.",
};

export default function ToolsRoute() {
return <ApplicationsLauncherPage />;
}
2 changes: 1 addition & 1 deletion src/components/clinical-dashboard/ClinicalSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const sidebarToolItems = [
{ id: "forms", label: "Forms", icon: ClipboardPen, href: "/forms" },
{ id: "favourites", label: "Favourites", icon: Heart, href: "/favourites" },
{ id: "differentials", label: "Differentials", icon: BrainCircuit, href: "/differentials" },
{ id: "prescribing", label: "Medications", icon: Pill, href: "/?mode=prescribing" },
{ id: "prescribing", label: "Medication", icon: Pill, href: "/?mode=prescribing" },
{ id: "tools", label: "Tools", icon: Wrench, href: "/?mode=tools" },
] as const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ function GlobalStandaloneSearchShellClient({
(searchMode === "forms" && pathname === "/forms") ||
(searchMode === "favourites" && pathname === "/favourites") ||
(searchMode === "differentials" && pathname === "/differentials") ||
(searchMode === "tools" && pathname === "/applications"));
(searchMode === "tools" && pathname === "/tools"));
const isDifferentialPresentationWorkflow = pathname.startsWith("/differentials/presentations");
const shouldShowDesktopSidebar = !hideDesktopSidebar;
const effectiveSidebarCollapsed = isDifferentialPresentationWorkflow ? true : sidebarCollapsed;
Expand Down
5 changes: 3 additions & 2 deletions src/components/clinical-dashboard/master-search-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,9 @@ export function MasterSearchHeader({
const activeQuickFilterCount =
(scopeFilters.sourceStatuses?.length ? 1 : 0) + (scopeFilters.locality ? 1 : 0) + activeLabelFilterCount;
const submitLabel = trimmedQuery ? selectedSearch.submitBusyLabel : selectedSearch.submitIdleLabel;
const queryPlaceholder =
composerPlaceholder ?? (isAnswerFooterComposer ? "Ask Clinical Guide" : selectedSearch.placeholder);
// One task-oriented placeholder per mode (PT-14): the follow-up composer must
// not swap to brand copy that hides what the input actually does.
const queryPlaceholder = composerPlaceholder ?? selectedSearch.placeholder;
const SelectedAppModeIcon = appModeIcons[selectedAppMode.id];
const actionMenuModeOptions = useMemo<ModeActionModeOption[]>(
() =>
Expand Down
4 changes: 2 additions & 2 deletions tests/ui-smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ test.describe("Clinical KB UI smoke coverage", () => {
{ name: "Forms", href: "/forms" },
{ name: "Favourites", href: "/favourites" },
{ name: "Differentials", href: "/differentials" },
{ name: "Medications", href: "/?mode=prescribing" },
{ name: "Medication", href: "/?mode=prescribing" },
{ name: "Tools", href: "/?mode=tools" },
] as const) {
await expect(page.getByRole("link", { name: tool.name, exact: true })).toHaveAttribute("href", tool.href);
Expand All @@ -963,7 +963,7 @@ test.describe("Clinical KB UI smoke coverage", () => {
{ path: "/?mode=answer", label: "Answer" },
{ path: "/?mode=documents", label: "Documents" },
{ path: "/favourites", label: "Favourites" },
{ path: "/?mode=prescribing", label: "Medications" },
{ path: "/?mode=prescribing", label: "Medication" },
] as const) {
await gotoApp(page, route.path);
if (route.path.includes("mode=answer")) {
Expand Down
10 changes: 5 additions & 5 deletions tests/ui-tools.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,9 @@ test.describe("Clinical KB tools launcher", () => {
});
}

test("standalone applications route uses the shared global search", async ({ page }) => {
test("standalone tools route uses the shared global search", async ({ page }) => {
await page.setViewportSize({ width: 1280, height: 900 });
await gotoLauncher(page, "/applications");
await gotoLauncher(page, "/tools");

await expect(page.getByRole("heading", { level: 1, name: "Tools" })).toBeVisible();
await expect(visibleGlobalSearchInput(page)).toHaveCount(1);
Expand Down Expand Up @@ -469,7 +469,7 @@ test.describe("Clinical KB tools launcher", () => {
{ path: "/forms", testId: "forms-home", heading: "Forms", headingLevel: 1 },
{ path: "/differentials", testId: "differentials-home", heading: "Differentials", headingLevel: 1 },
{ path: "/favourites", testId: "favourites-hub", heading: "Favourites command library", headingLevel: 1 },
{ path: "/applications", testId: "tools-home", heading: "Tools", headingLevel: 1 },
{ path: "/tools", testId: "tools-home", heading: "Tools", headingLevel: 1 },
] as const) {
await gotoLauncher(page, home.path);
await expect(page.getByTestId(home.testId)).toBeVisible();
Expand Down Expand Up @@ -638,7 +638,7 @@ test.describe("Clinical KB tools launcher", () => {

test("phone mode homes keep the shared search in the hero, not the bottom dock", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 820 });
for (const home of ["/services", "/forms", "/differentials", "/applications"]) {
for (const home of ["/services", "/forms", "/differentials", "/tools"]) {
await gotoLauncher(page, home);
const heroInput = page.locator(".mode-home-composer-slot").getByTestId("global-search-input");
await expect(heroInput).toBeVisible({ timeout: 15_000 });
Expand Down Expand Up @@ -695,7 +695,7 @@ test.describe("Clinical KB tools launcher", () => {
{ path: "/services", testId: "services-home", heading: "Find a service", headingLevel: 1 },
{ path: "/forms", testId: "forms-home", heading: "Forms", headingLevel: 1 },
{ path: "/differentials", testId: "differentials-home", heading: "Differentials", headingLevel: 1 },
{ path: "/applications", testId: "tools-home", heading: "Tools", headingLevel: 1 },
{ path: "/tools", testId: "tools-home", heading: "Tools", headingLevel: 1 },
] as const) {
await gotoLauncher(page, home.path);
await expect(page.getByTestId(home.testId)).toBeVisible();
Expand Down