Skip to content

Commit

Permalink
Do not update if there is a save pending (#4842)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwdchang authored Sep 24, 2024
1 parent db16c8f commit c42e16e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@
left: `${node.x}px`
}"
@dragging="(event) => updatePosition(node, event)"
@dragend="saveWorkflowHandler()"
@dragend="
isDragging = false;
saveWorkflowHandler();
"
>
<tera-operator
ref="teraOperatorRefs"
Expand Down Expand Up @@ -266,6 +269,8 @@ let canvasTransform = { x: 0, y: 0, k: 1 };
let currentPortPosition: Position = { x: 0, y: 0 };
let isMouseOverPort: boolean = false;
let saveTimer: any = null;
let pendingSave = false;
let isDragging = false;
let startTime: number = 0;
Expand Down Expand Up @@ -302,28 +307,35 @@ const teraOperatorRefs = ref();
async function updateWorkflowName() {
const workflowClone = cloneDeep(wf.value.dump());
workflowClone.name = newWorkflowName.value;
await workflowService.updateWorkflow(workflowClone);
await workflowService.saveWorkflow(workflowClone);
await useProjects().refresh();
isRenamingWorkflow.value = false;
wf.value.load(await workflowService.getWorkflow(props.assetId));
}
// eslint-disable-next-line
const _saveWorkflow = async () => {
await workflowService.updateWorkflow(wf.value.dump(), currentProjectId.value ?? undefined);
pendingSave = false;
await workflowService.saveWorkflow(wf.value.dump(), currentProjectId.value ?? undefined);
// wf.value.update(updated);
};
// eslint-disable-next-line
const _updateWorkflow = (event: any) => {
if (event.data.id !== wf.value.getId()) return;
// console.log('update workflow', event.data);
wf.value.update(event.data as Workflow);
if (event.data.id !== wf.value.getId()) {
return;
}
const delayUpdate = pendingSave || isDragging;
wf.value.update(event.data as Workflow, delayUpdate);
};
const saveWorkflowHandler = debounce(_saveWorkflow, 400);
const saveWorkflowDebounced = debounce(_saveWorkflow, 400);
const updateWorkflowHandler = debounce(_updateWorkflow, 250);
const saveWorkflowHandler = () => {
pendingSave = true;
saveWorkflowDebounced();
};
function appendInputPort(node: WorkflowNode<any>, port: { type: string; label?: string; value: any }) {
node.inputs.push({
id: uuidv4(),
Expand Down Expand Up @@ -869,6 +881,7 @@ const updatePosition = (node: WorkflowNode<any>, { x, y }) => {
if (teraNode.isEditing ?? false) {
return;
}
isDragging = true;
node.x += x / canvasTransform.k;
node.y += y / canvasTransform.k;
updateEdgePositions(node, { x, y });
Expand Down Expand Up @@ -934,6 +947,7 @@ watch(
() => props.assetId,
async (newId, oldId) => {
isRenamingWorkflow.value = false; // Closes rename input if opened in previous workflow
pendingSave = false;
// Save previous workflow, if applicable
if (newId !== oldId && oldId) {
Expand Down
34 changes: 31 additions & 3 deletions packages/client/hmi-client/src/services/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,14 @@ export class WorkflowWrapper {
* FIXME: Need to split workflow into different categories and sending the commands
* instead of the result. It is possible here to become de-synced: eg state-update-response
* comes in as we are about to change the output ports.
*
* delayUpdate is a used to indicate there are actions in progress, and an update from
* the DB can potentially overwrite what the user had already done that have yet to be flushed
* to the backend. In situation like this, we will update the version (so our subsequent updates are
* not rejected) and skip the rest. For example, the user may be dragging an operator on the
* canvas when the db upate comes in.
* */
update(updatedWF: Workflow) {
update(updatedWF: Workflow, delayUpdate: boolean) {
if (updatedWF.id !== this.wf.id) {
throw new Error(`Workflow failed, inconsistent ids updated=${updatedWF.id} self=${this.wf.id}`);
}
Expand All @@ -65,6 +71,28 @@ export class WorkflowWrapper {
const updatedNodeMap = new Map<string, WorkflowNode<any>>(updatedWF.nodes.map((n) => [n.id, n]));
const updatedEdgeMap = new Map<string, WorkflowEdge>(updatedWF.edges.map((e) => [e.id, e]));

if (delayUpdate) {
for (let i = 0; i < nodes.length; i++) {
const nodeId = nodes[i].id;
const updated = updatedNodeMap.get(nodeId);
if (updated) {
if (!nodes[i].version || (updated.version as number) > (nodes[i].version as number)) {
nodes[i].version = updated.version;
}
}
}
for (let i = 0; i < edges.length; i++) {
const edgeId = edges[i].id;
const updated = updatedEdgeMap.get(edgeId);
if (updated) {
if (!edges[i].version || (updated.version as number) > (edges[i].version as number)) {
edges[i].version = updated.version;
}
}
}
return;
}

// Update and deletes
for (let i = 0; i < nodes.length; i++) {
const nodeId = nodes[i].id;
Expand Down Expand Up @@ -664,8 +692,8 @@ export const createWorkflow = async (workflow: Workflow) => {
return response?.data ?? null;
};

// Update
export const updateWorkflow = async (workflow: Workflow, projectId?: string) => {
// Update/save
export const saveWorkflow = async (workflow: Workflow, projectId?: string) => {
const id = workflow.id;
const response = await API.put(`/workflows/${id}`, workflow, { params: { 'project-id': projectId } });
return response?.data ?? null;
Expand Down

0 comments on commit c42e16e

Please sign in to comment.