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
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,37 @@ const customNameTarget: EnvironmentRenameDialogTarget = {
canClearName: true,
};

export function BranchContext() {
const inputRef = useRef<HTMLInputElement | null>(null);
return (
<StoryCard>
<StoryRow
label="branch context"
hint="current branch beneath the custom worktree name"
>
<DialogStage>
<EnvironmentRenameDialogContent
target={{
id: "env_named",
currentName: "Design system polish",
branchName: "bb/design-system-polish",
canClearName: true,
}}
pending={false}
onRename={noop}
inputRef={inputRef}
/>
</DialogStage>
</StoryRow>
</StoryCard>
);
}

export function Overview() {
const inputRef = useRef<HTMLInputElement | null>(null);
return (
<StoryCard>
<StoryRow label="branch placeholder" hint="unnamed environment">
<StoryRow label="branch placeholder" hint="unnamed worktree">
<DialogStage>
<EnvironmentRenameDialogContent
target={unnamedTarget}
Expand Down Expand Up @@ -65,7 +91,7 @@ export function Overview() {
<EnvironmentRenameDialogContent
target={customNameTarget}
pending={false}
errorMessage="Environment name must be 80 characters or fewer."
errorMessage="Worktree name must be 80 characters or fewer."
onRename={noop}
inputRef={inputRef}
/>
Expand Down
15 changes: 11 additions & 4 deletions apps/app/src/components/dialogs/EnvironmentRenameDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const ENVIRONMENT_NAME_MAX_LENGTH = 80;

const ENVIRONMENT_NAME_LENGTH_RULE = {
limit: ENVIRONMENT_NAME_MAX_LENGTH,
message: `Environment name must be ${ENVIRONMENT_NAME_MAX_LENGTH} characters or fewer.`,
message: `Worktree name must be ${ENVIRONMENT_NAME_MAX_LENGTH} characters or fewer.`,
};

export interface EnvironmentRenameDialogTarget {
Expand Down Expand Up @@ -65,17 +65,24 @@ export function EnvironmentRenameDialogContent({
}: EnvironmentRenameDialogContentProps) {
return (
<RenameDialogContent
entityLabel="environment"
entityLabel="worktree"
initialName={target.currentName}
pending={pending}
errorMessage={errorMessage}
placeholder={target.branchName ?? "Environment name"}
placeholder={target.branchName ?? "Worktree name"}
inputDetails={
target.canClearName && target.branchName ? (
<p className="truncate text-xs text-muted-foreground">
Branch: <span className="font-mono">{target.branchName}</span>
</p>
) : undefined
}
maxLength={ENVIRONMENT_NAME_LENGTH_RULE}
autoCapitalize="sentences"
clearAction={
target.canClearName
? {
label: "Use branch name",
label: "Clear custom name",
onClear: () => onRename(target.id, null),
}
: undefined
Expand Down
3 changes: 3 additions & 0 deletions apps/app/src/components/dialogs/RenameDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ interface RenameDialogContentProps {
pending: boolean;
errorMessage?: string | null;
placeholder?: string;
inputDetails?: ReactNode;
maxLength?: { limit: number; message: string };
autoCapitalize: "words" | "sentences";
compact?: boolean;
Expand All @@ -65,6 +66,7 @@ export function RenameDialogContent({
pending,
errorMessage,
placeholder,
inputDetails,
maxLength,
autoCapitalize,
compact = false,
Expand Down Expand Up @@ -119,6 +121,7 @@ export function RenameDialogContent({
clearMessage();
}}
/>
{inputDetails}
{displayedErrorMessage ? (
<p className="text-sm text-destructive">{displayedErrorMessage}</p>
) : null}
Expand Down
1 change: 1 addition & 0 deletions apps/app/src/components/plugin/PluginThreadChat.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ vi.mock("@/lib/sdk", () => ({
}));

vi.mock("@/hooks/useRealtimeSubscription", () => ({
useHostListRealtimeSubscription: vi.fn(),
useThreadDetailRealtimeSubscription: vi.fn(),
useThreadListRealtimeSubscription: vi.fn(),
useEnvironmentDetailRealtimeSubscription: vi.fn(),
Expand Down
34 changes: 21 additions & 13 deletions apps/app/src/components/plugin/PluginThreadChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import { useThreadTimelineNavigation } from "@/components/thread/timeline/Thread
import { PluginContext } from "@/components/plugin/plugin-context";
import { ThreadProviderContext } from "@/components/thread/thread-provider-context";
import { useEnvironment } from "@/hooks/queries/environment-queries";
import { useHosts } from "@/hooks/queries/host-queries";
import { useSystemProviderInfo } from "@/hooks/queries/system-queries";
import { useThread } from "@/hooks/queries/thread-queries";
import { useHostDaemon } from "@/hooks/useHostDaemon";
import { getEnvironmentWorkspaceLabelIconName } from "@/lib/environment-workspace-display";
import {
getEnvironmentWorkspaceSummaryDisplay,
} from "@/lib/environment-workspace-display";
import { formatWorkspaceCheckoutDisplay } from "@/lib/workspace-checkout-display";
import { BbHttpError } from "@/lib/sdk";
import {
Expand Down Expand Up @@ -107,6 +110,11 @@ function PluginThreadChatBody({
const { isLocalDaemonHost } = useHostDaemon();
const environmentQuery = useEnvironment(thread?.environmentId ?? null);
const environment = environmentQuery.data ?? null;
const hostsQuery = useHosts({ enabled: environment !== null });
const environmentHostName = environment
? (hostsQuery.data?.find((host) => host.id === environment.hostId)?.name ??
null)
: null;
const timelineNavigation = useThreadTimelineNavigation();
const canUseHostFileNavigation =
thread !== undefined &&
Expand Down Expand Up @@ -171,25 +179,25 @@ function PluginThreadChatBody({

const environmentSummary = useMemo(() => {
if (environment === null) {
return (
<ThreadEnvironmentSummary
environmentLabel="Working locally"
environmentCompactLabel="Local"
/>
);
return null;
}
const host: EnvironmentDisplayHostContext = {
locality: isLocalDaemonHost(environment.hostId) ? "local" : "remote",
identity: null,
};
const display = formatEnvironmentDisplay({ environment, host });
const summaryDisplay = getEnvironmentWorkspaceSummaryDisplay({
display,
environmentName: environment.name,
locality: host.locality,
hostName: environmentHostName ?? undefined,
});
return (
<ThreadEnvironmentSummary
environmentLabel={display.modeLabel}
environmentCompactLabel={display.compactModeLabel}
environmentIcon={getEnvironmentWorkspaceLabelIconName(
display.workspaceDisplayKind,
)}
environmentLabel={summaryDisplay.label}
environmentCompactLabel={summaryDisplay.compactLabel}
environmentIcon={summaryDisplay.icon}
environmentTypeLabel={summaryDisplay.typeLabel}
environmentCheckout={
environment.branchName
? formatWorkspaceCheckoutDisplay({
Expand All @@ -203,7 +211,7 @@ function PluginThreadChatBody({
}
/>
);
}, [environment, isLocalDaemonHost]);
}, [environment, environmentHostName, isLocalDaemonHost]);

const isThreadMissing =
threadQuery.error instanceof BbHttpError &&
Expand Down
Loading
Loading