Add configurable terminal profiles
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
BUILTIN_PROVIDER_ICON_NAMES,
|
||||
KNOWN_PROVIDER_ICON_NAMES,
|
||||
TERMINAL_PROFILE_ICON_NAMES,
|
||||
} from "@getpaseo/protocol/provider-icon-names";
|
||||
import { ACP_PROVIDER_CATALOG } from "@/data/acp-provider-catalog";
|
||||
import { resolveProviderIconName } from "./provider-icon-name";
|
||||
|
||||
describe("resolveProviderIconName", () => {
|
||||
@@ -10,9 +16,34 @@ describe("resolveProviderIconName", () => {
|
||||
|
||||
it("returns the catalog identifier for ACP catalog provider ids that ship an icon", () => {
|
||||
expect(resolveProviderIconName("amp-acp")).toEqual({ kind: "catalog", id: "amp-acp" });
|
||||
expect(resolveProviderIconName("gemini")).toEqual({ kind: "catalog", id: "gemini" });
|
||||
});
|
||||
|
||||
it("falls back to the bot icon for unknown custom providers", () => {
|
||||
expect(resolveProviderIconName("custom-claude-profile")).toEqual({ kind: "bot" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("known provider icon names", () => {
|
||||
it("includes every ACP catalog entry that ships an icon", () => {
|
||||
const known = new Set(KNOWN_PROVIDER_ICON_NAMES);
|
||||
for (const entry of ACP_PROVIDER_CATALOG) {
|
||||
if (entry.iconSvg) {
|
||||
expect(known).toContain(entry.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("only lists ACP icon ids that have a catalog entry with an icon", () => {
|
||||
const builtin = new Set(BUILTIN_PROVIDER_ICON_NAMES);
|
||||
const terminalOnly = new Set(TERMINAL_PROFILE_ICON_NAMES);
|
||||
const catalogIdsWithIcons = new Set(
|
||||
ACP_PROVIDER_CATALOG.filter((entry) => entry.iconSvg).map((entry) => entry.id),
|
||||
);
|
||||
for (const name of KNOWN_PROVIDER_ICON_NAMES) {
|
||||
if (!builtin.has(name) && !terminalOnly.has(name)) {
|
||||
expect(catalogIdsWithIcons).toContain(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
import { ACP_PROVIDER_CATALOG } from "@/data/acp-provider-catalog";
|
||||
|
||||
export type BuiltinProviderIconName =
|
||||
| "claude"
|
||||
| "codex"
|
||||
| "copilot"
|
||||
| "kiro"
|
||||
| "omp"
|
||||
| "opencode"
|
||||
| "pi";
|
||||
import {
|
||||
BUILTIN_PROVIDER_ICON_NAMES,
|
||||
KNOWN_PROVIDER_ICON_NAMES,
|
||||
} from "@getpaseo/protocol/provider-icon-names";
|
||||
|
||||
export type ProviderIconName =
|
||||
| { kind: "builtin"; id: BuiltinProviderIconName }
|
||||
| { kind: "builtin"; id: string }
|
||||
| { kind: "catalog"; id: string }
|
||||
| { kind: "bot" };
|
||||
|
||||
const BUILTIN_PROVIDER_IDS: ReadonlySet<BuiltinProviderIconName> = new Set([
|
||||
"claude",
|
||||
"codex",
|
||||
"copilot",
|
||||
"kiro",
|
||||
"omp",
|
||||
"opencode",
|
||||
"pi",
|
||||
]);
|
||||
|
||||
const CATALOG_ICON_PROVIDER_IDS: ReadonlySet<string> = new Set(
|
||||
ACP_PROVIDER_CATALOG.flatMap((entry) => (entry.iconSvg ? [entry.id] : [])),
|
||||
);
|
||||
const BUILTIN_PROVIDER_IDS = new Set(BUILTIN_PROVIDER_ICON_NAMES);
|
||||
const KNOWN_PROVIDER_IDS = new Set(KNOWN_PROVIDER_ICON_NAMES);
|
||||
|
||||
export function resolveProviderIconName(provider: string): ProviderIconName {
|
||||
if (BUILTIN_PROVIDER_IDS.has(provider as BuiltinProviderIconName)) {
|
||||
return { kind: "builtin", id: provider as BuiltinProviderIconName };
|
||||
if (BUILTIN_PROVIDER_IDS.has(provider)) {
|
||||
return { kind: "builtin", id: provider };
|
||||
}
|
||||
if (CATALOG_ICON_PROVIDER_IDS.has(provider)) {
|
||||
if (KNOWN_PROVIDER_IDS.has(provider)) {
|
||||
return { kind: "catalog", id: provider };
|
||||
}
|
||||
return { kind: "bot" };
|
||||
|
||||
@@ -8,10 +8,7 @@ import { OpenCodeIcon } from "@/components/icons/opencode-icon";
|
||||
import { OmpIcon } from "@/components/icons/omp-icon";
|
||||
import { PiIcon } from "@/components/icons/pi-icon";
|
||||
import { ACP_PROVIDER_CATALOG } from "@/data/acp-provider-catalog";
|
||||
import {
|
||||
resolveProviderIconName,
|
||||
type BuiltinProviderIconName,
|
||||
} from "@/components/provider-icon-name";
|
||||
import { resolveProviderIconName } from "@/components/provider-icon-name";
|
||||
|
||||
export interface ProviderIconProps {
|
||||
size: number;
|
||||
@@ -20,7 +17,7 @@ export interface ProviderIconProps {
|
||||
|
||||
export type ProviderIconComponent = ComponentType<ProviderIconProps>;
|
||||
|
||||
const BUILTIN_PROVIDER_ICONS: Record<BuiltinProviderIconName, ProviderIconComponent> = {
|
||||
const BUILTIN_PROVIDER_ICONS: Record<string, ProviderIconComponent> = {
|
||||
claude: ClaudeIcon as unknown as ProviderIconComponent,
|
||||
codex: CodexIcon as unknown as ProviderIconComponent,
|
||||
copilot: CopilotIcon as unknown as ProviderIconComponent,
|
||||
@@ -53,7 +50,10 @@ function getCatalogProviderIcon(provider: string): ProviderIconComponent {
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const iconSvg = CATALOG_ICON_SVGS.get(provider) ?? "";
|
||||
const iconSvg = CATALOG_ICON_SVGS.get(provider);
|
||||
if (!iconSvg) {
|
||||
return Bot;
|
||||
}
|
||||
const icon = createCatalogIcon(provider, iconSvg);
|
||||
catalogIconComponents.set(provider, icon);
|
||||
return icon;
|
||||
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
WorkspaceDesktopTabsRow,
|
||||
type WorkspaceDesktopTabRowItem,
|
||||
} from "@/screens/workspace/workspace-desktop-tabs-row";
|
||||
import type { TerminalProfileInput } from "@/screens/workspace/terminals/use-workspace-terminals";
|
||||
import {
|
||||
WorkspaceTabPresentationResolver,
|
||||
WorkspaceTabIcon,
|
||||
@@ -92,7 +93,7 @@ interface SplitContainerProps {
|
||||
onCloseTabsToRight: (tabId: string, paneTabs: WorkspaceTabDescriptor[]) => Promise<void> | void;
|
||||
onCloseOtherTabs: (tabId: string, paneTabs: WorkspaceTabDescriptor[]) => Promise<void> | void;
|
||||
onCreateDraftTab: (input: { paneId?: string }) => void;
|
||||
onCreateTerminalTab: (input: { paneId?: string }) => void;
|
||||
onCreateTerminalTab: (input: { paneId?: string; profile?: TerminalProfileInput }) => void;
|
||||
onCreateBrowserTab: (input: { paneId?: string }) => void;
|
||||
showCreateBrowserTab?: boolean;
|
||||
buildPaneContentModel: (input: {
|
||||
|
||||
@@ -901,8 +901,6 @@ const styles = StyleSheet.create((theme) => ({
|
||||
labelText: {
|
||||
fontSize: theme.fontSize.xs,
|
||||
color: theme.colors.foregroundMuted,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 0.6,
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
|
||||
Reference in New Issue
Block a user