Remove pinned launchers from workspace rows
This commit is contained in:
@@ -19,10 +19,6 @@ export function tabRowPin(page: Page, target: PinnedTabTarget) {
|
|||||||
return page.getByTestId(`workspace-pinned-target-${pinnedTargetKey(target)}`);
|
return page.getByTestId(`workspace-pinned-target-${pinnedTargetKey(target)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sidebarPin(page: Page, target: PinnedTabTarget) {
|
|
||||||
return page.getByTestId(`sidebar-pinned-target-${pinnedTargetKey(target)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function openNewTabMenu(page: Page): Promise<void> {
|
export async function openNewTabMenu(page: Page): Promise<void> {
|
||||||
const trigger = page
|
const trigger = page
|
||||||
.getByTestId("workspace-new-tab-menu-trigger")
|
.getByTestId("workspace-new-tab-menu-trigger")
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { test, expect } from "./fixtures";
|
import { test, expect } from "./fixtures";
|
||||||
import { gotoWorkspace } from "./helpers/launcher";
|
import { gotoWorkspace } from "./helpers/launcher";
|
||||||
import { gotoAppShell } from "./helpers/app";
|
|
||||||
import { getServerId } from "./helpers/server-id";
|
|
||||||
import { seedWorkspace, type SeededWorkspace } from "./helpers/seed-client";
|
import { seedWorkspace, type SeededWorkspace } from "./helpers/seed-client";
|
||||||
import { togglePinFromMenu, tabRowPin, sidebarPin } from "./helpers/pins";
|
import { togglePinFromMenu, tabRowPin } from "./helpers/pins";
|
||||||
import { expectTerminalTabOpen } from "./helpers/workspace-tabs";
|
import { expectTerminalTabOpen } from "./helpers/workspace-tabs";
|
||||||
import type { PinnedTabTarget } from "../src/workspace-pins/target";
|
import type { PinnedTabTarget } from "../src/workspace-pins/target";
|
||||||
|
|
||||||
@@ -45,23 +43,4 @@ test.describe("Pinned tab targets", () => {
|
|||||||
|
|
||||||
await expectTerminalTabOpen(page);
|
await expectTerminalTabOpen(page);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("the pinned button is mirrored in the sidebar workspace row and launches a terminal in that workspace", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
test.setTimeout(45_000);
|
|
||||||
await gotoWorkspace(page, workspace.workspaceId);
|
|
||||||
await togglePinFromMenu(page, TERMINAL_TARGET);
|
|
||||||
|
|
||||||
await gotoAppShell(page);
|
|
||||||
const row = page.getByTestId(`sidebar-workspace-row-${getServerId()}:${workspace.workspaceId}`);
|
|
||||||
await expect(row).toBeVisible({ timeout: 30_000 });
|
|
||||||
await row.hover();
|
|
||||||
|
|
||||||
await expect(sidebarPin(page, TERMINAL_TARGET)).toBeVisible({ timeout: 10_000 });
|
|
||||||
await sidebarPin(page, TERMINAL_TARGET).click();
|
|
||||||
|
|
||||||
await expect(page).toHaveURL(/\/workspace\//, { timeout: 30_000 });
|
|
||||||
await expectTerminalTabOpen(page);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ import {
|
|||||||
type SidebarWorkspaceEntry,
|
type SidebarWorkspaceEntry,
|
||||||
} from "@/hooks/use-sidebar-workspaces-list";
|
} from "@/hooks/use-sidebar-workspaces-list";
|
||||||
import { useSidebarOrderStore } from "@/stores/sidebar-order-store";
|
import { useSidebarOrderStore } from "@/stores/sidebar-order-store";
|
||||||
import { buildWorkspaceTabPersistenceKey } from "@/stores/workspace-tabs-store/state";
|
|
||||||
import { usePinnedLaunchers } from "@/workspace-pins/launch";
|
|
||||||
import { useLaunchIntentStore } from "@/workspace-pins/launch-intent-store";
|
|
||||||
import { PinnedTargetsRow } from "@/workspace-pins/pinned-targets-row";
|
|
||||||
import type { PinnedTabTarget } from "@/workspace-pins/target";
|
|
||||||
import { useShowShortcutBadges } from "@/hooks/use-show-shortcut-badges";
|
import { useShowShortcutBadges } from "@/hooks/use-show-shortcut-badges";
|
||||||
import { ContextMenuTrigger, useContextMenu } from "@/components/ui/context-menu";
|
import { ContextMenuTrigger, useContextMenu } from "@/components/ui/context-menu";
|
||||||
import {
|
import {
|
||||||
@@ -667,40 +662,16 @@ function WorkspaceRowRightGroup({
|
|||||||
onRename?: () => void;
|
onRename?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isMobileBreakpoint = useIsCompactFormFactor();
|
|
||||||
const showShortcut = showShortcutBadge && shortcutNumber !== null;
|
const showShortcut = showShortcutBadge && shortcutNumber !== null;
|
||||||
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
||||||
const showKebabInSlot = showKebab && !showShortcut;
|
const showKebabInSlot = showKebab && !showShortcut;
|
||||||
const shouldRenderActionSlot = Boolean(onArchive || workspace.diffStat);
|
const shouldRenderActionSlot = Boolean(onArchive || workspace.diffStat);
|
||||||
const showPinnedTargets = (isHovered || platformIsNative || isMobileBreakpoint) && !showShortcut;
|
|
||||||
|
|
||||||
const onLaunch = useCallback(
|
|
||||||
(target: PinnedTabTarget) => {
|
|
||||||
const workspaceKey = buildWorkspaceTabPersistenceKey({
|
|
||||||
serverId: workspace.serverId,
|
|
||||||
workspaceId: workspace.workspaceId,
|
|
||||||
});
|
|
||||||
if (!workspaceKey) return;
|
|
||||||
navigateToWorkspace(workspace.serverId, workspace.workspaceId);
|
|
||||||
useLaunchIntentStore.getState().request({ workspaceKey, target });
|
|
||||||
},
|
|
||||||
[workspace.serverId, workspace.workspaceId],
|
|
||||||
);
|
|
||||||
const launchers = usePinnedLaunchers({ serverId: workspace.serverId, onLaunch });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isCreating ? (
|
{isCreating ? (
|
||||||
<Text style={styles.workspaceCreatingText}>{t("sidebar.workspace.status.creating")}</Text>
|
<Text style={styles.workspaceCreatingText}>{t("sidebar.workspace.status.creating")}</Text>
|
||||||
) : null}
|
) : null}
|
||||||
{launchers.length > 0 ? (
|
|
||||||
<View
|
|
||||||
style={showPinnedTargets ? undefined : styles.pinnedTargetsHidden}
|
|
||||||
pointerEvents={showPinnedTargets ? "auto" : "none"}
|
|
||||||
>
|
|
||||||
<PinnedTargetsRow launchers={launchers} testIdPrefix="sidebar-pinned-target" />
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
{shouldRenderActionSlot ? (
|
{shouldRenderActionSlot ? (
|
||||||
<SidebarWorkspaceTrailingActionSlot>
|
<SidebarWorkspaceTrailingActionSlot>
|
||||||
<SidebarWorkspaceTrailingActionBase
|
<SidebarWorkspaceTrailingActionBase
|
||||||
@@ -2719,9 +2690,6 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
fontSize: theme.fontSize.xs,
|
fontSize: theme.fontSize.xs,
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
},
|
},
|
||||||
pinnedTargetsHidden: {
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
kebabButton: {
|
kebabButton: {
|
||||||
padding: 2,
|
padding: 2,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
|
|||||||
@@ -185,8 +185,6 @@ import {
|
|||||||
resolveTerminalProfiles,
|
resolveTerminalProfiles,
|
||||||
} from "@getpaseo/protocol/terminal-profiles";
|
} from "@getpaseo/protocol/terminal-profiles";
|
||||||
import { getProviderIcon } from "@/components/provider-icons";
|
import { getProviderIcon } from "@/components/provider-icons";
|
||||||
import { useLaunchIntentStore } from "@/workspace-pins/launch-intent-store";
|
|
||||||
import { runPinnedTabTarget, type TabTargetHandlers } from "@/workspace-pins/run";
|
|
||||||
import {
|
import {
|
||||||
createWorkspaceFileTabTarget,
|
createWorkspaceFileTabTarget,
|
||||||
normalizeWorkspaceFileLocation,
|
normalizeWorkspaceFileLocation,
|
||||||
@@ -1720,37 +1718,6 @@ function useWorkspaceCheckoutStatus(input: {
|
|||||||
return { checkoutQuery, isCheckoutStatusLoading };
|
return { checkoutQuery, isCheckoutStatusLoading };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PinnedTabLaunchConsumerInput {
|
|
||||||
serverId: string;
|
|
||||||
persistenceKey: string | null;
|
|
||||||
isRouteFocused: boolean;
|
|
||||||
handlers: TabTargetHandlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
function usePinnedTabLaunchConsumer({
|
|
||||||
serverId,
|
|
||||||
persistenceKey,
|
|
||||||
isRouteFocused,
|
|
||||||
handlers,
|
|
||||||
}: PinnedTabLaunchConsumerInput) {
|
|
||||||
const { config } = useDaemonConfig(serverId);
|
|
||||||
const profiles = useMemo(
|
|
||||||
() => resolveTerminalProfiles(config?.terminalProfiles),
|
|
||||||
[config?.terminalProfiles],
|
|
||||||
);
|
|
||||||
const pending = useLaunchIntentStore((state) => state.pending);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!persistenceKey || !isRouteFocused || pending?.workspaceKey !== persistenceKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const target = useLaunchIntentStore.getState().consume(persistenceKey);
|
|
||||||
if (target) {
|
|
||||||
runPinnedTabTarget(target, profiles, handlers);
|
|
||||||
}
|
|
||||||
}, [handlers, isRouteFocused, pending, persistenceKey, profiles]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function WorkspaceScreenContent({
|
function WorkspaceScreenContent({
|
||||||
serverId,
|
serverId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -2597,28 +2564,6 @@ function WorkspaceScreenContent({
|
|||||||
[openWorkspaceTabFocused, persistenceKey],
|
[openWorkspaceTabFocused, persistenceKey],
|
||||||
);
|
);
|
||||||
|
|
||||||
const pinnedTabHandlers = useMemo<TabTargetHandlers>(
|
|
||||||
() => ({
|
|
||||||
createDraft: handleCreateDraftTab,
|
|
||||||
createTerminal: handleCreateTerminal,
|
|
||||||
createBrowser: handleCreateBrowserTab,
|
|
||||||
createTerminalWithProfile: handleCreateTerminalWithProfile,
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
handleCreateBrowserTab,
|
|
||||||
handleCreateDraftTab,
|
|
||||||
handleCreateTerminal,
|
|
||||||
handleCreateTerminalWithProfile,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
usePinnedTabLaunchConsumer({
|
|
||||||
serverId: normalizedServerId,
|
|
||||||
persistenceKey,
|
|
||||||
isRouteFocused,
|
|
||||||
handlers: pinnedTabHandlers,
|
|
||||||
});
|
|
||||||
|
|
||||||
useDesktopBrowserNewTabRequests({
|
useDesktopBrowserNewTabRequests({
|
||||||
enabled: Boolean(persistenceKey),
|
enabled: Boolean(persistenceKey),
|
||||||
workspaceLayout,
|
workspaceLayout,
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { beforeEach, describe, expect, it } from "vitest";
|
|
||||||
import { useLaunchIntentStore } from "./launch-intent-store";
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
useLaunchIntentStore.setState({ pending: null });
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("launch intent store", () => {
|
|
||||||
it("returns the requested target when the workspace key matches", () => {
|
|
||||||
useLaunchIntentStore.getState().request({ workspaceKey: "ws-1", target: { kind: "terminal" } });
|
|
||||||
expect(useLaunchIntentStore.getState().consume("ws-1")).toEqual({ kind: "terminal" });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("clears the pending intent once consumed", () => {
|
|
||||||
useLaunchIntentStore.getState().request({ workspaceKey: "ws-1", target: { kind: "draft" } });
|
|
||||||
useLaunchIntentStore.getState().consume("ws-1");
|
|
||||||
expect(useLaunchIntentStore.getState().pending).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns null and keeps the intent when the workspace key does not match", () => {
|
|
||||||
useLaunchIntentStore.getState().request({ workspaceKey: "ws-1", target: { kind: "browser" } });
|
|
||||||
expect(useLaunchIntentStore.getState().consume("ws-2")).toBeNull();
|
|
||||||
expect(useLaunchIntentStore.getState().pending).toEqual({
|
|
||||||
workspaceKey: "ws-1",
|
|
||||||
target: { kind: "browser" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns null when there is no pending intent", () => {
|
|
||||||
expect(useLaunchIntentStore.getState().consume("ws-1")).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { create } from "zustand";
|
|
||||||
import type { PinnedTabTarget } from "@/workspace-pins/target";
|
|
||||||
|
|
||||||
export interface PendingTabLaunch {
|
|
||||||
workspaceKey: string;
|
|
||||||
target: PinnedTabTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LaunchIntentState {
|
|
||||||
pending: PendingTabLaunch | null;
|
|
||||||
request: (intent: PendingTabLaunch) => void;
|
|
||||||
consume: (workspaceKey: string) => PinnedTabTarget | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useLaunchIntentStore = create<LaunchIntentState>((set, get) => ({
|
|
||||||
pending: null,
|
|
||||||
request: (intent) => set({ pending: intent }),
|
|
||||||
consume: (workspaceKey) => {
|
|
||||||
const { pending } = get();
|
|
||||||
if (!pending || pending.workspaceKey !== workspaceKey) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
set({ pending: null });
|
|
||||||
return pending.target;
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
Reference in New Issue
Block a user