Skip to content

Commit

Permalink
fix: add copy to clipboard icon for experiment ids on experiment comp…
Browse files Browse the repository at this point in the history
…are page (#5596)

* fix: add copy to clipboard icon for experiment ids on experiment compare page

* refactor to re-use experiment dropdown

* more minimal style

---------

Co-authored-by: Mikyo King <[email protected]>
  • Loading branch information
axiomofjoy and mikeldking authored Dec 3, 2024
1 parent eac071f commit 6a62bd2
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 131 deletions.
126 changes: 126 additions & 0 deletions app/src/components/experiment/ExperimentActionMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import React, { ReactNode, useState } from "react";
import { useNavigate } from "react-router";
import copy from "copy-to-clipboard";

import {
ActionMenu,
ActionMenuProps,
Dialog,
DialogContainer,
Flex,
Icon,
Icons,
Item,
Text,
} from "@arizeai/components";

import { JSONBlock } from "@phoenix/components/code";
import { useNotifySuccess } from "@phoenix/contexts";
import { assertUnreachable } from "@phoenix/typeUtils";

export enum ExperimentAction {
GO_TO_EXPERIMENT_RUN_TRACES = "GO_TO_EXPERIMENT_RUN_TRACES",
COPY_EXPERIMENT_ID = "COPY_EXPERIMENT_ID",
VIEW_METADATA = "VIEW_METADATA",
}

export function ExperimentActionMenu(props: {
projectId?: string | null;
experimentId: string;
metadata: unknown;
isQuiet?: ActionMenuProps<string>["isQuiet"];
}) {
const { projectId, isQuiet = false } = props;
const navigate = useNavigate();
const [dialog, setDialog] = useState<ReactNode>(null);
const notifySuccess = useNotifySuccess();
return (
<div
// TODO: add this logic to the ActionMenu component
onClick={(e) => {
// prevent parent anchor link from being followed
e.preventDefault();
e.stopPropagation();
}}
>
<ActionMenu
buttonSize="compact"
align="end"
isQuiet={isQuiet}
disabledKeys={
projectId ? [] : [ExperimentAction.GO_TO_EXPERIMENT_RUN_TRACES]
}
onAction={(firedAction) => {
const action = firedAction as ExperimentAction;
switch (action) {
case ExperimentAction.GO_TO_EXPERIMENT_RUN_TRACES: {
return navigate(`/projects/${projectId}`);
}
case ExperimentAction.VIEW_METADATA: {
setDialog(
<Dialog title="Metadata" onDismiss={() => setDialog(null)}>
<JSONBlock value={JSON.stringify(props.metadata, null, 2)} />
</Dialog>
);
break;
}
case ExperimentAction.COPY_EXPERIMENT_ID: {
copy(props.experimentId);
notifySuccess({
title: "Copied",
message: "The experiment ID has been copied to your clipboard",
});
break;
}
default: {
assertUnreachable(action);
}
}
}}
>
<Item key={ExperimentAction.GO_TO_EXPERIMENT_RUN_TRACES}>
<Flex
direction="row"
gap="size-75"
justifyContent="start"
alignItems="center"
>
<Icon svg={<Icons.Trace />} />
<Text>View run traces</Text>
</Flex>
</Item>
<Item key={ExperimentAction.VIEW_METADATA}>
<Flex
direction="row"
gap="size-75"
justifyContent="start"
alignItems="center"
>
<Icon svg={<Icons.InfoOutline />} />
<Text>View metadata</Text>
</Flex>
</Item>
<Item key={ExperimentAction.COPY_EXPERIMENT_ID}>
<Flex
direction="row"
gap="size-75"
justifyContent="start"
alignItems="center"
>
<Icon svg={<Icons.ClipboardCopy />} />
<Text>Copy experiment ID</Text>
</Flex>
</Item>
</ActionMenu>
<DialogContainer
type="modal"
isDismissable
onDismiss={() => {
setDialog(null);
}}
>
{dialog}
</DialogContainer>
</div>
);
}
6 changes: 6 additions & 0 deletions app/src/components/table/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ export const tableCSS = (theme: Theme) => css`
background: var(--ac-global-color-primary);
}
}
// Style action menu buttons in the header
.ac-button[data-size="compact"][data-childless="true"] {
padding: 0;
border: none;
background-color: transparent;
}
}
}
}
Expand Down
40 changes: 35 additions & 5 deletions app/src/pages/experiment/ExperimentCompareTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
} from "@phoenix/components/annotation";
import { JSONBlock } from "@phoenix/components/code";
import { JSONText } from "@phoenix/components/code/JSONText";
import { ExperimentActionMenu } from "@phoenix/components/experiment/ExperimentActionMenu";
import { SequenceNumberLabel } from "@phoenix/components/experiment/SequenceNumberLabel";
import { resizeHandleCSS } from "@phoenix/components/resize";
import {
Expand Down Expand Up @@ -73,7 +74,13 @@ type ExampleCompareTableProps = {

type ExperimentInfoMap = Record<
string,
{ name: string; sequenceNumber: number } | undefined
| {
name: string;
sequenceNumber: number;
metadata: object;
projectId: string | null;
}
| undefined
>;

type TableRow = ExperimentCompareTableQuery$data["comparisons"][number] & {
Expand Down Expand Up @@ -174,6 +181,10 @@ export function ExperimentCompareTable(props: ExampleCompareTableProps) {
id
name
sequenceNumber
metadata
project {
id
}
}
}
}
Expand All @@ -189,7 +200,10 @@ export function ExperimentCompareTable(props: ExampleCompareTableProps) {
const experimentInfoById = useMemo(() => {
return (
data.dataset?.experiments?.edges.reduce((acc, edge) => {
acc[edge.experiment.id] = { ...edge.experiment };
acc[edge.experiment.id] = {
...edge.experiment,
projectId: edge.experiment?.project?.id || null,
};
return acc;
}, {} as ExperimentInfoMap) || {}
);
Expand Down Expand Up @@ -278,12 +292,28 @@ export function ExperimentCompareTable(props: ExampleCompareTableProps) {
return experimentIds.map((experimentId) => ({
header: () => {
const name = experimentInfoById[experimentId]?.name;
const metadata = experimentInfoById[experimentId]?.metadata;
const projectId = experimentInfoById[experimentId]?.projectId;
const sequenceNumber =
experimentInfoById[experimentId]?.sequenceNumber || 0;
return (
<Flex direction="row" gap="size-100" wrap>
<SequenceNumberLabel sequenceNumber={sequenceNumber} />
<Text>{name}</Text>
<Flex
direction="row"
gap="size-100"
wrap
alignItems="center"
justifyContent="space-between"
>
<Flex direction="row" gap="size-100" wrap alignItems="center">
<SequenceNumberLabel sequenceNumber={sequenceNumber} />
<Text>{name}</Text>
</Flex>
<ExperimentActionMenu
experimentId={experimentId}
metadata={metadata}
isQuiet={true}
projectId={projectId}
/>
</Flex>
);
},
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6a62bd2

Please sign in to comment.