PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
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 +46 -31 3.1.33.2.1 View file →
@@ -1,24 +1,12 @@
1 1 import { isAbilityWorkflow } from '@agent/lib/abilities';
2 -import { isChangeSiteDesignWorkflowAvailable } from '@agent/lib/util';
3 -import { AbilityRunGate } from '@agent/workflows/abilities/components/AbilityRunGate';
4 -import changeSiteDesignWorkflow from '@agent/workflows/theme/change-site-design';
5 -import variationsWorkflow from '@agent/workflows/theme/change-theme-variation';
6 -import { workflows } from '@agent/workflows/workflows';
2 +import { AbilityRun } from '@agent/workflows/abilities/components/run';
3 +import { abilityWorkflows, workflows } from '@agent/workflows/workflows';
7 4 import { useQuickEditStore } from '@quick-edit/state/store';
8 5 import { deepMerge } from '@shared/lib/utils';
9 6 import { create } from 'zustand';
10 7 import { devtools, persist } from 'zustand/middleware';
11 8
12 -const onboarding = window.extAgentData.chatHistory?.length === 0;
13 -const agentResponse = isChangeSiteDesignWorkflowAvailable()
14 - ? changeSiteDesignWorkflow.example?.agentResponse
15 - : variationsWorkflow.example?.agentResponse;
16 -const onboardingToolProps = {
17 - ...agentResponse.whenFinishedTool,
18 - agentResponse,
19 -};
20 -
21 9 // Used to check case-insensitive matches for workflow examples
22 10 const collator = new Intl.Collator(undefined, {
23 11 sensitivity: 'base',
24 12 usage: 'search',
@@ -34,13 +22,15 @@
34 22 const currId = curr?.templateId || curr?.id;
35 23 const wf = workflows.find(({ id }) => id === currId);
36 24 if (!wf?.id) {
37 25 if (!curr) return null;
38 - // Ability workflows are shaped per request, so they carry no static
39 - // whenFinished component; give them the generic run gate.
40 - return isAbilityWorkflow(curr.id)
41 - ? { ...curr, whenFinished: { component: AbilityRunGate } }
42 - : curr;
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 };
43 33 }
44 34 return { ...deepMerge(curr, wf || {}), id: curr?.id };
45 35 },
46 36 getWorkflowByExample: (example) => {
@@ -47,8 +37,9 @@
47 37 const wf = workflows.find(
48 38 ({ example: ex }) => collator.compare(ex?.text, example) === 0,
49 39 );
50 40 if (!wf?.id) return null;
41 + if (!wf.available()) return null;
51 42 return wf;
52 43 },
53 44 // Gets the workflows available to the user
54 45 // TODO: maybe we need to have a way to include a
@@ -82,20 +73,41 @@
82 73 });
83 74 },
84 75 setWorkflow: (workflow) => {
85 76 const agentBlockCode = useQuickEditStore.getState().agentBlockCode;
77 + const started = workflow
78 + ? { ...workflow, startingPage: window.location.href }
79 + : null;
86 80 set({
87 - workflow: workflow
88 - ? { ...workflow, startingPage: window.location.href }
89 - : null,
81 + workflow: started,
90 82 // If a block is selected, add it to the workflow data
91 83 // previousContent is named this way for legacy reasons
92 84 workflowData: agentBlockCode ? { previousContent: agentBlockCode } : null,
93 85 whenFinishedToolProps: null,
94 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 + }
95 99 },
96 100 setWhenFinishedToolProps: (whenFinishedToolProps) =>
97 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 + ),
98 110 });
99 111
100 112 export const useWorkflowStore = create()(
101 113 persist(devtools(state, { name: 'Extendify Agent Workflows' }), {
@@ -100,19 +112,22 @@
100 112 export const useWorkflowStore = create()(
101 113 persist(devtools(state, { name: 'Extendify Agent Workflows' }), {
102 114 name: `extendify-agent-workflows-${window.extSharedData.siteId}`,
103 115 merge: (persistedState, currentState) => {
104 - // if we are in onboarding mode, add the starting workflow
105 - 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) {
106 123 return {
107 - ...currentState,
108 - ...persistedState,
109 - workflow: isChangeSiteDesignWorkflowAvailable()
110 - ? changeSiteDesignWorkflow
111 - : variationsWorkflow,
112 - whenFinishedToolProps: onboardingToolProps,
124 + ...merged,
125 + workflow: null,
126 + whenFinishedToolProps: null,
127 + workflowData: null,
113 128 };
114 129 }
115 - return { ...currentState, ...persistedState };
130 + return merged;
116 131 },
117 132 }),
118 133 );