feat: AI workflow builder front-end (no-changelog) (#14820)

Co-authored-by: Giulio Andreini <g.andreini@gmail.com>
This commit is contained in:
oleg
2025-04-28 15:38:32 +02:00
committed by GitHub
parent dbffcdc2ff
commit 97055d5714
56 changed files with 3857 additions and 1067 deletions

View File

@@ -114,6 +114,7 @@ import { getEasyAiWorkflowJson } from '@/utils/easyAiWorkflowUtils';
import type { CanvasLayoutEvent } from '@/composables/useCanvasLayout';
import { useClearExecutionButtonVisible } from '@/composables/useClearExecutionButtonVisible';
import { LOGS_PANEL_STATE } from '@/components/CanvasChat/types/logs';
import { useBuilderStore } from '@/stores/builder.store';
import { useFoldersStore } from '@/stores/folders.store';
defineOptions({
@@ -165,6 +166,7 @@ const tagsStore = useTagsStore();
const pushConnectionStore = usePushConnectionStore();
const ndvStore = useNDVStore();
const templatesStore = useTemplatesStore();
const builderStore = useBuilderStore();
const foldersStore = useFoldersStore();
const canvasEventBus = createEventBus<CanvasEventBusEvents>();
@@ -228,6 +230,7 @@ const isExecutionPreview = ref(false);
const canOpenNDV = ref(true);
const hideNodeIssues = ref(false);
const fallbackNodes = ref<INodeUi[]>([]);
const initializedWorkflowId = ref<string | undefined>();
const workflowId = computed(() => {
@@ -254,21 +257,6 @@ const isCanvasReadOnly = computed(() => {
);
});
const fallbackNodes = computed<INodeUi[]>(() =>
isLoading.value || isCanvasReadOnly.value
? []
: [
{
id: CanvasNodeRenderType.AddNodes,
name: CanvasNodeRenderType.AddNodes,
type: CanvasNodeRenderType.AddNodes,
typeVersion: 1,
position: [0, 0],
parameters: {},
},
],
);
const showFallbackNodes = computed(() => triggerNodes.value.length === 0);
const keyBindingsEnabled = computed(() => {
@@ -632,7 +620,12 @@ function onRevertNodePosition({ nodeName, position }: { nodeName: string; positi
}
function onDeleteNode(id: string) {
deleteNode(id, { trackHistory: true });
const matchedFallbackNode = fallbackNodes.value.findIndex((node) => node.id === id);
if (matchedFallbackNode >= 0) {
fallbackNodes.value.splice(matchedFallbackNode, 1);
} else {
deleteNode(id, { trackHistory: true });
}
}
function onDeleteNodes(ids: string[]) {
@@ -972,6 +965,11 @@ async function onImportWorkflowDataEvent(data: IDataObject) {
fitView();
selectNodes(workflowData.nodes?.map((node) => node.id) ?? []);
if (data.tidyUp) {
setTimeout(() => {
canvasEventBus.emit('tidyUp', { source: 'import-workflow-data' });
}, 0);
}
}
async function onImportWorkflowUrlEvent(data: IDataObject) {
@@ -1673,6 +1671,37 @@ watch(
},
);
watch(
() => {
return isLoading.value || isCanvasReadOnly.value || editableWorkflow.value.nodes.length !== 0;
},
(isReadOnlyOrLoading) => {
const defaultFallbackNodes: INodeUi[] = [
{
id: CanvasNodeRenderType.AddNodes,
name: CanvasNodeRenderType.AddNodes,
type: CanvasNodeRenderType.AddNodes,
typeVersion: 1,
position: [0, 0],
parameters: {},
},
];
if (builderStore.isAIBuilderEnabled && builderStore.isAssistantEnabled) {
defaultFallbackNodes.unshift({
id: CanvasNodeRenderType.AIPrompt,
name: CanvasNodeRenderType.AIPrompt,
type: CanvasNodeRenderType.AIPrompt,
typeVersion: 1,
position: [-690, -15],
parameters: {},
});
}
fallbackNodes.value = isReadOnlyOrLoading ? [] : defaultFallbackNodes;
},
);
// This keeps the selected node in sync if the URL is updated
watch(
() => route.params.nodeId,