Files
kandev/apps/web/lib/links.ts
T
Jérémy Coatelen 538813de02 feat(web): add Threads view for live agent conversations (#3112)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
2026-09-03 08:07:16 +00:00

68 lines
2.5 KiB
TypeScript

export function linkToTask(taskId: string, layout?: string): string {
const base = `/t/${taskId}`;
return layout ? `${base}?layout=${encodeURIComponent(layout)}` : base;
}
export function linkToTaskOverview({
workspaceId,
workflowId,
}: {
workspaceId?: string;
workflowId?: string;
} = {}): string {
const params = new URLSearchParams({ home: "overview" });
if (workspaceId) params.set("workspaceId", workspaceId);
if (workflowId) params.set("workflowId", workflowId);
return `/?${params.toString()}`;
}
/**
* The Office home for a workspace. The one builder for this URL: the sidebar
* brand link, the Home row, and the topbar's home crumb render side by side,
* so their hrefs must be byte-identical for the same workspace.
*/
export function linkToOfficeHome({ workspaceId }: { workspaceId?: string } = {}): string {
if (!workspaceId) return "/office";
return `/office?${new URLSearchParams({ workspaceId }).toString()}`;
}
/** Task-detail route prefixes the SPA serves: canonical and compatibility. */
const TASK_DETAIL_PREFIXES = ["/t/", "/tasks/"];
export function normalizePathname(pathname: string): string {
return pathname.length > 1 && pathname.endsWith("/") ? pathname.slice(0, -1) : pathname;
}
/**
* True when `pathname` is a task-detail route for `taskId`. Matches both the
* canonical `/t/:id` and the compatibility `/tasks/:id` paths.
*/
export function isTaskDetailPath(pathname: string, taskId: string): boolean {
const normalized = normalizePathname(pathname);
return TASK_DETAIL_PREFIXES.some((prefix) => normalized === `${prefix}${taskId}`);
}
/** Replace the browser URL to reflect the active task (no navigation). */
export function replaceTaskUrl(taskId: string): void {
if (typeof window === "undefined") return;
window.history.replaceState({}, "", linkToTask(taskId));
}
export function linkToTasks(workspaceId?: string): string {
return workspaceId ? `/tasks?workspace=${workspaceId}` : "/tasks";
}
/**
* The Threads deck: every live agent conversation side by side. `taskId` asks
* the deck to scroll that task's column into view on arrival, which is how a
* task page hands a specific discussion back to the deck.
*/
export function linkToThreads(workspaceId?: string, taskId?: string, sessionId?: string): string {
const params = new URLSearchParams();
if (workspaceId) params.set("workspace", workspaceId);
if (taskId) params.set("taskId", taskId);
if (taskId && sessionId) params.set("sessionId", sessionId);
const query = params.toString();
return query ? `/threads?${query}` : "/threads";
}