add Use Script Cache toggle; align toggles to right-hand side (#3121)

This commit is contained in:
Jonathan Dobson
2025-08-06 17:48:55 -04:00
committed by GitHub
parent 60ad36f839
commit 75eadef0e1
11 changed files with 92 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ import {
import { flushSync } from "react-dom"; import { flushSync } from "react-dom";
import Draggable from "react-draggable"; import Draggable from "react-draggable";
import { OrgWalled } from "./Orgwalled";
import { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
@@ -627,7 +628,11 @@ function FloatingWindow({
onClick={toggleMaximized} onClick={toggleMaximized}
/> />
)} )}
{showPowerButton && <PowerButton onClick={() => cycle()} />} {showPowerButton && (
<OrgWalled className="flex items-center justify-center">
<PowerButton onClick={() => cycle()} />
</OrgWalled>
)}
</div> </div>
<div className="ml-auto">{title}</div> <div className="ml-auto">{title}</div>
{showReloadButton && ( {showReloadButton && (

View File

@@ -0,0 +1,46 @@
import { useIsSkyvernUser } from "@/hooks/useIsSkyvernUser";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/util/utils";
function OrgWalled({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
const isSkyvernUser = useIsSkyvernUser();
if (!isSkyvernUser) {
return null;
}
// Wrap children with visual indication for org-walled features
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div
className={cn(
"relative rounded-md border-2 border-dashed border-yellow-400 p-2",
className,
)}
>
{children}
</div>
</TooltipTrigger>
<TooltipContent>
<p>This feature is only available to Skyvern organization members</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
export { OrgWalled };

View File

@@ -0,0 +1,11 @@
import { useUser } from "./useUser";
function useIsSkyvernUser() {
const user = useUser().get();
const email = user?.email;
const isSkyvernUser = email?.toLowerCase().endsWith("@skyvern.com") ?? false;
return isSkyvernUser;
}
export { useIsSkyvernUser };

View File

@@ -349,6 +349,7 @@ function FlowRenderer({
max_screenshot_scrolls: data.settings.maxScreenshotScrolls, max_screenshot_scrolls: data.settings.maxScreenshotScrolls,
totp_verification_url: workflow.totp_verification_url, totp_verification_url: workflow.totp_verification_url,
extra_http_headers: extraHttpHeaders, extra_http_headers: extraHttpHeaders,
use_cache: data.settings.useScriptCache,
workflow_definition: { workflow_definition: {
parameters: data.parameters, parameters: data.parameters,
blocks: data.blocks, blocks: data.blocks,

View File

@@ -24,7 +24,6 @@ import { Skeleton } from "@/components/ui/skeleton";
import { toast } from "@/components/ui/use-toast"; import { toast } from "@/components/ui/use-toast";
import { useCredentialGetter } from "@/hooks/useCredentialGetter"; import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { useMountEffect } from "@/hooks/useMountEffect"; import { useMountEffect } from "@/hooks/useMountEffect";
import { useUser } from "@/hooks/useUser";
import { statusIsFinalized } from "@/routes/tasks/types.ts"; import { statusIsFinalized } from "@/routes/tasks/types.ts";
import { useSidebarStore } from "@/store/SidebarStore"; import { useSidebarStore } from "@/store/SidebarStore";
import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore"; import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore";
@@ -44,9 +43,6 @@ function WorkflowDebugger() {
const credentialGetter = useCredentialGetter(); const credentialGetter = useCredentialGetter();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [shouldFetchDebugSession, setShouldFetchDebugSession] = useState(false); const [shouldFetchDebugSession, setShouldFetchDebugSession] = useState(false);
const user = useUser().get();
const email = user?.email;
const isSkyvernUser = email?.toLowerCase().endsWith("@skyvern.com") ?? false;
const { data: workflowRun } = useWorkflowRunQuery(); const { data: workflowRun } = useWorkflowRunQuery();
const { data: workflow } = useWorkflowQuery({ const { data: workflow } = useWorkflowQuery({
@@ -157,6 +153,7 @@ function WorkflowDebugger() {
extraHttpHeaders: workflow.extra_http_headers extraHttpHeaders: workflow.extra_http_headers
? JSON.stringify(workflow.extra_http_headers) ? JSON.stringify(workflow.extra_http_headers)
: null, : null,
useScriptCache: workflow.use_cache,
}; };
const elements = getElements( const elements = getElements(
@@ -235,7 +232,7 @@ function WorkflowDebugger() {
initialHeight={360} initialHeight={360}
showMaximizeButton={true} showMaximizeButton={true}
showMinimizeButton={true} showMinimizeButton={true}
showPowerButton={blockLabel === undefined && isSkyvernUser} showPowerButton={blockLabel === undefined}
showReloadButton={true} showReloadButton={true}
// -- // --
onCycle={handleOnCycle} onCycle={handleOnCycle}

View File

@@ -58,6 +58,7 @@ function WorkflowEditor() {
extraHttpHeaders: workflow.extra_http_headers extraHttpHeaders: workflow.extra_http_headers
? JSON.stringify(workflow.extra_http_headers) ? JSON.stringify(workflow.extra_http_headers)
: null, : null,
useScriptCache: workflow.use_cache,
}; };
const elements = getElements( const elements = getElements(

View File

@@ -22,6 +22,7 @@ import { ModelSelector } from "@/components/ModelSelector";
import { WorkflowModel } from "@/routes/workflows/types/workflowTypes"; import { WorkflowModel } from "@/routes/workflows/types/workflowTypes";
import { MAX_SCREENSHOT_SCROLLS_DEFAULT } from "../Taskv2Node/types"; import { MAX_SCREENSHOT_SCROLLS_DEFAULT } from "../Taskv2Node/types";
import { KeyValueInput } from "@/components/KeyValueInput"; import { KeyValueInput } from "@/components/KeyValueInput";
import { OrgWalled } from "@/components/Orgwalled";
import { useWorkflowSettingsStore } from "@/store/WorkflowSettingsStore"; import { useWorkflowSettingsStore } from "@/store/WorkflowSettingsStore";
function StartNode({ id, data }: NodeProps<StartNode>) { function StartNode({ id, data }: NodeProps<StartNode>) {
@@ -59,6 +60,7 @@ function StartNode({ id, data }: NodeProps<StartNode>) {
? data.maxScreenshotScrolls ? data.maxScreenshotScrolls
: null, : null,
extraHttpHeaders: data.withWorkflowSettings ? data.extraHttpHeaders : null, extraHttpHeaders: data.withWorkflowSettings ? data.extraHttpHeaders : null,
useScriptCache: data.withWorkflowSettings ? data.useScriptCache : false,
}); });
useEffect(() => { useEffect(() => {
@@ -131,11 +133,27 @@ function StartNode({ id, data }: NodeProps<StartNode>) {
}} }}
/> />
</div> </div>
<OrgWalled>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Label>Use Script Cache</Label>
<HelpTooltip content="Generate & use cached scripts for faster execution" />
<Switch
className="ml-auto"
checked={inputs.useScriptCache}
onCheckedChange={(value) => {
handleChange("useScriptCache", value);
}}
/>
</div>
</div>
</OrgWalled>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Label>Save &amp; Reuse Session</Label> <Label>Save &amp; Reuse Session</Label>
<HelpTooltip content="Persist session information across workflow runs" /> <HelpTooltip content="Persist session information across workflow runs" />
<Switch <Switch
className="ml-auto"
checked={inputs.persistBrowserSession} checked={inputs.persistBrowserSession}
onCheckedChange={(value) => { onCheckedChange={(value) => {
handleChange("persistBrowserSession", value); handleChange("persistBrowserSession", value);

View File

@@ -12,6 +12,7 @@ export type WorkflowStartNodeData = {
maxScreenshotScrolls: number | null; maxScreenshotScrolls: number | null;
extraHttpHeaders: string | null; extraHttpHeaders: string | null;
editable: boolean; editable: boolean;
useScriptCache: boolean;
}; };
export type OtherStartNodeData = { export type OtherStartNodeData = {

View File

@@ -698,6 +698,7 @@ function getElements(
maxScreenshotScrolls: settings.maxScreenshotScrolls, maxScreenshotScrolls: settings.maxScreenshotScrolls,
extraHttpHeaders: settings.extraHttpHeaders, extraHttpHeaders: settings.extraHttpHeaders,
editable, editable,
useScriptCache: settings.useScriptCache,
}), }),
); );
@@ -1400,6 +1401,7 @@ function getWorkflowSettings(nodes: Array<AppNode>): WorkflowSettings {
model: null, model: null,
maxScreenshotScrolls: null, maxScreenshotScrolls: null,
extraHttpHeaders: null, extraHttpHeaders: null,
useScriptCache: false,
}; };
const startNodes = nodes.filter(isStartNode); const startNodes = nodes.filter(isStartNode);
const startNodeWithWorkflowSettings = startNodes.find( const startNodeWithWorkflowSettings = startNodes.find(
@@ -1417,6 +1419,7 @@ function getWorkflowSettings(nodes: Array<AppNode>): WorkflowSettings {
model: data.model, model: data.model,
maxScreenshotScrolls: data.maxScreenshotScrolls, maxScreenshotScrolls: data.maxScreenshotScrolls,
extraHttpHeaders: data.extraHttpHeaders, extraHttpHeaders: data.extraHttpHeaders,
useScriptCache: data.useScriptCache,
}; };
} }
return defaultSettings; return defaultSettings;

View File

@@ -501,6 +501,7 @@ export type WorkflowApiResponse = {
created_at: string; created_at: string;
modified_at: string; modified_at: string;
deleted_at: string | null; deleted_at: string | null;
use_cache: boolean;
}; };
export type WorkflowSettings = { export type WorkflowSettings = {
@@ -510,6 +511,7 @@ export type WorkflowSettings = {
model: WorkflowModel | null; model: WorkflowModel | null;
maxScreenshotScrolls: number | null; maxScreenshotScrolls: number | null;
extraHttpHeaders: string | null; extraHttpHeaders: string | null;
useScriptCache: boolean;
}; };
export type WorkflowModel = JsonObjectExtendable<{ model_name: string }>; export type WorkflowModel = JsonObjectExtendable<{ model_name: string }>;

View File

@@ -14,6 +14,7 @@ export type WorkflowCreateYAMLRequest = {
is_saved_task?: boolean; is_saved_task?: boolean;
max_screenshot_scrolls?: number | null; max_screenshot_scrolls?: number | null;
extra_http_headers?: Record<string, string> | null; extra_http_headers?: Record<string, string> | null;
use_cache?: boolean;
}; };
export type WorkflowDefinitionYAML = { export type WorkflowDefinitionYAML = {