Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const PermissionsProvider: React.FC<{ children: ReactNode }> = ({
canUpdateAlerts,
canAnnotateTraceSpanThread,
canTagTrace,
canUsePlayground,
isPending,
} = useUserPermission();

Expand Down Expand Up @@ -63,6 +64,7 @@ const PermissionsProvider: React.FC<{ children: ReactNode }> = ({
canUpdateAlerts,
canAnnotateTraceSpanThread,
canTagTrace,
canUsePlayground,
},
isPending,
}),
Expand Down Expand Up @@ -92,6 +94,7 @@ const PermissionsProvider: React.FC<{ children: ReactNode }> = ({
canUpdateAlerts,
canAnnotateTraceSpanThread,
canTagTrace,
canUsePlayground,
isPending,
],
);
Expand Down
1 change: 1 addition & 0 deletions apps/opik-frontend/src/plugins/comet/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export enum ManagementPermissionsNames {
COMMENT_WRITE = "comment_write",
ONLINE_EVALUATION_RULE_UPDATE = "online_evaluation_rule_update",
ALERT_UPDATE = "alert_update",
PLAYGROUND_USE = "playground_use",
}

export interface UserPermission {
Expand Down
6 changes: 6 additions & 0 deletions apps/opik-frontend/src/plugins/comet/useUserPermission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@ const useUserPermission = (config?: { enabled?: boolean }) => {
[checkNullablePermission],
);

const canUsePlayground = useMemo(
() => checkNullablePermission(ManagementPermissionsNames.PLAYGROUND_USE),
[checkNullablePermission],
);

return {
canInviteMembers,
isWorkspaceOwner,
Expand Down Expand Up @@ -251,6 +256,7 @@ const useUserPermission = (config?: { enabled?: boolean }) => {
canUpdateAlerts,
canAnnotateTraceSpanThread,
canTagTrace,
canUsePlayground,
isPending: isEnabled && isPending,
};
};
Expand Down
2 changes: 2 additions & 0 deletions apps/opik-frontend/src/types/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface Permissions {
canUpdateAlerts: boolean;
canAnnotateTraceSpanThread: boolean;
canTagTrace: boolean;
canUsePlayground: boolean;
}

export interface PermissionsContextValue {
Expand Down Expand Up @@ -58,6 +59,7 @@ export const DEFAULT_PERMISSIONS: PermissionsContextValue = {
canUpdateAlerts: true,
canAnnotateTraceSpanThread: true,
canTagTrace: true,
canUsePlayground: true,
},
isPending: false,
};
17 changes: 17 additions & 0 deletions apps/opik-frontend/src/v1/layout/PlaygroundPageGuard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { usePermissions } from "@/contexts/PermissionsContext";
import NoAccessPageGuard from "@/v1/layout/NoAccessPageGuard/NoAccessPageGuard";

const PlaygroundPageGuard = () => {
const {
permissions: { canUsePlayground },
} = usePermissions();

return (
<NoAccessPageGuard
canViewPage={canUsePlayground}
message="You don't have permissions to use playground in this workspace."
/>
);
};

export default PlaygroundPageGuard;
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@ interface SideBarMenuItemsProps {
const SideBarMenuItems: React.FC<SideBarMenuItemsProps> = ({ expanded }) => {
const { activeWorkspaceName: workspaceName } = useAppStore();
const {
permissions: { canViewExperiments, canViewDashboards, canViewDatasets },
permissions: {
canViewExperiments,
canViewDashboards,
canViewDatasets,
canUsePlayground,
},
} = usePermissions();

const menuItems = getMenuItems({
canViewExperiments,
canViewDashboards,
canViewDatasets,
canUsePlayground,
});

const { data: projectData } = useProjectsList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ const getMenuItems = ({
canViewExperiments,
canViewDashboards,
canViewDatasets,
canUsePlayground,
}: {
canViewExperiments: boolean;
canViewDashboards: boolean;
canViewDatasets: boolean;
canUsePlayground: boolean;
}): MenuItemGroup[] => {
return [
{
Expand Down Expand Up @@ -115,13 +117,17 @@ const getMenuItems = ({
label: "Prompt library",
count: "prompts",
},
{
id: "playground",
path: "/$workspaceName/playground",
type: MENU_ITEM_TYPE.router,
icon: Blocks,
label: "Playground",
},
...(canUsePlayground
? [
{
id: "playground",
path: "/$workspaceName/playground",
type: MENU_ITEM_TYPE.router as const,
icon: Blocks,
label: "Playground",
},
]
: []),
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import get from "lodash/get";
import { FileTerminal, GitCommitVertical } from "lucide-react";
import useAppStore from "@/store/AppStore";
import { useIsFeatureEnabled } from "@/contexts/feature-toggles-provider";
import { usePermissions } from "@/contexts/PermissionsContext";
import { FeatureToggleKeys } from "@/types/feature-toggles";
import TryInPlaygroundButton from "@/v1/pages/PromptPage/TryInPlaygroundButton";
import PromptContentView, {
Expand Down Expand Up @@ -71,6 +72,10 @@ const PromptsTab: React.FunctionComponent<PromptsTabProps> = ({
data,
search,
}) => {
const {
permissions: { canUsePlayground },
} = usePermissions();

const rawPrompts = get(
data.metadata as Record<string, unknown>,
"opik_prompts",
Expand Down Expand Up @@ -129,10 +134,12 @@ const PromptsTab: React.FunctionComponent<PromptsTabProps> = ({
search={search}
templateStructure={rawPrompts[index]?.template_structure}
playgroundButton={
<TryInPlaygroundButton
prompt={promptInfo}
ButtonComponent={CustomUseInPlaygroundButton}
/>
canUsePlayground ? (
<TryInPlaygroundButton
prompt={promptInfo}
ButtonComponent={CustomUseInPlaygroundButton}
/>
) : null
}
/>
</AccordionContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ function UseEvaluationSuiteDropdown({
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);

const {
permissions: { canViewExperiments, canCreateExperiments },
permissions: { canViewExperiments, canCreateExperiments, canUsePlayground },
} = usePermissions();

const hasAnyAction = canUsePlayground || canCreateExperiments;

const { loadPlayground, isPlaygroundEmpty, isPendingProviderKeys } =
useLoadPlayground();

Expand All @@ -55,6 +57,8 @@ function UseEvaluationSuiteDropdown({
}
};

if (!hasAnyAction) return null;

return (
<>
{canViewExperiments && (
Expand All @@ -65,19 +69,21 @@ function UseEvaluationSuiteDropdown({
datasetName={datasetName}
/>
)}
<ConfirmDialog
key={`confirm-dialog-${resetKeyRef.current}`}
open={openConfirmDialog}
setOpen={setOpenConfirmDialog}
onConfirm={handleLoadPlayground}
title={`Load ${
isEvalSuite ? "evaluation suite" : "dataset"
} into playground`}
description={`Loading this ${
isEvalSuite ? "evaluation suite" : "dataset"
} into the Playground will replace any unsaved changes. This action cannot be undone.`}
confirmText={`Load ${isEvalSuite ? "evaluation suite" : "dataset"}`}
/>
{canUsePlayground && (
<ConfirmDialog
key={`confirm-dialog-${resetKeyRef.current}`}
open={openConfirmDialog}
setOpen={setOpenConfirmDialog}
onConfirm={handleLoadPlayground}
title={`Load ${
isEvalSuite ? "evaluation suite" : "dataset"
} into playground`}
description={`Loading this ${
isEvalSuite ? "evaluation suite" : "dataset"
} into the Playground will replace any unsaved changes. This action cannot be undone.`}
confirmText={`Load ${isEvalSuite ? "evaluation suite" : "dataset"}`}
/>
)}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" disabled={disabled}>
Expand All @@ -86,20 +92,22 @@ function UseEvaluationSuiteDropdown({
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-80">
<DropdownMenuItem
onClick={handleOpenPlaygroundClick}
disabled={disabled || isPendingProviderKeys}
>
<Blocks className="mr-2 mt-0.5 size-4 shrink-0 self-start" />
<div className="comet-body-s flex flex-col">
<span>Open in Playground</span>
<span className="text-light-slate">
Test prompts over your{" "}
{isEvalSuite ? "evaluation suite" : "dataset"} and run
evaluations interactively
</span>
</div>
</DropdownMenuItem>
{canUsePlayground && (
<DropdownMenuItem
onClick={handleOpenPlaygroundClick}
disabled={disabled || isPendingProviderKeys}
>
<Blocks className="mr-2 mt-0.5 size-4 shrink-0 self-start" />
<div className="comet-body-s flex flex-col">
<span>Open in Playground</span>
<span className="text-light-slate">
Test prompts over your{" "}
{isEvalSuite ? "evaluation suite" : "dataset"} and run
evaluations interactively
</span>
</div>
</DropdownMenuItem>
)}
{canCreateExperiments && (
<DropdownMenuItem
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ import ChatPromptView from "./ChatPromptView";
import TextPromptView from "./TextPromptView";
import TagListRenderer from "@/shared/TagListRenderer/TagListRenderer";
import usePromptVersionsUpdateMutation from "@/api/prompts/usePromptVersionsUpdateMutation";
import { usePermissions } from "@/contexts/PermissionsContext";

interface PromptTabInterface {
prompt?: PromptWithLatestVersion;
}

const PromptTab = ({ prompt }: PromptTabInterface) => {
const {
permissions: { canUsePlayground },
} = usePermissions();

const [openUseThisPrompt, setOpenUseThisPrompt] = useState(false);
const [openEditPrompt, setOpenEditPrompt] = useState(false);
const [versionToRestore, setVersionToRestore] =
Expand Down Expand Up @@ -120,8 +125,13 @@ const PromptTab = ({ prompt }: PromptTabInterface) => {
<Info className="mr-1.5 size-3.5" />
Use this prompt
</Button>
<TryInPlaygroundButton prompt={prompt} activeVersion={activeVersion} />
{!isChatPrompt && (
{canUsePlayground && (
<TryInPlaygroundButton
prompt={prompt}
activeVersion={activeVersion}
/>
)}
{canUsePlayground && !isChatPrompt && (
<ImproveInPlaygroundButton
prompt={prompt}
activeVersion={activeVersion}
Expand Down
9 changes: 8 additions & 1 deletion apps/opik-frontend/src/v1/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import WorkspaceGuard from "@/v1/layout/WorkspaceGuard/WorkspaceGuard";
import ExperimentsPageGuard from "@/v1/layout/ExperimentsPageGuard";
import DatasetsPageGuard from "@/v1/layout/DatasetsPageGuard";
import DashboardsPageGuard from "@/v1/layout/DashboardsPageGuard";
import PlaygroundPageGuard from "@/v1/layout/PlaygroundPageGuard";
import SMEPageLayout from "@/v1/layout/SMEPageLayout/SMEPageLayout";
import ExperimentsPage from "@/v1/pages/ExperimentsPage/ExperimentsPage";
import CompareExperimentsPage from "@/v1/pages/CompareExperimentsPage/CompareExperimentsPage";
Expand Down Expand Up @@ -437,6 +438,12 @@ const playgroundRoute = createRoute({
staticData: {
title: "Playground",
},
component: PlaygroundPageGuard,
});

const playgroundIndexRoute = createRoute({
path: "/",
getParentRoute: () => playgroundRoute,
component: PlaygroundPage,
});

Expand Down Expand Up @@ -561,7 +568,7 @@ const routeTree = rootRoute.addChildren([
redirectProjectsRoute,
redirectDatasetsRoute,
]),
playgroundRoute,
playgroundRoute.addChildren([playgroundIndexRoute]),
configurationRoute,
alertsRoute.addChildren([alertNewRoute, alertEditRoute]),
onlineEvaluationRoute,
Expand Down
17 changes: 17 additions & 0 deletions apps/opik-frontend/src/v2/layout/PlaygroundPageGuard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { usePermissions } from "@/contexts/PermissionsContext";
import NoAccessPageGuard from "@/v2/layout/NoAccessPageGuard/NoAccessPageGuard";

const PlaygroundPageGuard = () => {
const {
permissions: { canUsePlayground },
} = usePermissions();

return (
<NoAccessPageGuard
canViewPage={canUsePlayground}
message="You don't have permissions to use playground in this workspace."
/>
);
};

export default PlaygroundPageGuard;
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import { usePermissions } from "@/contexts/PermissionsContext";
const SideBarMenuItems: React.FC = () => {
const activeProjectId = useActiveProjectId();
const {
permissions: { canViewExperiments, canViewDatasets },
permissions: { canViewExperiments, canViewDatasets, canUsePlayground },
} = usePermissions();

const menuItems = getMenuItems({
projectId: activeProjectId,
canViewExperiments,
canViewDatasets,
canUsePlayground,
});

const renderItems = (items: MenuItem[]) => {
Expand Down
Loading
Loading