Skip to content
Draft
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
20 changes: 14 additions & 6 deletions src/components/shared/SubgraphBreadcrumbsView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Home } from "lucide-react";
import { Fragment } from "react";
import { Fragment, type ReactNode } from "react";

import {
Breadcrumb,
Expand All @@ -11,15 +11,18 @@ import {
} from "@/components/ui/breadcrumb";
import { Button } from "@/components/ui/button";
import { InlineStack } from "@/components/ui/layout";
import { pluralize } from "@/utils/string";

interface SubgraphBreadcrumbsViewProps {
path: string[];
onNavigate: (index: number) => void;
actions?: ReactNode;
}

export const SubgraphBreadcrumbsView = ({
path,
onNavigate,
actions,
}: SubgraphBreadcrumbsViewProps) => {
if (path.length <= 1) {
return null;
Expand All @@ -28,10 +31,12 @@ export const SubgraphBreadcrumbsView = ({
return (
<InlineStack
align="space-between"
gap="0"
blockAlign="start"
wrap="nowrap"
gap="2"
className="px-4 py-2 bg-gray-50 border-b w-full z-1"
>
<Breadcrumb>
<Breadcrumb className="flex-1 min-w-0">
<BreadcrumbList>
Comment thread
camielvs marked this conversation as resolved.
{path.map((pathSegment, index) => {
const isLast = index === path.length - 1;
Expand Down Expand Up @@ -78,9 +83,12 @@ export const SubgraphBreadcrumbsView = ({
</BreadcrumbList>
</Breadcrumb>

<div className="text-xs text-gray-500">
{path.length - 1} level{path.length - 1 !== 1 ? "s" : ""} deep
</div>
<InlineStack gap="2" blockAlign="center" className="shrink-0">
<div className="text-xs text-gray-500">
{path.length - 1} {pluralize(path.length - 1, "level")} deep
</div>
{actions}
</InlineStack>
</InlineStack>
);
};
18 changes: 15 additions & 3 deletions src/routes/v2/pages/Editor/hooks/usePipelineDetailsWindow.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
import { reaction } from "mobx";
import { useEffect } from "react";

import { PipelineDetailsContent } from "@/routes/v2/pages/Editor/components/PipelineDetailsContent/PipelineDetailsContent";
import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext";

const PIPELINE_DETAILS_WINDOW_ID = "pipeline-details";
const ROOT_TITLE = "Pipeline Details";
const SUBGRAPH_TITLE = "Subgraph Details";

export function usePipelineDetailsWindow() {
const { windows } = useSharedStores();
const { windows, navigation } = useSharedStores();
useEffect(() => {
if (!windows.getWindowById(PIPELINE_DETAILS_WINDOW_ID)) {
windows.openWindow(<PipelineDetailsContent />, {
id: PIPELINE_DETAILS_WINDOW_ID,
title: "Pipeline Details",
title: ROOT_TITLE,
position: { x: 0, y: 460 },
size: { width: 280, height: 350 },
disabledActions: ["close"],
persisted: true,
defaultDockState: "right",
});
}
}, [windows]);

return reaction(
() => navigation.navigationDepth > 0,
(isNested) => {
const win = windows.getWindowById(PIPELINE_DETAILS_WINDOW_ID);
win?.setTitle(isNested ? SUBGRAPH_TITLE : ROOT_TITLE);
},
{ fireImmediately: true },
);
}, [windows, navigation]);
}
100 changes: 100 additions & 0 deletions src/routes/v2/shared/components/SubgraphActionsMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { observer } from "mobx-react-lite";
import { useState } from "react";

import { CodeViewer } from "@/components/shared/CodeViewer";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Icon } from "@/components/ui/icon";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import useToastNotification from "@/hooks/useToastNotification";
import { serializeComponentSpecToYaml } from "@/models/componentSpec";
import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext";
import { downloadYamlFromComponentText } from "@/utils/URL";

export const SubgraphActionsMenu = observer(function SubgraphActionsMenu() {
const { navigation } = useSharedStores();
const notify = useToastNotification();
const [showCodeViewer, setShowCodeViewer] = useState(false);

const spec = navigation.activeSpec;

if (!spec || navigation.navigationDepth === 0) {
return null;
}

const subgraphName = spec.name || "subgraph";

const handleViewYaml = () => setShowCodeViewer(true);

const handleDownloadYaml = () => {
downloadYamlFromComponentText(
serializeComponentSpecToYaml(spec),
subgraphName,
);
};

const handleCopyYaml = () => {
navigator.clipboard.writeText(serializeComponentSpecToYaml(spec)).then(
() => notify("YAML copied to clipboard", "success"),
(err) => notify("Failed to copy YAML: " + err, "error"),
);
};

return (
<>
<DropdownMenu>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="min"
aria-label="Subgraph actions"
data-testid="subgraph-actions-menu-trigger"
>
<Icon name="EllipsisVertical" size="sm" />
</Button>
</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent>Subgraph actions</TooltipContent>
</Tooltip>

<DropdownMenuContent align="end">
<DropdownMenuItem onClick={handleViewYaml}>
<Icon name="FileCode" size="sm" />
View YAML
</DropdownMenuItem>

<DropdownMenuItem onClick={handleDownloadYaml}>
<Icon name="Download" size="sm" />
Download YAML
</DropdownMenuItem>

<DropdownMenuItem onClick={handleCopyYaml}>
<Icon name="Clipboard" size="sm" />
Copy YAML
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

{showCodeViewer && (
<CodeViewer
code={serializeComponentSpecToYaml(spec)}
language="yaml"
filename={subgraphName}
fullscreen
onClose={() => setShowCodeViewer(false)}
/>
)}
</>
);
});
10 changes: 9 additions & 1 deletion src/routes/v2/shared/components/SubgraphBreadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { observer } from "mobx-react-lite";
import { SubgraphBreadcrumbsView } from "@/components/shared/SubgraphBreadcrumbsView";
import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext";

import { SubgraphActionsMenu } from "./SubgraphActionsMenu";

export const SubgraphBreadcrumbs = observer(function SubgraphBreadcrumbs() {
const { navigation } = useSharedStores();

Expand All @@ -14,5 +16,11 @@ export const SubgraphBreadcrumbs = observer(function SubgraphBreadcrumbs() {
navigation.navigateToLevel(index);
};

return <SubgraphBreadcrumbsView path={path} onNavigate={handleNavigate} />;
return (
<SubgraphBreadcrumbsView
path={path}
onNavigate={handleNavigate}
actions={<SubgraphActionsMenu />}
/>
);
});
4 changes: 4 additions & 0 deletions src/routes/v2/shared/windows/windowModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ export class WindowModel {
this.store.bringToFront(this.id);
}

@action setTitle(title: string): void {
this.title = title;
}

@action updatePosition(pos: Position): void {
this.position = pos;
}
Expand Down
Loading