@truedat/qx 8.10.2 → 8.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/components/QxRoutes.js +8 -7
- package/src/components/__tests__/QxRoutes.spec.js +2 -1
- package/src/components/__tests__/__fixtures__/helper.js +13 -0
- package/src/components/__tests__/__snapshots__/QxRoutes.spec.js.snap +1 -1
- package/src/components/common/ClauseViewer.js +52 -8
- package/src/components/common/DescriptionInput.js +9 -34
- package/src/components/common/TypeSelector.js +20 -10
- package/src/components/common/__tests__/ClauseViewer.spec.js +150 -0
- package/src/components/common/__tests__/DescriptionInput.spec.js +2 -5
- package/src/components/common/__tests__/__snapshots__/DescriptionInput.spec.js.snap +7 -10
- package/src/components/common/expressions/Clauses.js +22 -17
- package/src/components/common/expressions/Condition.js +201 -102
- package/src/components/common/expressions/Expression.js +17 -23
- package/src/components/common/expressions/FunctionSelector.js +3 -3
- package/src/components/common/expressions/ShapeSelector.js +1 -1
- package/src/components/common/expressions/__tests__/Clauses.spec.js +1 -1
- package/src/components/common/expressions/__tests__/Condition.spec.js +83 -26
- package/src/components/common/expressions/__tests__/ParamSelector.spec.js +1 -1
- package/src/components/common/expressions/__tests__/__snapshots__/Clauses.spec.js.snap +18 -22
- package/src/components/common/expressions/__tests__/__snapshots__/Condition.spec.js.snap +215 -216
- package/src/components/common/expressions/__tests__/__snapshots__/ConstantSelector.spec.js.snap +6 -10
- package/src/components/common/expressions/__tests__/__snapshots__/Expression.spec.js.snap +630 -654
- package/src/components/common/expressions/__tests__/__snapshots__/FunctionArgs.spec.js.snap +193 -201
- package/src/components/common/expressions/__tests__/__snapshots__/FunctionSelector.spec.js.snap +450 -466
- package/src/components/common/expressions/__tests__/__snapshots__/ShapeSelector.spec.js.snap +34 -34
- package/src/components/common/expressions/constantInputs/AnySelector.js +1 -0
- package/src/components/common/expressions/constantInputs/__tests__/__snapshots__/AnySelector.spec.js.snap +15 -15
- package/src/components/dataViews/__tests__/__snapshots__/AdvancedDataViewEditor.spec.js.snap +378 -406
- package/src/components/dataViews/__tests__/__snapshots__/DataViewSummary.spec.js.snap +6 -6
- package/src/components/dataViews/__tests__/__snapshots__/Queryable.spec.js.snap +489 -577
- package/src/components/dataViews/__tests__/__snapshots__/Queryables.spec.js.snap +400 -476
- package/src/components/dataViews/advancedForm/Queryable.js +56 -64
- package/src/components/dataViews/advancedForm/Queryables.js +11 -2
- package/src/components/dataViews/queryableProperties/Join.js +16 -6
- package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/Join.spec.js.snap +0 -28
- package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/Select.spec.js.snap +270 -282
- package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/SelectField.spec.js.snap +172 -180
- package/src/components/dataViews/simpleForm/DatasetForm.js +4 -0
- package/src/components/dataViews/simpleForm/FormQueryable.js +49 -53
- package/src/components/dataViews/summary/Where.js +3 -2
- package/src/components/functions/FunctionEdit.js +92 -0
- package/src/components/functions/FunctionEditor.js +32 -10
- package/src/components/functions/FunctionParams.js +54 -61
- package/src/components/functions/FunctionsList.js +213 -0
- package/src/components/functions/__tests__/FunctionEdit.spec.js +168 -0
- package/src/components/functions/__tests__/FunctionParams.spec.js +1 -8
- package/src/components/functions/__tests__/FunctionsList.spec.js +62 -0
- package/src/components/functions/__tests__/__snapshots__/FunctionEditor.spec.js.snap +553 -469
- package/src/components/functions/__tests__/__snapshots__/FunctionParams.spec.js.snap +139 -161
- package/src/components/functions/__tests__/__snapshots__/FunctionsList.spec.js.snap +588 -0
- package/src/components/qualityControls/__tests__/NewQualityControl.spec.js +4 -0
- package/src/components/qualityControls/__tests__/QualityControlEditor.spec.js +8 -1
- package/src/components/qualityControls/__tests__/__snapshots__/EditQualityControl.spec.js.snap +109 -118
- package/src/components/qualityControls/__tests__/__snapshots__/NewDraftQualityControl.spec.js.snap +109 -118
- package/src/components/qualityControls/__tests__/__snapshots__/QualityControlEditor.spec.js.snap +471 -468
- package/src/hooks/useFunctions.js +6 -0
- package/src/styles/Expression.less +39 -6
- package/src/components/functions/Functions.js +0 -143
- package/src/components/functions/__tests__/Functions.spec.js +0 -56
- package/src/components/functions/__tests__/__snapshots__/Functions.spec.js.snap +0 -85
|
@@ -31,3 +31,9 @@ export const useFunctionDelete = (func) => {
|
|
|
31
31
|
const url = compile(API_FUNCTION)({ id: `${id}` });
|
|
32
32
|
return useSWRMutations(url, (url, { arg }) => apiJsonDelete(url, arg));
|
|
33
33
|
};
|
|
34
|
+
|
|
35
|
+
export const useFunctionFetch = (id) => {
|
|
36
|
+
const url = id ? compile(API_FUNCTION)({ id: `${id}` }) : null;
|
|
37
|
+
const { data, error } = useSWR(url, apiJson);
|
|
38
|
+
return { data: data?.data, error, loading: !error && !data };
|
|
39
|
+
};
|
|
@@ -30,21 +30,33 @@
|
|
|
30
30
|
display: flex;
|
|
31
31
|
flex-direction: row;
|
|
32
32
|
align-items: flex-start;
|
|
33
|
+
|
|
34
|
+
.expression-content {
|
|
35
|
+
flex: 1;
|
|
36
|
+
min-width: 0;
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: row;
|
|
39
|
+
align-items: flex-start;
|
|
40
|
+
}
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
.shape-selector-trigger
|
|
43
|
+
.shape-selector-trigger,
|
|
44
|
+
.type-selector-trigger {
|
|
36
45
|
width: 38px;
|
|
37
46
|
height: 38px;
|
|
38
47
|
border: 1px solid rgba(34, 36, 38, 0.15);
|
|
39
48
|
border-radius: 4px;
|
|
40
|
-
font-size: 12px;
|
|
41
|
-
font-weight: bold;
|
|
42
|
-
font-family: monospace;
|
|
43
49
|
display: flex;
|
|
44
50
|
align-items: center;
|
|
45
51
|
justify-content: center;
|
|
46
52
|
}
|
|
47
53
|
|
|
54
|
+
.shape-selector-trigger {
|
|
55
|
+
font-size: 12px;
|
|
56
|
+
font-weight: bold;
|
|
57
|
+
font-family: monospace;
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
.shape-icon {
|
|
49
61
|
font-size: 12px;
|
|
50
62
|
font-weight: bold;
|
|
@@ -127,8 +139,26 @@ ul.function-tree {
|
|
|
127
139
|
|
|
128
140
|
.condition-row {
|
|
129
141
|
display: flex;
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
align-items: flex-start;
|
|
143
|
+
gap: 4px;
|
|
144
|
+
|
|
145
|
+
.condition-fields {
|
|
146
|
+
flex: 1;
|
|
147
|
+
display: flex;
|
|
148
|
+
flex-direction: row;
|
|
149
|
+
gap: 4px;
|
|
150
|
+
min-width: 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.condition-arg-field {
|
|
154
|
+
flex: 1 1 0;
|
|
155
|
+
min-width: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.condition-operator-field {
|
|
159
|
+
flex: 0 0 12%;
|
|
160
|
+
min-width: 0;
|
|
161
|
+
}
|
|
132
162
|
}
|
|
133
163
|
|
|
134
164
|
.condition-operator-trigger {
|
|
@@ -156,6 +186,9 @@ ul.function-tree {
|
|
|
156
186
|
display: flex;
|
|
157
187
|
align-items: center;
|
|
158
188
|
justify-content: flex-end;
|
|
189
|
+
flex-shrink: 0;
|
|
190
|
+
width: 2rem;
|
|
191
|
+
padding-top: 2px;
|
|
159
192
|
}
|
|
160
193
|
|
|
161
194
|
.join_type {
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import _ from "lodash/fp";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { useIntl, FormattedMessage } from "react-intl";
|
|
4
|
-
import {
|
|
5
|
-
Button,
|
|
6
|
-
Grid,
|
|
7
|
-
GridColumn,
|
|
8
|
-
Header,
|
|
9
|
-
Icon,
|
|
10
|
-
List,
|
|
11
|
-
Segment,
|
|
12
|
-
} from "semantic-ui-react";
|
|
13
|
-
|
|
14
|
-
import { typeLabel } from "@truedat/qx/types";
|
|
15
|
-
import {
|
|
16
|
-
useFunctions,
|
|
17
|
-
useFunctionCreate,
|
|
18
|
-
useFunctionDelete,
|
|
19
|
-
useFunctionUpdate,
|
|
20
|
-
} from "@truedat/qx/hooks/useFunctions";
|
|
21
|
-
import FunctionEditor from "./FunctionEditor";
|
|
22
|
-
|
|
23
|
-
const NEW_FUNCTION = {
|
|
24
|
-
name: "",
|
|
25
|
-
description: "",
|
|
26
|
-
type: "boolean",
|
|
27
|
-
params: [],
|
|
28
|
-
expression: { shape: "function", value: null },
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export default function Functions() {
|
|
32
|
-
const { formatMessage } = useIntl();
|
|
33
|
-
const { data, loading, mutate } = useFunctions();
|
|
34
|
-
const [selectedFunction, setSelectedFunction] = useState();
|
|
35
|
-
const [isDirty, setDirty] = useState(false);
|
|
36
|
-
|
|
37
|
-
const functions = data?.data;
|
|
38
|
-
const userFunctions = _.reject(({ expression }) => _.isNil(expression))(
|
|
39
|
-
functions,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
const changeSelectedFunction = (selection) => {
|
|
43
|
-
setSelectedFunction(null);
|
|
44
|
-
setSelectedFunction(selection);
|
|
45
|
-
};
|
|
46
|
-
const setStateNewFunction = () => changeSelectedFunction(NEW_FUNCTION);
|
|
47
|
-
const clearForm = () => {
|
|
48
|
-
setSelectedFunction(null);
|
|
49
|
-
setDirty(false);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const { trigger: createFunction, isMutating: isCreating } =
|
|
53
|
-
useFunctionCreate();
|
|
54
|
-
|
|
55
|
-
const { trigger: updateFunction, isMutating: isUpdating } =
|
|
56
|
-
useFunctionUpdate(selectedFunction);
|
|
57
|
-
|
|
58
|
-
const { trigger: deleteFunction, isMutating: isDeleting } =
|
|
59
|
-
useFunctionDelete(selectedFunction);
|
|
60
|
-
|
|
61
|
-
const isSubmitting = isCreating || isUpdating || isDeleting;
|
|
62
|
-
const onFunctionCreate = (func) => {
|
|
63
|
-
const mutateFunction = selectedFunction?.id
|
|
64
|
-
? updateFunction
|
|
65
|
-
: createFunction;
|
|
66
|
-
mutateFunction({ function: func }).then(() => {
|
|
67
|
-
clearForm();
|
|
68
|
-
mutate();
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
const onFunctionDelete = (func) => {
|
|
72
|
-
deleteFunction({ function: func }).then(() => {
|
|
73
|
-
clearForm();
|
|
74
|
-
mutate();
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
return (
|
|
78
|
-
<Segment loading={loading}>
|
|
79
|
-
<Header as="h2">
|
|
80
|
-
<Icon circular name="archive" />
|
|
81
|
-
<Header.Content>
|
|
82
|
-
<FormattedMessage id="functions.header" />
|
|
83
|
-
<Header.Subheader>
|
|
84
|
-
<FormattedMessage id="functions.subheader" />
|
|
85
|
-
</Header.Subheader>
|
|
86
|
-
</Header.Content>
|
|
87
|
-
</Header>
|
|
88
|
-
<Grid>
|
|
89
|
-
<GridColumn width={4}>
|
|
90
|
-
<Button fluid onClick={setStateNewFunction} disabled={isDirty}>
|
|
91
|
-
{formatMessage({ id: "functions.action.new" })}
|
|
92
|
-
</Button>
|
|
93
|
-
<List divided selection={!isDirty}>
|
|
94
|
-
{!_.isEmpty(userFunctions) ? (
|
|
95
|
-
userFunctions.map((func, key) => (
|
|
96
|
-
<List.Item
|
|
97
|
-
key={key}
|
|
98
|
-
onClick={() => !isDirty && changeSelectedFunction(func)}
|
|
99
|
-
>
|
|
100
|
-
<List.Content>
|
|
101
|
-
<List.Header>
|
|
102
|
-
{typeLabel(func.type)}
|
|
103
|
-
{func.name || "Function"}/{func.params.length}
|
|
104
|
-
</List.Header>
|
|
105
|
-
</List.Content>
|
|
106
|
-
</List.Item>
|
|
107
|
-
))
|
|
108
|
-
) : (
|
|
109
|
-
<List.Item>
|
|
110
|
-
<List.Content>
|
|
111
|
-
<List.Header>
|
|
112
|
-
{formatMessage({ id: "functions.empty_list" })}
|
|
113
|
-
</List.Header>
|
|
114
|
-
</List.Content>
|
|
115
|
-
</List.Item>
|
|
116
|
-
)}
|
|
117
|
-
</List>
|
|
118
|
-
</GridColumn>
|
|
119
|
-
<GridColumn width={11}>
|
|
120
|
-
{selectedFunction ? (
|
|
121
|
-
<FunctionEditor
|
|
122
|
-
key={selectedFunction?.id || "new"}
|
|
123
|
-
selectedFunction={selectedFunction}
|
|
124
|
-
functions={functions}
|
|
125
|
-
onCancel={clearForm}
|
|
126
|
-
onSubmit={onFunctionCreate}
|
|
127
|
-
onDelete={selectedFunction?.id ? onFunctionDelete : null}
|
|
128
|
-
isSubmitting={isSubmitting}
|
|
129
|
-
setDirty={setDirty}
|
|
130
|
-
/>
|
|
131
|
-
) : (
|
|
132
|
-
<Header as="h2" icon textAlign="center">
|
|
133
|
-
<Icon name="hand pointer outline" />
|
|
134
|
-
<Header.Subheader>
|
|
135
|
-
{formatMessage({ id: "functions.no_selection" })}
|
|
136
|
-
</Header.Subheader>
|
|
137
|
-
</Header>
|
|
138
|
-
)}
|
|
139
|
-
</GridColumn>
|
|
140
|
-
</Grid>
|
|
141
|
-
</Segment>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import userEvent from "@testing-library/user-event";
|
|
2
|
-
import { render, waitForLoad } from "@truedat/test/render";
|
|
3
|
-
import Functions from "../Functions";
|
|
4
|
-
|
|
5
|
-
jest.mock("@truedat/qx/hooks/useFunctions", () => {
|
|
6
|
-
const originalModule = jest.requireActual("@truedat/qx/hooks/useFunctions");
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
__esModule: true,
|
|
10
|
-
...originalModule,
|
|
11
|
-
useFunctions: jest.fn(() => ({
|
|
12
|
-
data: {
|
|
13
|
-
data: [
|
|
14
|
-
{
|
|
15
|
-
name: "eq",
|
|
16
|
-
type: "boolean",
|
|
17
|
-
params: [
|
|
18
|
-
{ name: "arg1", type: "any" },
|
|
19
|
-
{ name: "arg2", type: "any" },
|
|
20
|
-
],
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: "user_false",
|
|
24
|
-
type: "boolean",
|
|
25
|
-
params: [],
|
|
26
|
-
expression: {
|
|
27
|
-
shape: "constant",
|
|
28
|
-
value: { type: "boolean", value: "false" },
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
loading: false,
|
|
34
|
-
})),
|
|
35
|
-
useFunctionCreate: jest.fn(() => ({
|
|
36
|
-
trigger: jest.fn(() => new Promise(() => {})),
|
|
37
|
-
isMutating: false,
|
|
38
|
-
})),
|
|
39
|
-
useFunctionDelete: jest.fn(() => ({
|
|
40
|
-
trigger: jest.fn(() => new Promise(() => {})),
|
|
41
|
-
isMutating: false,
|
|
42
|
-
})),
|
|
43
|
-
useFunctionUpdate: jest.fn(() => ({
|
|
44
|
-
trigger: jest.fn(() => new Promise(() => {})),
|
|
45
|
-
isMutating: false,
|
|
46
|
-
})),
|
|
47
|
-
};
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe("<Functions />", () => {
|
|
51
|
-
it("matches the latest snapshot", async () => {
|
|
52
|
-
const rendered = render(<Functions />);
|
|
53
|
-
await waitForLoad(rendered);
|
|
54
|
-
expect(rendered.container).toMatchSnapshot();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`<Functions /> matches the latest snapshot 1`] = `
|
|
4
|
-
<div>
|
|
5
|
-
<div
|
|
6
|
-
class="ui segment"
|
|
7
|
-
>
|
|
8
|
-
<h2
|
|
9
|
-
class="ui header"
|
|
10
|
-
>
|
|
11
|
-
<i
|
|
12
|
-
aria-hidden="true"
|
|
13
|
-
class="archive circular icon"
|
|
14
|
-
/>
|
|
15
|
-
<div
|
|
16
|
-
class="content"
|
|
17
|
-
>
|
|
18
|
-
functions.header
|
|
19
|
-
<div
|
|
20
|
-
class="sub header"
|
|
21
|
-
>
|
|
22
|
-
functions.subheader
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</h2>
|
|
26
|
-
<div
|
|
27
|
-
class="ui grid"
|
|
28
|
-
>
|
|
29
|
-
<div
|
|
30
|
-
class="four wide column"
|
|
31
|
-
>
|
|
32
|
-
<button
|
|
33
|
-
class="ui fluid button"
|
|
34
|
-
>
|
|
35
|
-
functions.action.new
|
|
36
|
-
</button>
|
|
37
|
-
<div
|
|
38
|
-
class="ui divided selection list"
|
|
39
|
-
role="list"
|
|
40
|
-
>
|
|
41
|
-
<div
|
|
42
|
-
class="item"
|
|
43
|
-
role="listitem"
|
|
44
|
-
>
|
|
45
|
-
<div
|
|
46
|
-
class="content"
|
|
47
|
-
>
|
|
48
|
-
<div
|
|
49
|
-
class="header"
|
|
50
|
-
>
|
|
51
|
-
<div
|
|
52
|
-
class="ui teal tiny circular label"
|
|
53
|
-
width="100px"
|
|
54
|
-
>
|
|
55
|
-
b
|
|
56
|
-
</div>
|
|
57
|
-
user_false
|
|
58
|
-
/
|
|
59
|
-
0
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
<div
|
|
66
|
-
class="eleven wide column"
|
|
67
|
-
>
|
|
68
|
-
<h2
|
|
69
|
-
class="ui icon center aligned header"
|
|
70
|
-
>
|
|
71
|
-
<i
|
|
72
|
-
aria-hidden="true"
|
|
73
|
-
class="hand pointer outline icon"
|
|
74
|
-
/>
|
|
75
|
-
<div
|
|
76
|
-
class="sub header"
|
|
77
|
-
>
|
|
78
|
-
functions.no_selection
|
|
79
|
-
</div>
|
|
80
|
-
</h2>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
`;
|