Skip to content

Commit 141f3fa

Browse files
feat(friend): Workflows opens from the sidebar footer
The only way into Workflows was a row inside the Bots block, which shows only in the "sections" sidebar layout and only while expanded. The default layout is "rail", and a bots host with no bots had no entry at all. Workflows now has a footer item next to Kanban, shown whenever a bots host is connected, and the Bots block row is gone. FORK.md and the design doc point to the new place. Found in the integrated real-app pass; checked headlessly over CDP against a dev server of this branch: footer entry, one-press save, run with its gate, dark reload of the run page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 0a10e84 commit 141f3fa

6 files changed

Lines changed: 40 additions & 31 deletions

File tree

‎FORK.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ run view or by direct link.
365365

366366
## Using workflows
367367

368-
Open Workflows from the Bots block of the sidebar (web and desktop) or from the Workflows row of the
369-
Android Bots tab. It lists the bots host's workflows with their last run.
368+
Open Workflows from the sidebar footer, next to Kanban (web and desktop), or from the Workflows row
369+
of the Android Bots tab. It lists the bots host's workflows with their last run.
370370

371371
- **Create one.** "From template" copies a ready routine under a new name; "New workflow" starts
372372
blank. A new workflow starts turned off.

‎apps/web/src/bots/BotsSidebarSection.tsx‎

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ import {
2424
} from "@t3tools/contracts";
2525
import { useNavigate } from "@tanstack/react-router";
2626
import { Schema } from "effect";
27-
import { ChevronRightIcon, PlusIcon, WorkflowIcon } from "lucide-react";
27+
import { ChevronRightIcon, PlusIcon } from "lucide-react";
2828
import { useState, type ReactNode } from "react";
2929

3030
import { CollapsibleSectionHeader } from "../components/ui/collapsible-section-header";
31-
import { useSidebar } from "../components/ui/sidebar";
3231
import { useLocalStorage } from "../hooks/useLocalStorage";
3332
import { useNowMinute } from "../hooks/useNowMinute";
3433
import { useThreadActions } from "../hooks/useThreadActions";
@@ -727,33 +726,10 @@ export function BotsSidebarSection(props: {
727726
) : null}
728727
</DndContext>
729728
)}
730-
{expanded && environmentId !== null ? <WorkflowsRow environmentId={environmentId} /> : null}
731729
</section>
732730
);
733731
}
734732

735-
/** Opens the bots host's Workflows, where the workflow step threads live. */
736-
function WorkflowsRow(props: { environmentId: EnvironmentId }) {
737-
const navigate = useNavigate();
738-
const { isMobile, setOpenMobile } = useSidebar();
739-
return (
740-
<button
741-
type="button"
742-
onClick={() => {
743-
if (isMobile) setOpenMobile(false);
744-
void navigate({
745-
to: "/workflows/$environmentId",
746-
params: { environmentId: props.environmentId },
747-
});
748-
}}
749-
className="flex cursor-pointer items-center gap-1.5 px-2 py-1 text-2xs text-sidebar-muted-foreground hover:text-sidebar-foreground"
750-
>
751-
<WorkflowIcon className="size-3" />
752-
Workflows
753-
</button>
754-
);
755-
}
756-
757733
/** `bot:<id>`, `section:<id>` or `group:<id>` split into its kind and id. */
758734
function splitDragId(id: string): readonly [kind: string, id: string] {
759735
const colon = id.indexOf(":");
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useNavigate } from "@tanstack/react-router";
2+
import { WorkflowIcon } from "lucide-react";
3+
import type { ComponentType, ReactNode } from "react";
4+
5+
import { useSidebar } from "../../components/ui/sidebar";
6+
import { useBotsEnvironmentId } from "../../state/bots";
7+
8+
/**
9+
* The sidebar footer's Workflows button, after Kanban. Like Kanban it shows only while a bots host
10+
* is connected, so Workflows is reachable in every sidebar layout and with no bots yet.
11+
*/
12+
export function WorkflowsSidebarItem({
13+
Item,
14+
}: {
15+
readonly Item: ComponentType<{ icon: ReactNode; label: string; onClick: () => void }>;
16+
}) {
17+
const navigate = useNavigate();
18+
const { isMobile, setOpenMobile } = useSidebar();
19+
const environmentId = useBotsEnvironmentId();
20+
if (environmentId === null) return null;
21+
return (
22+
<Item
23+
icon={<WorkflowIcon />}
24+
label="Workflows"
25+
onClick={() => {
26+
if (isMobile) setOpenMobile(false);
27+
void navigate({ to: "/workflows/$environmentId", params: { environmentId } });
28+
}}
29+
/>
30+
);
31+
}

‎apps/web/src/components/sidebar/SidebarChrome.tsx‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ import { isSidebarUtilityPage, useNavigateToMainApp } from "./mainAppLocation";
3737
import { SidebarThreadUndoNotice } from "./SidebarThreadUndoNotice";
3838
import { SidebarProviderUpdatePill } from "./SidebarProviderUpdatePill";
3939
import { SidebarUpdateArchitectureWarning, SidebarUpdatePill } from "./SidebarUpdatePill";
40-
// Fork (friend): the fork Mac app's self-update notice and the kanban button.
40+
// Fork (friend): the fork Mac app's self-update notice and the kanban and workflows buttons.
4141
import { DesktopSelfUpdateNotice } from "../../bots/DesktopSelfUpdateNotice";
4242
import { KanbanSidebarItem } from "../../bots/kanban/KanbanSidebarItem";
43+
import { WorkflowsSidebarItem } from "../../bots/workflows/WorkflowsSidebarItem";
4344
import { PullRequestGlyph } from "~/components/pullRequest/pullRequestIcons";
4445
import { observeResize } from "~/lib/observeResize";
4546

@@ -281,8 +282,9 @@ const SidebarUtilityMenu = memo(function SidebarUtilityMenu() {
281282
onClick={handlePullRequestsClick}
282283
/>
283284
) : null}
284-
{/* Fork (friend): the bots host's kanban, next to pull requests. */}
285+
{/* Fork (friend): the bots host's kanban and workflows, next to pull requests. */}
285286
<KanbanSidebarItem Item={SidebarUtilityItem} />
287+
<WorkflowsSidebarItem Item={SidebarUtilityItem} />
286288
<SidebarUtilityItem
287289
icon={<ChartNoAxesColumnIcon />}
288290
label="Usage"

‎docs/friend/workflows-design.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2054,7 +2054,7 @@ Nove arquivos do upstream. Oito já são seams hoje (`scripts/friend/seams.ts`;
20542054
| `packages/shared/package.json` | sim, desde a fatia 1 (contains) | Export `./workflows` para `src/workflows/` (compilador, expressões, `classifyCommand`) | O AGENTS.md reserva `packages/contracts` para schemas; lógica de runtime compartilhada mora em `packages/shared`, que só expõe subpaths declarados |
20552055
| `evals/mcp-tool-use/run.ts` | **não, nova** (1) | Incluir os toolkits do fork no catálogo da eval (`:303`) | Sem isso, nenhuma ferramenta do fork tem eval, nem as de hoje |
20562056

2057-
Sem mudança em `runtimeLayer.ts`, `ws.ts`, `rpc.ts`, `RpcAuthorization.ts`, `ServerEnvironment.ts`, `GitWorkflowService`, nos adapters de provider, no `ProviderSessionManager` ou no `ThreadLaunchService`. Com os passos no host, saíram as mudanças que só existiam pelo container: o 403 do MCP para threads `wf:` no `McpHttpServer.ts:239`, o `isWorkflowLauncher` e as instâncias de workflow. O spread de `BOTS_RPCS`, os spreads de escopo e a capability `bots` já levam tudo. A entrada na barra lateral do web fica no `BotsSidebarSection`, que é do fork. Prefixos do fork em `FORK_OWNED_PREFIXES`: `packages/contracts/src/workflows.`, `packages/shared/src/workflows/` e `docs/friend/` (da fatia 1); `packages/client-runtime/src/workflows.` e `apps/web/src/routes/_chat.workflows` entram com as fatias 9 e 10.
2057+
Sem mudança em `runtimeLayer.ts`, `ws.ts`, `rpc.ts`, `RpcAuthorization.ts`, `ServerEnvironment.ts`, `GitWorkflowService`, nos adapters de provider, no `ProviderSessionManager` ou no `ThreadLaunchService`. Com os passos no host, saíram as mudanças que só existiam pelo container: o 403 do MCP para threads `wf:` no `McpHttpServer.ts:239`, o `isWorkflowLauncher` e as instâncias de workflow. O spread de `BOTS_RPCS`, os spreads de escopo e a capability `bots` já levam tudo. A entrada na barra lateral do web fica no rodapé, ao lado do Kanban (`WorkflowsSidebarItem`, do fork, pela seam já existente em `SidebarChrome.tsx`), para aparecer em todo layout e sem nenhum bot. Prefixos do fork em `FORK_OWNED_PREFIXES`: `packages/contracts/src/workflows.`, `packages/shared/src/workflows/` e `docs/friend/` (da fatia 1); `packages/client-runtime/src/workflows.` e `apps/web/src/routes/_chat.workflows` entram com as fatias 9 e 10.
20582058

20592059
---
20602060

‎scripts/friend/seams.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ export const SEAMS: readonly Seam[] = [
518518
{
519519
file: "apps/web/src/components/sidebar/SidebarChrome.tsx",
520520
markers: 3,
521-
why: "the Mac app's self-update notice and the kanban button in the sidebar footer",
521+
why: "the Mac app's self-update notice and the kanban and workflows buttons in the sidebar footer",
522522
},
523523
{
524524
file: "apps/web/src/components/sidebar/mainAppLocation.ts",

0 commit comments

Comments
 (0)