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
39 changes: 39 additions & 0 deletions src/components/shared/Buttons/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { type ReactNode } from "react";

import { Icon, type IconName } from "@/components/ui/icon";

import TooltipButton from "./TooltipButton";

type ActionButtonProps = {
label: string;
destructive?: boolean;
disabled?: boolean;
onClick: () => void;
className?: string;
} & (
| { icon: IconName; children?: never }
| { children: ReactNode; icon?: never }
);

export const ActionButton = ({
label,
destructive,
disabled,
onClick,
className,
icon,
children,
}: ActionButtonProps) => {
return (
<TooltipButton
data-testid={`action-${label}`}
variant={destructive ? "destructive" : "outline"}
tooltip={label}
onClick={onClick}
disabled={disabled}
className={className}
>
{children === undefined && icon ? <Icon name={icon} /> : children}
</TooltipButton>
);
};
2 changes: 1 addition & 1 deletion src/components/shared/Buttons/TooltipButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";

export interface TooltipButtonProps extends ButtonProps {
interface TooltipButtonProps extends ButtonProps {
tooltip: React.ReactNode;
tooltipSide?: "top" | "right" | "bottom" | "left";
tooltipAlign?: "start" | "center" | "end";
Expand Down
13 changes: 5 additions & 8 deletions src/components/shared/Buttons/ViewYamlButton.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useState } from "react";

import { Icon } from "@/components/ui/icon";
import type {
ComponentSpec,
HydratedComponentReference,
} from "@/utils/componentSpec";
import { getComponentName } from "@/utils/getComponentName";

import TaskImplementation from "../TaskDetails/Implementation";
import TooltipButton from "./TooltipButton";
import { ActionButton } from "./ActionButton";

type ViewYamlButtonProps =
| { componentRef: HydratedComponentReference; componentSpec?: never }
Expand All @@ -34,13 +33,11 @@ export const ViewYamlButton = ({

return (
<>
<TooltipButton
variant="outline"
tooltip="View YAML"
<ActionButton
label="View YAML"
icon="FileCodeCorner"
onClick={handleClick}
>
<Icon name="FileCodeCorner" />
</TooltipButton>
/>

{showCodeViewer && (
<TaskImplementation
Expand Down
3 changes: 1 addition & 2 deletions src/components/shared/ContextPanel/Blocks/ActionBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export type Action = {
| { content: ReactNode; icon?: never }
);

// Temporary: ReactNode included for backward compatibility with some existing buttons. In the long-term we should strive for only Action types.
export type ActionOrReactNode = Action | ReactNode;
type ActionOrReactNode = Action | ReactNode;

interface ActionBlockProps {
title?: string;
Expand Down
120 changes: 30 additions & 90 deletions src/components/shared/Dialogs/ComponentDetailsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import { useHydrateComponentReference } from "@/hooks/useHydrateComponentReferen
import type { ComponentReference } from "@/utils/componentSpec";

import InfoIconButton from "../Buttons/InfoIconButton";
import TooltipButton from "../Buttons/TooltipButton";
import { ComponentEditorDialog } from "../ComponentEditor/ComponentEditorDialog";
import { ComponentFavoriteToggle } from "../FavoriteComponentToggle";
import { InfoBox } from "../InfoBox";
import { PublishComponent } from "../ManageComponent/PublishComponent";
Expand All @@ -32,9 +30,7 @@ interface ComponentDetailsProps {
component: ComponentReference;
displayName: string;
trigger?: ReactNode;
actions?: ReactNode[];
onClose?: () => void;
onDelete?: () => void;
}

const ComponentDetailsDialogContentSkeleton = () => {
Expand Down Expand Up @@ -64,12 +60,7 @@ const ComponentDetailsDialogContentSkeleton = () => {
};

const ComponentDetailsDialogContent = withSuspenseWrapper(
({
component,
displayName,
actions = [],
onDelete,
}: ComponentDetailsProps) => {
({ component, displayName }: ComponentDetailsProps) => {
const remoteComponentLibrarySearchEnabled = useBetaFlagValue(
"remote-component-library-search",
);
Expand All @@ -84,7 +75,7 @@ const ComponentDetailsDialogContent = withSuspenseWrapper(
);
}

const { url, spec: componentSpec, digest: componentDigest } = componentRef;
const componentSpec = componentRef.spec;

const hasPublishSection =
remoteComponentLibrarySearchEnabled && component.owned;
Expand Down Expand Up @@ -133,14 +124,7 @@ const ComponentDetailsDialogContent = withSuspenseWrapper(
<PublishedComponentDetails component={componentRef} />
) : null}

<TaskDetails
displayName={displayName}
componentRef={componentRef}
componentDigest={componentDigest}
url={url}
actions={actions}
onDelete={onDelete}
/>
<TaskDetails componentRef={componentRef} />
</TabsContent>

<TabsContent value="io" className="h-full">
Expand Down Expand Up @@ -175,18 +159,11 @@ const ComponentDetails = ({
component,
displayName,
trigger,
actions = [],
onClose,
onDelete,
}: ComponentDetailsProps) => {
const hasEnabledInAppEditor = useBetaFlagValue("in-app-component-editor");

const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
const [open, setOpen] = useState(false);
const dialogTriggerButton = trigger || <InfoIconButton />;

const componentText = component.text;

const dialogContextValue = useMemo(
() => ({
name: "ComponentDetails",
Expand All @@ -197,79 +174,42 @@ const ComponentDetails = ({
[],
);

const handleCloseEditDialog = useCallback(() => {
setIsEditDialogOpen(false);
}, []);

const onOpenChange = useCallback((open: boolean) => {
setOpen(open);
if (!open) {
onClose?.();
}
}, []);

const handleEditComponent = useCallback(() => {
setIsEditDialogOpen(true);
}, []);

const actionsWithEdit = useMemo(() => {
if (!hasEnabledInAppEditor) return actions;

const EditButton = (
<TooltipButton
variant="secondary"
onClick={handleEditComponent}
tooltip="Edit Component Definition"
key={`${displayName}-edit-button`}
>
<Icon name="FilePenLine" />
</TooltipButton>
);

return [...actions, EditButton];
}, [actions, hasEnabledInAppEditor, handleEditComponent]);

return (
<>
<Dialog modal open={open} onOpenChange={onOpenChange}>
<DialogTrigger asChild>{dialogTriggerButton}</DialogTrigger>

<DialogDescription
className="hidden"
aria-label={`${displayName} component details`}
>
{`${displayName} component details`}
</DialogDescription>
<DialogContent
className="max-w-2xl min-w-2xl overflow-hidden"
aria-label={`${displayName} component details`}
>
<DialogHeader>
<DialogTitle className="flex items-center gap-2 mr-5">
<span>{displayName}</span>
<ComponentFavoriteToggle component={component} />
</DialogTitle>
</DialogHeader>
<Dialog modal open={open} onOpenChange={onOpenChange}>
<DialogTrigger asChild>{dialogTriggerButton}</DialogTrigger>

<DialogContext.Provider value={dialogContextValue}>
<ComponentDetailsDialogContent
component={component}
displayName={displayName}
trigger={dialogTriggerButton}
actions={actionsWithEdit}
onClose={onClose}
onDelete={onDelete}
/>
</DialogContext.Provider>
</DialogContent>
</Dialog>
{isEditDialogOpen && (
<ComponentEditorDialog
text={componentText}
onClose={handleCloseEditDialog}
/>
)}
</>
<DialogDescription
className="hidden"
aria-label={`${displayName} component details`}
>
{`${displayName} component details`}
</DialogDescription>
<DialogContent
className="max-w-2xl min-w-2xl overflow-hidden"
aria-label={`${displayName} component details`}
>
<DialogHeader>
<DialogTitle className="flex items-center gap-2 mr-5">
<span>{displayName}</span>
<ComponentFavoriteToggle component={component} />
</DialogTitle>
</DialogHeader>

<DialogContext.Provider value={dialogContextValue}>
<ComponentDetailsDialogContent
component={component}
displayName={displayName}
/>
</DialogContext.Provider>
</DialogContent>
</Dialog>
);
};

Expand Down
Loading