File size: 4,473 Bytes
1dd9186
cfaaa6c
 
1dd9186
cfaaa6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1dd9186
cfaaa6c
 
 
 
1dd9186
cfaaa6c
 
 
1dd9186
cfaaa6c
 
 
 
 
 
 
 
 
 
 
 
 
 
1dd9186
cfaaa6c
 
 
1dd9186
cfaaa6c
 
 
 
 
1dd9186
cfaaa6c
 
 
1dd9186
cfaaa6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { memo, useEffect } from 'react';
import { useUpdateNodeInternals } from '@xyflow/react';
import NodeShell from '../components/NodeShell.jsx';
import { NodeDraftInput } from '../components/NodeDraftField.jsx';
import { useWorkflow } from '../context/WorkflowContext.jsx';
import { createBrowserId } from '../lib/ids.js';
import { getNodeAccent } from '../lib/nodeRegistry.js';

function JsonParserFlowNode({ id, data, selected, type }) {
  const { getNodeHandles, replaceNodeData, removeHandleConnections } = useWorkflow();
  const updateNodeInternals = useUpdateNodeInternals();
  const handles = getNodeHandles(type, data);
  const runtime = data.runtime || {};
  const values = runtime.values || {};

  useEffect(() => {
    updateNodeInternals(id);
  }, [id, data.extracts.length, updateNodeInternals]);

  const addExtract = () => {
    replaceNodeData(id, (current) => ({
      ...current,
      extracts: [
        ...current.extracts,
        {
          id: createBrowserId('json-extract'),
          label: `result ${current.extracts.length}`,
          path: '',
          fields: '',
        },
      ],
    }));
  };

  const updateExtract = (extractId, patch) => {
    replaceNodeData(id, (current) => ({
      ...current,
      extracts: current.extracts.map((extract) =>
        extract.id === extractId ? { ...extract, ...patch } : extract,
      ),
    }));
  };

  const removeExtract = (extractId) => {
    if (data.extracts.length <= 1) {
      return;
    }

    removeHandleConnections(id, extractId, 'source');
    replaceNodeData(id, (current) => ({
      ...current,
      extracts: current.extracts.filter((extract) => extract.id !== extractId),
    }));
  };

  const filledValuesCount = Object.values(values).filter(Boolean).length;

  return (
    <NodeShell
      nodeId={id}
      title={data.title}
      accent={getNodeAccent(type)}
      selected={selected}
      status={runtime.status}
      inputs={handles.inputs}
      outputs={handles.outputs}
    >
      <div className="field-stack">
        <div className="json-parser-rule-list">
          {data.extracts.map((extract, index) => (
            <div key={extract.id} className="json-parser-rule">
              <div className="field-row">
                <label className="field-stack">
                  <span className="field-label">Выход</span>
                  <NodeDraftInput
                    className="nodrag node-input"
                    value={extract.label}
                    placeholder={`результат ${index + 1}`}
                    onCommit={(value) => updateExtract(extract.id, { label: value })}
                  />
                </label>
                <button
                  type="button"
                  className="nodrag chip__remove"
                  onClick={() => removeExtract(extract.id)}
                  disabled={data.extracts.length <= 1}
                >
                  x
                </button>
              </div>

              <label className="field-stack">
                <span className="field-label">Путь</span>
                <NodeDraftInput
                  className="nodrag node-input"
                  value={extract.path}
                  placeholder="data.filter_group.items"
                  onCommit={(value) => updateExtract(extract.id, { path: value })}
                />
              </label>

              <label className="field-stack">
                <span className="field-label">Поля</span>
                <NodeDraftInput
                  className="nodrag node-input"
                  value={extract.fields}
                  placeholder="key, name"
                  onCommit={(value) => updateExtract(extract.id, { fields: value })}
                />
              </label>
            </div>
          ))}
        </div>

        <button type="button" className="nodrag node-button node-button--ghost" onClick={addExtract}>
          + Добавить извлечение
        </button>

        <div className="node-note">
          {filledValuesCount > 0
            ? `Извлечено выходов: ${filledValuesCount}.`
            : 'Путь использует dot notation. Поля опциональны и задаются через запятую.'}
        </div>

        {runtime.error ? <div className="node-error">{runtime.error}</div> : null}
      </div>
    </NodeShell>
  );
}

export default memo(JsonParserFlowNode);