authorgravatar for 97427849+flamboh@users.noreply.github.comoliver <97427849+flamboh@users.noreply.github.com> 2026-10-07 23:04:09-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-08 03:04:09-03:00
logff9eb8bd0c8e71f98969a58d5789889e07b57c8b
treedfb5d97fc05eb3f405ece7c3c9a6497ea424231a
parent12865b4a73c23bb402717d5f592dcd954ed196e5
signature Signed by PGP key B5690EEEBB952194

feat(web): projectless threads show their machine in the sidebar (#17022)


1 files changed, 30 insertions(+), 1 deletions(-)

apps/web/src/components/Sidebar.tsx+30-1
...@@ -169,6 +169,7 @@ import {...@@ -169,6 +169,7 @@ import {
169} from "../threadRoutes";169} from "../threadRoutes";
170import { formatRelativeTimeLabel, parseTimestampDate } from "../timestampFormat";170import { formatRelativeTimeLabel, parseTimestampDate } from "../timestampFormat";
171import type { SidebarThreadSummary } from "../types";171import type { SidebarThreadSummary } from "../types";
172import { isScratchProject } from "@t3tools/client-runtime/state/projects";
172import type { EnvironmentProject } from "@t3tools/client-runtime/state/shell";173import type { EnvironmentProject } from "@t3tools/client-runtime/state/shell";
173import { cn } from "~/lib/utils";174import { cn } from "~/lib/utils";
174import { EnvironmentMachineIcon } from "./EnvironmentMachineIcon";175import { EnvironmentMachineIcon } from "./EnvironmentMachineIcon";
...@@ -1141,6 +1142,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1141,6 +1142,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1141 currentEnvironmentId: string | null;1142 currentEnvironmentId: string | null;
1142 environmentLabel: string | null;1143 environmentLabel: string | null;
1143 environmentMachine: EnvironmentMachineKind;1144 environmentMachine: EnvironmentMachineKind;
1145 scratchMachineLabel: string | null;
1144 project: EnvironmentProject | null;1146 project: EnvironmentProject | null;
1145 projectDisplayName: string | null;1147 projectDisplayName: string | null;
1146 providerEntryByInstanceId: ReadonlyMap<string, ProviderInstanceEntry>;1148 providerEntryByInstanceId: ReadonlyMap<string, ProviderInstanceEntry>;
...@@ -1370,6 +1372,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1370,6 +1372,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1370 // that is every thread, which is the point: the glyph is what tells rows on1372 // that is every thread, which is the point: the glyph is what tells rows on
1371 // different machines apart.1373 // different machines apart.
1372 const isRemote = thread.environmentId !== props.currentEnvironmentId;1374 const isRemote = thread.environmentId !== props.currentEnvironmentId;
1375 const showsScratchMachine = !thread.branch && props.scratchMachineLabel !== null;
13731376
1374 const detailsTooltip = (1377 const detailsTooltip = (
1375 <SidebarThreadTooltip1378 <SidebarThreadTooltip
...@@ -2164,6 +2167,17 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -2164,6 +2167,17 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
2164 <MiddleTruncate value={thread.branch} showTitle={false} />2167 <MiddleTruncate value={thread.branch} showTitle={false} />
2165 </span>2168 </span>
2166 </>2169 </>
2170 ) : showsScratchMachine ? (
2171 <>
2172 <EnvironmentMachineIcon
2173 aria-hidden
2174 kind={props.environmentMachine}
2175 className="size-3 shrink-0 text-muted-foreground/40"
2176 />
2177 <span className="min-w-0 flex-1 truncate text-muted-foreground/40">
2178 {props.scratchMachineLabel}
2179 </span>
2180 </>
2167 ) : (2181 ) : (
2168 <span className="flex-1" />2182 <span className="flex-1" />
2169 )}2183 )}
...@@ -2179,7 +2193,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -2179,7 +2193,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
2179 aria-hidden2193 aria-hidden
2180 className="pointer-events-none ml-auto inline-flex shrink-0 items-center gap-1"2194 className="pointer-events-none ml-auto inline-flex shrink-0 items-center gap-1"
2181 >2195 >
2182 {isRemote ? (2196 {isRemote && !showsScratchMachine ? (
2183 <span className="inline-flex shrink-0 items-center text-sidebar-muted-foreground/70">2197 <span className="inline-flex shrink-0 items-center text-sidebar-muted-foreground/70">
2184 <EnvironmentMachineIcon2198 <EnvironmentMachineIcon
2185 aria-hidden2199 aria-hidden
...@@ -2595,6 +2609,20 @@ export default function Sidebar() {...@@ -2595,6 +2609,20 @@ export default function Sidebar() {
2595 () => projectGroupsSpanEnvironments(projectGroups),2609 () => projectGroupsSpanEnvironments(projectGroups),
2596 [projectGroups],2610 [projectGroups],
2597 );2611 );
2612 const scratchMachineLabelFor = useCallback(
2613 (thread: Pick<SidebarThreadSummary, "environmentId" | "projectId">) => {
2614 if (!showProjectEnvironments) return null;
2615 const project = projectByKey.get(`${thread.environmentId}:${thread.projectId}`);
2616 if (
2617 !project ||
2618 !isScratchProject(project, serverConfigs.get(thread.environmentId)?.scratchWorkspaceRoot)
2619 ) {
2620 return null;
2621 }
2622 return environmentLabelById.get(thread.environmentId) ?? null;
2623 },
2624 [environmentLabelById, projectByKey, serverConfigs, showProjectEnvironments],
2625 );
2598 const projectGroupByScopeKey = useMemo(2626 const projectGroupByScopeKey = useMemo(
2599 () => new Map(projectGroups.map((project) => [project.projectKey, project] as const)),2627 () => new Map(projectGroups.map((project) => [project.projectKey, project] as const)),
2600 [projectGroups],2628 [projectGroups],
...@@ -5299,6 +5327,7 @@ export default function Sidebar() {...@@ -5299,6 +5327,7 @@ export default function Sidebar() {
5299 environmentMachine={5327 environmentMachine={
5300 environmentMachineById.get(thread.environmentId) ?? "server"5328 environmentMachineById.get(thread.environmentId) ?? "server"
5301 }5329 }
5330 scratchMachineLabel={scratchMachineLabelFor(thread)}
5302 project={5331 project={
5303 projectByKey.get(`${thread.environmentId}:${thread.projectId}`) ??5332 projectByKey.get(`${thread.environmentId}:${thread.projectId}`) ??
5304 null5333 null