Skip to content

Commit

Permalink
Merge pull request writer#579 from writer/feat-workflows-tools2
Browse files Browse the repository at this point in the history
feat: Workflows tools 2
  • Loading branch information
ramedina86 authored Oct 7, 2024
2 parents 522c405 + 50e77c0 commit e41fe17
Show file tree
Hide file tree
Showing 20 changed files with 489 additions and 85 deletions.
1 change: 1 addition & 0 deletions apps/default/.wf/components-workflows_root.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id": "workflows_root", "type": "workflows_root", "content": {}, "isCodeManaged": false, "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
4 changes: 3 additions & 1 deletion src/ui/src/builder/BuilderComponentShortcuts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class="BuilderComponentShortcuts"
:data-writer-id="componentId"
>
<div class="type">
<div v-if="shortcutsInfo?.toolkit !== 'workflows'" class="type">
{{ shortcutsInfo?.componentTypeName }}
</div>
<template v-if="!isAddMode">
Expand Down Expand Up @@ -186,6 +186,7 @@ const isAddMode = ref(false);
const shortcutsInfo: Ref<{
componentTypeName: string;
toolkit?: WriterComponentDefinition["toolkit"];
isAddEnabled: boolean;
isMoveUpEnabled: boolean;
isMoveDownEnabled: boolean;
Expand Down Expand Up @@ -232,6 +233,7 @@ function reprocessShorcutsInfo(): void {
shortcutsInfo.value = {
isAddEnabled: isAddAllowed(componentId.value),
componentTypeName: wf.getComponentDefinition(component.type)?.name,
toolkit: wf.getComponentDefinition(component.type)?.toolkit,
isMoveUpEnabled,
isMoveDownEnabled,
isCopyEnabled: isCopyAllowed(componentId.value),
Expand Down
11 changes: 9 additions & 2 deletions src/ui/src/builder/BuilderSwitcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,17 @@ const isWorkflowsFeatureFlagged = computed(() =>
let selectedId: Ref<string> = ref(null);
const selectOption = (optionId: "ui" | "code" | "preview" | "workflows") => {
const preMode = ssbm.getMode();
if (preMode == optionId) return;
selectedId.value = optionId;
ssbm.setMode(optionId);
if (ssbm.getMode() != "preview") return;
ssbm.setSelection(null);
if (
optionId == "preview" ||
preMode == "workflows" ||
optionId == "workflows"
) {
ssbm.setSelection(null);
}
};
const activeId = computed(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/ui/src/components/core/content/CoreChatbot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ const MAX_FILE_SIZE = 200 * 1024 * 1024;
const description = "A chatbot component to build human-to-AI interactions.";
const defaultConversation = `[
const initConversation = `[
{
"role": "assistant",
"content": "How can I help you?"
Expand Down Expand Up @@ -238,7 +238,7 @@ export default {
fields: {
conversation: {
name: "Conversation",
default: defaultConversation,
init: initConversation,
desc: "An array with messages or a writer.ai.Conversation object.",
type: FieldType.Object,
},
Expand Down
4 changes: 3 additions & 1 deletion src/ui/src/components/core/root/CoreRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ const { isComponentVisible } = useEvaluator(wf);
const displayedPageId = computed(() => {
const activePageId = wf.getActivePageId();
if (activePageId && wf.isChildOf("root", activePageId)) return activePageId;
const activePageExists = Boolean(wf.getComponentById(activePageId));
if (activePageExists && wf.isChildOf("root", activePageId))
return activePageId;
const pageComponents = wf.getComponents("root", {
includeBMC: true,
Expand Down
3 changes: 2 additions & 1 deletion src/ui/src/components/workflows/WorkflowsRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ const rootEl: Ref<HTMLElement> = ref(null);
const displayedWorkflowId = computed(() => {
const activePageId = wf.getActivePageId();
if (activePageId && wf.isChildOf("workflows_root", activePageId))
const activePageExists = Boolean(wf.getComponentById(activePageId));
if (activePageExists && wf.isChildOf("workflows_root", activePageId))
return activePageId;
const pageComponents = wf.getComponents("workflows_root", {
Expand Down
69 changes: 60 additions & 9 deletions src/ui/src/components/workflows/WorkflowsWorkflow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<div
ref="rootEl"
class="WorkflowsWorkflow"
@click="handleClick"
@dragover="handleDragover"
@drop="handleDrop"
@drag="handleDrag"
Expand All @@ -13,6 +14,11 @@
:key="arrowId"
:arrow="arrow"
:is-selected="selectedArrow == arrowId"
:is-engaged="
selectedArrow == arrowId ||
wfbm.getSelectedId() == arrow.fromNodeId ||
wfbm.getSelectedId() == arrow.out.toNodeId
"
@click="handleArrowClick($event, arrowId)"
@delete="handleDeleteClick($event, arrow)"
></WorkflowArrow>
Expand All @@ -34,13 +40,17 @@
"
></component>
</template>
<WdsButton class="runButton" variant="secondary" @click="handleRun">{{
isRunning ? "Running..." : "Run"
}}</WdsButton>
</div>
</template>

<script lang="ts">
import { type Component, FieldType } from "@/writerTypes";
import WorkflowArrow from "./base/WorkflowArrow.vue";
import { watch } from "vue";
import WdsButton from "@/wds/WdsButton.vue";
const description =
"A container component representing a single workflow within the application.";
Expand Down Expand Up @@ -72,6 +82,7 @@ export type WorkflowArrowData = {
color: string;
fromNodeId: Component["id"];
out: Component["outs"][number];
isEngaged: boolean;
};
</script>
<script setup lang="ts">
Expand All @@ -87,8 +98,11 @@ const wf = inject(injectionKeys.core);
const wfbm = inject(injectionKeys.builderManager);
const arrows: Ref<WorkflowArrowData[]> = ref([]);
const renderOffset = ref({ x: 0, y: 0 });
const isRunning = ref(false);
let clickOffset = { x: 0, y: 0 };
const selectedArrow = ref(null);
const componentId = inject(injectionKeys.componentId);
const instancePath = inject(injectionKeys.instancePath);
const workflowComponentId = inject(injectionKeys.componentId);
Expand Down Expand Up @@ -127,6 +141,7 @@ function refreshArrows() {
if (!fromEl || !toEl) return;
const fromCBR = fromEl.getBoundingClientRect();
const toCBR = toEl.getBoundingClientRect();
a.push({
x1: fromCBR.x - canvasCBR.x + fromCBR.width / 2,
y1: fromCBR.y - canvasCBR.y + fromCBR.height / 2,
Expand All @@ -146,6 +161,26 @@ const isUnselectable = computed(() => {
return true;
});
function handleClick() {
selectedArrow.value = null;
}
async function handleRun() {
if (isRunning.value) return;
isRunning.value = true;
await wf.forwardEvent(
new CustomEvent("wf-builtin-run", {
detail: {
callback: () => {
isRunning.value = false;
},
},
}),
instancePath,
false,
);
}
function handleNodeOutSelect(componentId: Component["id"], outId: string) {
activeNodeOut.value = {
fromComponentId: componentId,
Expand Down Expand Up @@ -212,7 +247,9 @@ function handleArrowClick(ev: MouseEvent, arrowId: number) {
selectedArrow.value = null;
return;
}
ev.stopPropagation();
selectedArrow.value = arrowId;
wfbm.setSelection(null);
}
async function handleDeleteClick(ev: MouseEvent, arrow: WorkflowArrowData) {
Expand Down Expand Up @@ -272,6 +309,14 @@ async function createNode(type: string, x: number, y: number) {
createAndInsertComponent(type, workflowComponentId, undefined, { x, y });
}
watch(
() => wfbm.getSelectedId(),
(newSelected) => {
if (!newSelected) return;
selectedArrow.value = null;
},
);
watch(
children,
async (postChildren, preChildren) => {
Expand All @@ -283,24 +328,24 @@ watch(
[...preIds].filter((cId) => !postIds.has(cId)),
);
postChildren.forEach((c) => {
if (!c.outs || c.outs.length === 0) return;
c.outs = c.outs.filter((out) => !removedIds.has(out.toNodeId));
});
if (removedIds.size > 0) {
postChildren.forEach((c) => {
if (!c.outs || c.outs.length === 0) return;
c.outs = c.outs.filter((out) => !removedIds.has(out.toNodeId));
});
wf.sendComponentUpdate();
}
// Refresh arrows
await nextTick();
refreshArrows();
if (removedIds.size > 0) {
wf.sendComponentUpdate();
}
},
{ deep: true },
);
onMounted(() => {
onMounted(async () => {
await nextTick();
refreshArrows();
});
</script>
Expand All @@ -320,6 +365,12 @@ onMounted(() => {
overflow: hidden;
}
.runButton {
position: absolute;
right: 32px;
top: 32px;
}
.component.WorkflowsWorkflow.selected {
background: var(--builderSubtleSeparatorColor);
}
Expand Down
Loading

0 comments on commit e41fe17

Please sign in to comment.