Skip to content

Commit c3ccfe0

Browse files
authored
Merge pull request #97 from FlowTestAI/user-feedbacks
feat: main viewports and logs of each canvas and introduce json editor
2 parents 2e3fd5d + 5ac8237 commit c3ccfe0

23 files changed

Lines changed: 430 additions & 47 deletions

File tree

.changeset/slimy-bottles-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"flowtestai": patch
3+
---
4+
5+
Maintain state of logs and viewports of each canvas separately. Add Json editor in request and output node. Fix some minor bugs

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pnpm install
4242

4343
### Implement your changes
4444

45-
This project is a monorepo. The code for the CLI is in the `package/flowtest-cli` directory, (add here learn what flowtest-electron is vs the main src folder)
45+
This project is a monorepo. FlowTestAI is offered as a local electron desktop app. In lieu of that it has two major components, the main logical part of the application resides in `packages/flowtest-electron` and the renderer (UI) part of the application resides in `src`. We are also actively developing the CLI and it resides in `packages/flowtest-cli` directory.
4646

4747
Here are some useful scripts for when you are developing:
4848

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@testing-library/react": "^13.4.0",
4545
"@testing-library/user-event": "^13.5.0",
4646
"@tippyjs/react": "^4.2.6",
47+
"ace-builds": "^1.33.1",
4748
"allotment": "^1.20.0",
4849
"autoprefixer": "^10.4.18",
4950
"axios": "^1.5.1",
@@ -54,6 +55,7 @@
5455
"notistack": "^3.0.1",
5556
"postcss": "^8.4.35",
5657
"react": "^18.2.0",
58+
"react-ace": "^11.0.1",
5759
"react-dom": "^18.2.0",
5860
"react-edit-text": "^5.1.1",
5961
"react-icons": "^5.0.1",

packages/flowtest-electron/src/utils/flowparser/parser.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ const deserialize = (flowData) => {
153153
textData.graph.metadata.edges[edge.id] = _edge;
154154
});
155155
}
156+
157+
if (flowData.viewport) {
158+
textData.graph.metadata.viewport = flowDataCopy.viewport;
159+
}
156160
}
157161

158162
return textData;
@@ -162,6 +166,7 @@ const serialize = (textData) => {
162166
const flowData = {};
163167
flowData.nodes = [];
164168
flowData.edges = [];
169+
flowData.viewport = { x: 0, y: 0, zoom: 1 };
165170

166171
// we don't want to modify original object
167172
const textDataCopy = cloneDeep(textData);
@@ -242,6 +247,10 @@ const serialize = (textData) => {
242247
...value,
243248
});
244249
});
250+
251+
if (textDataCopy.graph.metadata.viewport) {
252+
flowData.viewport = textDataCopy.graph.metadata.viewport;
253+
}
245254
}
246255
} else {
247256
throw new Error('Version not recognized');

packages/flowtest-electron/tests/utils/flowtest-parser.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ describe('FlowTest parser', () => {
253253
id: 'reactflow__edge-9true-10',
254254
},
255255
],
256+
viewport: { x: 0.1, y: 0.2, zoom: 1.9876 },
256257
};
257258

258259
const textData = deserialize(flowData);
@@ -262,5 +263,6 @@ describe('FlowTest parser', () => {
262263

263264
expect(_flowData.nodes).toEqual(flowData.nodes);
264265
expect(_flowData.edges).toEqual(flowData.edges);
266+
expect(_flowData.viewport).toEqual(flowData.viewport);
265267
});
266268
});

pnpm-lock.yaml

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/atoms/JsonEditor.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { Component } from 'react';
2+
import AceEditor from 'react-ace';
3+
import 'ace-builds/src-noconflict/mode-json';
4+
import 'ace-builds/src-noconflict/theme-github';
5+
import 'ace-builds/src-noconflict/ext-language_tools';
6+
7+
const JsonEditor = ({ ...props }) => {
8+
return (
9+
<AceEditor
10+
height='inherit'
11+
width='inherit'
12+
minLines={2}
13+
maxLines={props.maxLines || 15}
14+
placeholder={props.placeholder || ''}
15+
mode='json'
16+
theme='github'
17+
name={props.name}
18+
//onLoad={this.onLoad}
19+
onChange={props.onChange}
20+
fontSize={14}
21+
lineHeight={19}
22+
showPrintMargin={true}
23+
showGutter={true}
24+
highlightActiveLine={true}
25+
value={props.value}
26+
setOptions={{
27+
enableBasicAutocompletion: true,
28+
enableLiveAutocompletion: true,
29+
enableSnippets: false,
30+
showLineNumbers: true,
31+
tabSize: 2,
32+
}}
33+
readOnly={props.readOnly || false}
34+
/>
35+
);
36+
};
37+
38+
export default JsonEditor;

src/components/atoms/Tabs.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,24 @@ import { useTabStore } from 'stores/TabStore';
44
import ConfirmActionModal from 'components/molecules/modals/ConfirmActionModal';
55
import { isEqual } from 'lodash';
66
import { OBJ_TYPES } from 'constants/Common';
7+
import { compare } from './util';
78

89
const tabUnsavedChanges = (tab) => {
9-
if (tab.type === OBJ_TYPES.flowtest && tab.flowDataDraft && !isEqual(tab.flowData, tab.flowDataDraft)) {
10-
return true;
10+
if (tab.type === OBJ_TYPES.flowtest && tab.flowDataDraft) {
11+
const draftNodesSansOutput = tab.flowDataDraft.nodes.map((node) => {
12+
if (node.type === 'outputNode' && node.data.output) {
13+
const { ['output']: _, ...data } = node.data;
14+
return {
15+
...node,
16+
data,
17+
};
18+
}
19+
return node;
20+
});
21+
if (!isEqual(tab.flowData.nodes, draftNodesSansOutput) || !isEqual(tab.flowData.edges, tab.flowDataDraft.edges)) {
22+
console.log('Detected unsaved changes: ', compare(tab.flowData, tab.flowDataDraft));
23+
return true;
24+
}
1125
} else if (tab.type === OBJ_TYPES.environment && tab.variablesDraft && !isEqual(tab.variables, tab.variablesDraft)) {
1226
return true;
1327
} else {

src/components/atoms/common/TimeSelector.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React, { useState } from 'react';
22
import PropTypes from 'prop-types';
33
import { ClockIcon } from '@heroicons/react/24/outline';
4+
import Tippy from '@tippyjs/react';
5+
import 'tippy.js/dist/tippy.css';
46

57
const TimeSelector = ({ optionsData, defaultOptionData, onSelectHandler = () => null }) => {
68
return (
79
<div className='flex items-center justify-between gap-2 pl-4 outline-none'>
8-
<ClockIcon className='w-5 h-5' />
10+
<Tippy content='Timeout' placement='top'>
11+
<ClockIcon className='w-5 h-5' />
12+
</Tippy>
913
<select
1014
onChange={onSelectHandler}
1115
name='timer-selector'

src/components/atoms/util.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import _, { isEqual, map } from 'lodash';
2+
3+
export const compare = (a, b) => {
4+
const result = {
5+
different: [],
6+
missing_from_first: [],
7+
missing_from_second: [],
8+
};
9+
10+
_.reduce(
11+
a,
12+
function (result, value, key) {
13+
if (Object.prototype.hasOwnProperty.call(b, key)) {
14+
if (isEqual(value, b[key])) {
15+
return result;
16+
} else {
17+
if (typeof a[key] != typeof {} || typeof b[key] != typeof {}) {
18+
//dead end.
19+
result.different.push(key);
20+
return result;
21+
} else {
22+
var deeper = compare(a[key], b[key]);
23+
result.different = result.different.concat(
24+
map(deeper.different, (sub_path) => {
25+
return key + '.' + sub_path;
26+
}),
27+
);
28+
29+
result.missing_from_second = result.missing_from_second.concat(
30+
map(deeper.missing_from_second, (sub_path) => {
31+
return key + '.' + sub_path;
32+
}),
33+
);
34+
35+
result.missing_from_first = result.missing_from_first.concat(
36+
map(deeper.missing_from_first, (sub_path) => {
37+
return key + '.' + sub_path;
38+
}),
39+
);
40+
return result;
41+
}
42+
}
43+
} else {
44+
result.missing_from_second.push(key);
45+
return result;
46+
}
47+
},
48+
result,
49+
);
50+
51+
_.reduce(
52+
b,
53+
function (result, value, key) {
54+
if (Object.prototype.hasOwnProperty.call(a, key)) {
55+
return result;
56+
} else {
57+
result.missing_from_first.push(key);
58+
return result;
59+
}
60+
},
61+
result,
62+
);
63+
64+
return result;
65+
};

0 commit comments

Comments
 (0)