PluginProbe
Extendify / trunk
Extendify vtrunk
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
← All changes | src/Agent/state/workflows.js +50 -26 3.1.1 → trunk View file →
@@ -1,22 +1,12 @@
1 -import { isChangeSiteDesignWorkflowAvailable } from '@agent/lib/util';
2 -import changeSiteDesignWorkflow from '@agent/workflows/theme/change-site-design';
3 -import variationsWorkflow from '@agent/workflows/theme/change-theme-variation';
4 -import { workflows } from '@agent/workflows/workflows';
1 +import { isAbilityWorkflow } from '@agent/lib/abilities';
2 +import { AbilityRun } from '@agent/workflows/abilities/components/run';
3 +import { abilityWorkflows, workflows } from '@agent/workflows/workflows';
5 4 import { useQuickEditStore } from '@quick-edit/state/store';
6 5 import { deepMerge } from '@shared/lib/utils';
7 6 import { create } from 'zustand';
8 7 import { devtools, persist } from 'zustand/middleware';
9 8
10 -const onboarding = window.extAgentData.chatHistory?.length === 0;
11 -const agentResponse = isChangeSiteDesignWorkflowAvailable()
12 - ? changeSiteDesignWorkflow.example?.agentResponse
13 - : variationsWorkflow.example?.agentResponse;
14 -const onboardingToolProps = {
15 - ...agentResponse.whenFinishedTool,
16 - agentResponse,
17 -};
18 -
19 9 // Used to check case-insensitive matches for workflow examples
20 10 const collator = new Intl.Collator(undefined, {
21 11 sensitivity: 'base',
22 12 usage: 'search',
@@ -30,9 +20,18 @@
30 20 const curr = get().workflow;
31 21 // Workflows may define a "parent" workflow via templateId
32 22 const currId = curr?.templateId || curr?.id;
33 23 const wf = workflows.find(({ id }) => id === currId);
34 - if (!wf?.id) return curr || null;
24 + if (!wf?.id) {
25 + if (!curr) return null;
26 + if (!isAbilityWorkflow(curr.id)) return curr;
27 + // The backend never sends whenFinished, so this supplies the gate.
28 + const ability = deepMerge(
29 + { whenFinished: { component: AbilityRun } },
30 + abilityWorkflows[curr.id] ?? {},
31 + );
32 + return { ...deepMerge(curr, ability), id: curr.id };
33 + }
35 34 return { ...deepMerge(curr, wf || {}), id: curr?.id };
36 35 },
37 36 getWorkflowByExample: (example) => {
38 37 const wf = workflows.find(
@@ -38,8 +37,9 @@
38 37 const wf = workflows.find(
39 38 ({ example: ex }) => collator.compare(ex?.text, example) === 0,
40 39 );
41 40 if (!wf?.id) return null;
41 + if (!wf.available()) return null;
42 42 return wf;
43 43 },
44 44 // Gets the workflows available to the user
45 45 // TODO: maybe we need to have a way to include a
@@ -73,20 +73,41 @@
73 73 });
74 74 },
75 75 setWorkflow: (workflow) => {
76 76 const agentBlockCode = useQuickEditStore.getState().agentBlockCode;
77 + const started = workflow
78 + ? { ...workflow, startingPage: window.location.href }
79 + : null;
77 80 set({
78 - workflow: workflow
79 - ? { ...workflow, startingPage: window.location.href }
80 - : null,
81 + workflow: started,
81 82 // If a block is selected, add it to the workflow data
82 83 // previousContent is named this way for legacy reasons
83 84 workflowData: agentBlockCode ? { previousContent: agentBlockCode } : null,
84 85 whenFinishedToolProps: null,
85 86 });
87 + if (!started) return;
88 + const workflowStarted = get().getWorkflow();
89 + window.dispatchEvent(
90 + new CustomEvent('extendify-workflow::started', {
91 + detail: workflowStarted,
92 + }),
93 + );
94 + try {
95 + workflowStarted?.onStarted?.(workflowStarted);
96 + } catch {
97 + // A workflow that can't read the page still has to start.
98 + }
86 99 },
87 100 setWhenFinishedToolProps: (whenFinishedToolProps) =>
88 101 set({ whenFinishedToolProps }),
102 + // Declared up front it would hide the workflow while nothing is staged.
103 + // Not setWorkflow: that resets workflowData and drops the run's data.
104 + requireBlock: () =>
105 + set((state) =>
106 + state.workflow
107 + ? { workflow: { ...state.workflow, requires: ['block'] } }
108 + : {},
109 + ),
89 110 });
90 111
91 112 export const useWorkflowStore = create()(
92 113 persist(devtools(state, { name: 'Extendify Agent Workflows' }), {
@@ -91,19 +112,22 @@
91 112 export const useWorkflowStore = create()(
92 113 persist(devtools(state, { name: 'Extendify Agent Workflows' }), {
93 114 name: `extendify-agent-workflows-${window.extSharedData.siteId}`,
94 115 merge: (persistedState, currentState) => {
95 - // if we are in onboarding mode, add the starting workflow
96 - if (onboarding) {
116 + const merged = { ...currentState, ...persistedState };
117 + // A reload can't carry the staged block a block-patching workflow
118 + // depends on, so a rehydrated-open one is always stale. A canvas
119 + // session is stale too: its field values never persist.
120 + const id = merged.workflow?.templateId || merged.workflow?.id;
121 + const registered = workflows.find((wf) => wf.id === id);
122 + if (id === 'block-patching' || registered?.whenFinished?.canvas) {
97 123 return {
98 - ...currentState,
99 - ...persistedState,
100 - workflow: isChangeSiteDesignWorkflowAvailable()
101 - ? changeSiteDesignWorkflow
102 - : variationsWorkflow,
103 - whenFinishedToolProps: onboardingToolProps,
124 + ...merged,
125 + workflow: null,
126 + whenFinishedToolProps: null,
127 + workflowData: null,
104 128 };
105 129 }
106 - return { ...currentState, ...persistedState };
130 + return merged;
107 131 },
108 132 }),
109 133 );