Files
paseo/packages/app/src/workspace-pins/launch.tsx
T
3e8dce7d7c Hide browser shortcuts outside the desktop app (#2116)
* fix: hide browser pin on non-Electron web

Browser is desktop-only, but the pinned shortcut bar still rendered a
New browser pin on web where createBrowser is a silent no-op.

Skip browser pins in usePinnedLaunchers when not Electron, and drop
browser from default pinned targets so new users only get terminal.

* fix(app): preserve browser pin defaults on desktop

Keep platform availability in the pinned-target policy so regular web hides browser shortcuts without changing Electron defaults.

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-16 12:36:20 +00:00

116 lines
3.6 KiB
TypeScript

import { useMemo, type ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { Globe, SquarePen, SquareTerminal } from "lucide-react-native";
import { withUnistyles } from "react-native-unistyles";
import {
getTerminalProfileIcon,
resolveTerminalProfiles,
} from "@getpaseo/protocol/terminal-profiles";
import { getProviderIcon } from "@/components/provider-icons";
import { getIsElectron } from "@/constants/platform";
import { useDaemonConfig } from "@/hooks/use-daemon-config";
import type { Theme } from "@/styles/theme";
import {
isPinnedTargetAvailable,
pinnedTargetKey,
type PinnedTabTarget,
} from "@/workspace-pins/target";
import { usePinnedTargetsStore } from "@/workspace-pins/store";
export interface ResolvedPin {
key: string;
label: string;
icon: ReactElement;
onPress: () => void;
}
interface UsePinnedLaunchersInput {
serverId: string;
onLaunch: (target: PinnedTabTarget) => void;
}
const mutedColorMapping = (theme: Theme) => ({ color: theme.colors.foregroundMuted });
const ThemedSquarePen = withUnistyles(SquarePen);
const ThemedSquareTerminal = withUnistyles(SquareTerminal);
const ThemedGlobe = withUnistyles(Globe);
function ProviderPinIcon({
iconKey,
size,
color = "",
}: {
iconKey: string;
size: number;
color?: string;
}) {
const Icon = getProviderIcon(iconKey);
return <Icon size={size} color={color} />;
}
const ThemedProviderPinIcon = withUnistyles(ProviderPinIcon);
export function ProfileIcon({ iconKey }: { iconKey: string | undefined }): ReactElement {
if (!iconKey) {
return <ThemedSquareTerminal size={14} uniProps={mutedColorMapping} />;
}
return <ThemedProviderPinIcon iconKey={iconKey} size={14} uniProps={mutedColorMapping} />;
}
export function usePinnedLaunchers({ serverId, onLaunch }: UsePinnedLaunchersInput): ResolvedPin[] {
const { t } = useTranslation();
const pinned = usePinnedTargetsStore((state) => state.pinned);
const { config } = useDaemonConfig(serverId);
const profiles = useMemo(
() => resolveTerminalProfiles(config?.terminalProfiles),
[config?.terminalProfiles],
);
return useMemo(() => {
const resolved: ResolvedPin[] = [];
for (const target of pinned) {
if (!isPinnedTargetAvailable(target, { isElectron: getIsElectron() })) {
continue;
}
if (target.kind === "draft") {
resolved.push({
key: pinnedTargetKey(target),
label: t("workspace.tabs.actions.newAgent"),
icon: <ThemedSquarePen size={14} uniProps={mutedColorMapping} />,
onPress: () => onLaunch(target),
});
continue;
}
if (target.kind === "terminal") {
resolved.push({
key: pinnedTargetKey(target),
label: t("workspace.tabs.actions.newTerminal"),
icon: <ThemedSquareTerminal size={14} uniProps={mutedColorMapping} />,
onPress: () => onLaunch(target),
});
continue;
}
if (target.kind === "browser") {
resolved.push({
key: pinnedTargetKey(target),
label: t("workspace.tabs.actions.newBrowser"),
icon: <ThemedGlobe size={14} uniProps={mutedColorMapping} />,
onPress: () => onLaunch(target),
});
continue;
}
const profile = profiles.find((entry) => entry.id === target.profileId);
if (!profile) {
continue;
}
resolved.push({
key: pinnedTargetKey(target),
label: profile.name,
icon: <ProfileIcon iconKey={getTerminalProfileIcon(profile)} />,
onPress: () => onLaunch(target),
});
}
return resolved;
}, [onLaunch, pinned, profiles, t]);
}