-
-
Notifications
You must be signed in to change notification settings - Fork 345
Expand file tree
/
Copy pathuseRunNode.ts
More file actions
100 lines (86 loc) · 3.37 KB
/
useRunNode.ts
File metadata and controls
100 lines (86 loc) · 3.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useContext } from 'use-context-selector';
import { NodeData } from '../../common/common-types';
import { log } from '../../common/log';
import { delay, mapInputValues } from '../../common/util';
import { AlertBoxContext } from '../contexts/AlertBoxContext';
import { BackendContext } from '../contexts/BackendContext';
import { GlobalContext } from '../contexts/GlobalNodeState';
import { useAsyncEffect } from './useAsyncEffect';
import { useAutomaticFeatures } from './useAutomaticFeatures';
import { useSettings } from './useSettings';
/**
* Runs the given node as soon as it should.
*
* Calling the returned function will try to re-run the node.
*/
export const useRunNode = (
{ inputData, id, schemaId }: NodeData,
isValid: boolean
): { reload: () => void; isLive: boolean } => {
const { sendToast } = useContext(AlertBoxContext);
const { addIndividuallyRunning, removeIndividuallyRunning } = useContext(GlobalContext);
const { schemata, backend } = useContext(BackendContext);
const { packageSettings } = useSettings();
const [reloadCounter, setReloadCounter] = useState(0);
const reload = useCallback(() => setReloadCounter((c) => c + 1), []);
const schema = schemata.get(schemaId);
const didEverRun = useRef(false);
const inputs = useMemo(
() => mapInputValues(schema, (inputId) => inputData[inputId] ?? null),
[inputData, schema]
);
const inputHash = useMemo(
() => `${reloadCounter};${JSON.stringify(inputs)}`,
[reloadCounter, inputs]
);
const lastInputHash = useRef<string>();
const { isAutomatic, hasIncomingConnections } = useAutomaticFeatures(id, schemaId);
const shouldRun = isValid && isAutomatic;
useAsyncEffect(
() => async (token) => {
if (inputHash === lastInputHash.current) {
return;
}
// give it some time for other effects to settle in
await delay(50);
token.checkCanceled();
lastInputHash.current = inputHash;
if (shouldRun) {
didEverRun.current = true;
addIndividuallyRunning(id);
const result = await backend.runIndividual({
schemaId,
id,
inputs,
options: packageSettings,
});
removeIndividuallyRunning(id);
if (!result.success) {
sendToast({
status: 'error',
title: 'Error',
description:
result.error ||
'Preview failed to load, probably unsupported file type.',
});
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[shouldRun, inputHash]
);
useEffect(() => {
return () => {
if (didEverRun.current) {
backend.clearNodeCacheIndividual(id).catch(log.error);
}
};
}, [backend, id]);
useEffect(() => {
if (hasIncomingConnections && didEverRun.current) {
backend.clearNodeCacheIndividual(id).catch(log.error);
}
}, [backend, hasIncomingConnections, id]);
return { reload, isLive: shouldRun };
};