@truedat/qx 7.13.7 → 7.13.9

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.
Files changed (74) hide show
  1. package/package.json +3 -3
  2. package/src/components/QxRoutes.js +8 -6
  3. package/src/components/common/ResourceSelector.js +25 -6
  4. package/src/components/common/TypeSelector.js +14 -9
  5. package/src/components/common/__tests__/__snapshots__/ResourceSelector.spec.js.snap +269 -241
  6. package/src/components/common/__tests__/__snapshots__/TypeSelector.spec.js.snap +198 -190
  7. package/src/components/common/expressions/Clauses.js +19 -11
  8. package/src/components/common/expressions/Condition.js +32 -31
  9. package/src/components/common/expressions/FieldSelector.js +30 -16
  10. package/src/components/common/expressions/FunctionSelector.js +38 -23
  11. package/src/components/common/expressions/ShapeSelector.js +6 -5
  12. package/src/components/common/expressions/__tests__/ShapeSelector.spec.js +1 -1
  13. package/src/components/common/expressions/__tests__/__snapshots__/Clauses.spec.js.snap +36 -12
  14. package/src/components/common/expressions/__tests__/__snapshots__/Condition.spec.js.snap +87 -75
  15. package/src/components/common/expressions/__tests__/__snapshots__/ConstantSelector.spec.js.snap +99 -97
  16. package/src/components/common/expressions/__tests__/__snapshots__/Expression.spec.js.snap +236 -216
  17. package/src/components/common/expressions/__tests__/__snapshots__/FunctionArgs.spec.js.snap +97 -89
  18. package/src/components/common/expressions/__tests__/__snapshots__/FunctionSelector.spec.js.snap +373 -345
  19. package/src/components/common/expressions/constantInputs/AnySelector.js +2 -1
  20. package/src/components/common/expressions/constantInputs/BooleanSelector.js +20 -15
  21. package/src/components/common/expressions/constantInputs/DefaultSelector.js +0 -1
  22. package/src/components/common/expressions/constantInputs/__tests__/__snapshots__/AnySelector.spec.js.snap +189 -182
  23. package/src/components/common/expressions/constantInputs/__tests__/__snapshots__/BooleanSelector.spec.js.snap +74 -66
  24. package/src/components/common/expressions/constantInputs/__tests__/__snapshots__/DefaultSelector.spec.js.snap +2 -4
  25. package/src/components/common/resourceSelectors/DataStructureSelector.js +5 -4
  26. package/src/components/common/resourceSelectors/DataViewSelector.js +4 -3
  27. package/src/components/common/resourceSelectors/ReferenceDatasetSelector.js +4 -3
  28. package/src/components/common/resourceSelectors/__tests__/__snapshots__/DataStructureSelector.spec.js.snap +65 -61
  29. package/src/components/common/resourceSelectors/__tests__/__snapshots__/DataViewSelector.spec.js.snap +38 -34
  30. package/src/components/common/resourceSelectors/__tests__/__snapshots__/ReferenceDatasetSelector.spec.js.snap +38 -34
  31. package/src/components/dataViews/BreadCrumb.js +20 -0
  32. package/src/components/dataViews/DataViewEditor.js +169 -178
  33. package/src/components/dataViews/DataViews.js +113 -135
  34. package/src/components/dataViews/__tests__/AdvancedDataViewEditor.spec.js +260 -0
  35. package/src/components/dataViews/__tests__/DataViewEditor.spec.js +173 -239
  36. package/src/components/dataViews/__tests__/DataViewSelect.spec.js +1 -1
  37. package/src/components/dataViews/__tests__/DataViews.spec.js +124 -51
  38. package/src/components/dataViews/__tests__/Queryable.spec.js +1 -1
  39. package/src/components/dataViews/__tests__/Queryables.spec.js +1 -1
  40. package/src/components/dataViews/__tests__/SimpleDataViewEditor.spec.js +164 -0
  41. package/src/components/dataViews/__tests__/__snapshots__/{DataViewEditor.spec.js.snap → AdvancedDataViewEditor.spec.js.snap} +230 -200
  42. package/src/components/dataViews/__tests__/__snapshots__/DataViews.spec.js.snap +141 -29
  43. package/src/components/dataViews/__tests__/__snapshots__/Queryable.spec.js.snap +184 -141
  44. package/src/components/dataViews/__tests__/__snapshots__/Queryables.spec.js.snap +126 -91
  45. package/src/components/dataViews/actions/CancelButton.js +33 -0
  46. package/src/components/dataViews/actions/DeleteButton.js +33 -0
  47. package/src/components/dataViews/advancedForm/AdvancedDataViewEditor.js +159 -0
  48. package/src/components/dataViews/{DataViewSelect.js → advancedForm/DataViewSelect.js} +2 -2
  49. package/src/components/dataViews/{Queryable.js → advancedForm/Queryable.js} +2 -2
  50. package/src/components/dataViews/queryableFunctions.js +7 -0
  51. package/src/components/dataViews/queryableProperties/GroupBy.js +23 -27
  52. package/src/components/dataViews/queryableProperties/Join.js +0 -3
  53. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/From.spec.js.snap +30 -26
  54. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/GroupBy.spec.js.snap +130 -102
  55. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/Join.spec.js.snap +42 -31
  56. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/Select.spec.js.snap +81 -69
  57. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/SelectField.spec.js.snap +62 -54
  58. package/src/components/dataViews/queryableProperties/__tests__/__snapshots__/Where.spec.js.snap +12 -4
  59. package/src/components/dataViews/simpleForm/AggregationForm.js +179 -0
  60. package/src/components/dataViews/simpleForm/DatasetForm.js +199 -0
  61. package/src/components/dataViews/simpleForm/FormQueryable.js +114 -0
  62. package/src/components/dataViews/simpleForm/InformationForm.js +107 -0
  63. package/src/components/dataViews/simpleForm/SelectionForm.js +50 -0
  64. package/src/components/dataViews/simpleForm/SimpleDataViewEditor.js +265 -0
  65. package/src/components/functions/__tests__/__snapshots__/FunctionEditor.spec.js.snap +663 -631
  66. package/src/components/functions/__tests__/__snapshots__/FunctionParams.spec.js.snap +113 -109
  67. package/src/components/qualityControls/__tests__/__snapshots__/ControlProperties.spec.js.snap +92 -76
  68. package/src/components/qualityControls/__tests__/__snapshots__/EditQualityControl.spec.js.snap +108 -80
  69. package/src/components/qualityControls/__tests__/__snapshots__/NewDraftQualityControl.spec.js.snap +108 -80
  70. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlEditor.spec.js.snap +108 -80
  71. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Count.spec.js.snap +40 -36
  72. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Ratio.spec.js.snap +92 -76
  73. package/src/hooks/useDataViews.js +7 -0
  74. /package/src/components/dataViews/{Queryables.js → advancedForm/Queryables.js} +0 -0
@@ -0,0 +1,107 @@
1
+ import _ from "lodash/fp";
2
+ import { useIntl } from "react-intl";
3
+ import { lazy, useEffect } from "react";
4
+ import { Divider, Header, Form, Segment } from "semantic-ui-react";
5
+ import { useFormContext, Controller } from "react-hook-form";
6
+
7
+ const SourceSelector = lazy(
8
+ () => import("@truedat/cx/sources/components/SourceSelector")
9
+ );
10
+
11
+ const InformationForm = ({
12
+ isEditForm,
13
+ setStepInformation,
14
+ stepInformation,
15
+ }) => {
16
+ const { formatMessage } = useIntl();
17
+ const { control, watch } = useFormContext();
18
+ const fieldNames = ["name", "source_id", "description"];
19
+
20
+ useEffect(() => {
21
+ if (!_.isEqual(stepInformation?.fieldNames, fieldNames))
22
+ setStepInformation(0, { ...stepInformation, fieldNames });
23
+ }, [stepInformation, fieldNames]);
24
+
25
+ return (
26
+ <>
27
+ <Segment>
28
+ <Header as="h3">
29
+ {watch("name") || formatMessage({ id: "dataViews.action.new" })}
30
+ </Header>
31
+ <Controller
32
+ control={control}
33
+ name="name"
34
+ rules={{
35
+ required: formatMessage(
36
+ { id: "form.validation.required" },
37
+ { prop: formatMessage({ id: "dataViews.form.name" }) }
38
+ ),
39
+ }}
40
+ render={({
41
+ field: { onBlur, onChange, value },
42
+ fieldState: { error },
43
+ }) => (
44
+ <Form.Field required width={10}>
45
+ <label>{formatMessage({ id: "group.props.name" })}</label>
46
+ <Form.Input
47
+ autoComplete="off"
48
+ placeholder={formatMessage({
49
+ id: "dataViews.form.name",
50
+ })}
51
+ error={error?.message}
52
+ onBlur={onBlur}
53
+ onChange={(_e, { value }) => onChange(value)}
54
+ value={value}
55
+ />
56
+ </Form.Field>
57
+ )}
58
+ />
59
+ <Controller
60
+ name="description"
61
+ control={control}
62
+ render={({ field: { onBlur, onChange, value } }) => (
63
+ <Form.Field width={10}>
64
+ <label>{formatMessage({ id: "group.props.description" })}</label>
65
+ <Form.Input
66
+ onBlur={onBlur}
67
+ placeholder={formatMessage({ id: "hierarchy.add_description" })}
68
+ onChange={(_e, { value }) => onChange(value)}
69
+ value={value}
70
+ style={{ width: "100%" }}
71
+ />
72
+ </Form.Field>
73
+ )}
74
+ />
75
+ <Controller
76
+ control={control}
77
+ name="source_id"
78
+ rules={{
79
+ required: {
80
+ value: true,
81
+ message: formatMessage({ id: "dataViews.form.source.required" }),
82
+ },
83
+ }}
84
+ render={({
85
+ field: { onBlur, onChange, value },
86
+ fieldState: { error },
87
+ }) => (
88
+ <Form.Field required width={10}>
89
+ <label>{formatMessage({ id: "dataViews.form.source" })}</label>
90
+ <SourceSelector
91
+ disabled={isEditForm}
92
+ required
93
+ value={value}
94
+ onBlur={onBlur}
95
+ onChange={(_e, { value }) => onChange(value)}
96
+ error={error?.message}
97
+ />
98
+ </Form.Field>
99
+ )}
100
+ />
101
+ </Segment>
102
+ <Divider hidden />
103
+ </>
104
+ );
105
+ };
106
+
107
+ export default InformationForm;
@@ -0,0 +1,50 @@
1
+ import _ from "lodash/fp";
2
+ import { use, useEffect } from "react";
3
+ import { useIntl } from "react-intl";
4
+ import { useFormContext } from "react-hook-form";
5
+ import { Divider, Grid, Segment } from "semantic-ui-react";
6
+ import QxContext from "@truedat/qx/components/QxContext";
7
+ import { Select } from "../queryableProperties";
8
+ import { reduceQueryableFields } from "../queryableFunctions";
9
+
10
+ export default function SelectionForm({ setStepInformation, stepInformation }) {
11
+ const { formatMessage } = useIntl();
12
+ const { watch } = useFormContext();
13
+ const context = use(QxContext);
14
+ const queryables = watch("queryables");
15
+ const fieldNames = ["select.properties.fields"];
16
+
17
+ const fields = _.flow(
18
+ _.map.convert({ cap: false })((q, id) => ({ ...q, id })),
19
+ reduceQueryableFields(formatMessage)
20
+ )(queryables);
21
+
22
+ useEffect(() => {
23
+ if (!_.isEqual(stepInformation?.fieldNames, fieldNames)) {
24
+ setStepInformation(3, { ...stepInformation, fieldNames });
25
+ }
26
+ }, [fieldNames, stepInformation, setStepInformation]);
27
+
28
+ return (
29
+ <div>
30
+ <Grid>
31
+ <Grid.Column>
32
+ <Segment>
33
+ <Grid.Row className="vertical-space">
34
+ <QxContext
35
+ value={{
36
+ ...context,
37
+ field: `select.properties`,
38
+ fields,
39
+ }}
40
+ >
41
+ <Select />
42
+ </QxContext>
43
+ </Grid.Row>
44
+ </Segment>
45
+ </Grid.Column>
46
+ </Grid>
47
+ <Divider hidden />
48
+ </div>
49
+ );
50
+ }
@@ -0,0 +1,265 @@
1
+ import _ from "lodash/fp";
2
+ import { Fragment, useState } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Button, Divider, Grid, Icon, Form, Step } from "semantic-ui-react";
5
+ import { FormProvider, useForm, useFieldArray } from "react-hook-form";
6
+ import { useIntl } from "react-intl";
7
+ import QxContext from "@truedat/qx/components/QxContext";
8
+ import InformationForm from "./InformationForm";
9
+ import DatasetForm from "./DatasetForm";
10
+ import AggregationForm from "./AggregationForm";
11
+ import SelectionForm from "./SelectionForm";
12
+ import CancelButton from "../actions/CancelButton";
13
+
14
+ export default function SimpleDataViewEditor({
15
+ selectedDataView,
16
+ context,
17
+ onSubmit,
18
+ onCancel,
19
+ isSubmitting,
20
+ mode,
21
+ }) {
22
+ const form = useForm({
23
+ mode: "onTouched",
24
+ defaultValues: selectedDataView,
25
+ });
26
+
27
+ const [activeStep, setActiveStep] = useState(0);
28
+ const [stepInformation, setStepInformation] = useState({});
29
+ const [stepState, setStepState] = useState({});
30
+ const { formatMessage } = useIntl();
31
+ const { control, handleSubmit, watch, trigger } = form;
32
+
33
+ const { insert, remove } = useFieldArray({ control, name: "queryables" });
34
+
35
+ const isEditForm = !_.isNil(selectedDataView?.id);
36
+ const sourceId = watch("source_id");
37
+
38
+ const doSubmit = async (data) => {
39
+ const ok = await trigger();
40
+
41
+ if (ok) {
42
+ const queryables = _.propOr([], "queryables")(data);
43
+ onSubmit({ ...data, mode, queryables });
44
+ }
45
+ };
46
+ const updateStepInformation = (key, data) =>
47
+ setStepInformation({ ...stepInformation, [key]: data });
48
+
49
+ const updateStatusState = async (steps) => {
50
+ const validations = await Promise.all(
51
+ _.map.convert({ cap: false })(async (step) => {
52
+ const ok = await trigger(stepInformation[step]["fieldNames"], {
53
+ shouldFocus: true,
54
+ });
55
+ const content = ok ? { status: "valid" } : { status: "error" };
56
+ return [step, content];
57
+ })(steps)
58
+ );
59
+
60
+ setStepState({ ...stepState, ..._.fromPairs(validations) });
61
+ };
62
+
63
+ const moveToStep = async (step) => {
64
+ if (step < activeStep) {
65
+ await updateStatusState(_.range(0, activeStep + 1));
66
+ setActiveStep(step);
67
+ } else {
68
+ await updateStatusState(_.range(0, step));
69
+ const ok = await trigger(stepInformation[activeStep]["fieldNames"], {
70
+ shouldFocus: true,
71
+ });
72
+
73
+ if (ok) {
74
+ setActiveStep(step);
75
+ }
76
+ }
77
+ };
78
+
79
+ const stepProps = (step) => {
80
+ if (_.has(step)(stepInformation) && step !== activeStep)
81
+ return { link: true, onClick: () => moveToStep(step) };
82
+ return {};
83
+ };
84
+
85
+ const statusIcon = (step, defaultName) => {
86
+ const defaultIcon = { name: defaultName };
87
+
88
+ const status = stepState[step]?.status;
89
+ if (status === "valid") {
90
+ return { name: "check", color: "green" };
91
+ }
92
+
93
+ if (status === "error") {
94
+ return { name: "x", color: "red" };
95
+ }
96
+
97
+ return defaultIcon;
98
+ };
99
+
100
+ if (!selectedDataView) return null;
101
+
102
+ return (
103
+ <Fragment>
104
+ <Grid>
105
+ <Grid.Column width="12">
106
+ <Grid.Row textAlign="center">
107
+ <Step.Group>
108
+ <Step active={activeStep == 0} {...stepProps(0)}>
109
+ <Icon {...statusIcon(0, "info")} />
110
+ <Step.Content>
111
+ <Step.Title>
112
+ {formatMessage({
113
+ id: "dataViews.form.step.information.title",
114
+ })}
115
+ </Step.Title>
116
+ <Step.Description>
117
+ {formatMessage({
118
+ id: "dataViews.form.step.information.description",
119
+ })}
120
+ </Step.Description>
121
+ </Step.Content>
122
+ </Step>
123
+
124
+ <Step active={activeStep == 1} {...stepProps(1)}>
125
+ <Icon {...statusIcon(1, "database")} />
126
+ <Step.Content>
127
+ <Step.Title>
128
+ {formatMessage({ id: "dataViews.form.step.dataset.title" })}
129
+ </Step.Title>
130
+ <Step.Description>
131
+ {formatMessage({
132
+ id: "dataViews.form.step.dataset.description",
133
+ })}
134
+ </Step.Description>
135
+ </Step.Content>
136
+ </Step>
137
+
138
+ <Step active={activeStep == 2} {...stepProps(2)}>
139
+ <Icon {...statusIcon(2, "calculator")} />
140
+ <Step.Content>
141
+ <Step.Title>
142
+ {formatMessage({
143
+ id: "dataViews.form.step.aggregations.title",
144
+ })}
145
+ </Step.Title>
146
+ <Step.Description>
147
+ {formatMessage({
148
+ id: "dataViews.form.step.aggregations.description",
149
+ })}
150
+ </Step.Description>
151
+ </Step.Content>
152
+ </Step>
153
+ <Step active={activeStep == 3} {...stepProps(3)}>
154
+ <Icon {...statusIcon(3, "columns")} />
155
+ <Step.Content>
156
+ <Step.Title>
157
+ {formatMessage({ id: "dataViews.form.step.select.title" })}
158
+ </Step.Title>
159
+ <Step.Description>
160
+ {formatMessage({
161
+ id: "dataViews.form.step.select.description",
162
+ })}
163
+ </Step.Description>
164
+ </Step.Content>
165
+ </Step>
166
+ </Step.Group>
167
+ </Grid.Row>
168
+ <Divider hidden />
169
+ <Grid.Row>
170
+ <FormProvider {...form}>
171
+ <Form>
172
+ <div style={{ display: activeStep == 0 ? "block" : "none" }}>
173
+ <InformationForm
174
+ isEditForm={isEditForm}
175
+ stepInformation={stepInformation[0]}
176
+ setStepInformation={updateStepInformation}
177
+ />
178
+ </div>
179
+ {!_.isNil(sourceId) && (
180
+ <QxContext value={{ ...context, sourceId }}>
181
+ <div
182
+ style={{ display: activeStep == 1 ? "block" : "none" }}
183
+ >
184
+ <DatasetForm
185
+ insert={insert}
186
+ remove={remove}
187
+ stepInformation={stepInformation[1]}
188
+ stepState={stepState[1]}
189
+ setStepInformation={updateStepInformation}
190
+ />
191
+ </div>
192
+ <div
193
+ style={{ display: activeStep == 2 ? "block" : "none" }}
194
+ >
195
+ <AggregationForm
196
+ insert={insert}
197
+ remove={remove}
198
+ stepInformation={stepInformation[2]}
199
+ setStepInformation={updateStepInformation}
200
+ />
201
+ </div>
202
+ <div
203
+ style={{ display: activeStep == 3 ? "block" : "none" }}
204
+ >
205
+ <SelectionForm
206
+ stepInformation={stepInformation[3]}
207
+ setStepInformation={updateStepInformation}
208
+ />
209
+ </div>
210
+ </QxContext>
211
+ )}
212
+ {activeStep === 3 && (
213
+ <>
214
+ <Button
215
+ floated="right"
216
+ content={formatMessage({ id: "actions.save" })}
217
+ primary
218
+ disabled={isSubmitting}
219
+ onClick={handleSubmit((data) => doSubmit(data))}
220
+ />
221
+ </>
222
+ )}
223
+ {activeStep < 3 && (
224
+ <>
225
+ <Button
226
+ content={formatMessage({
227
+ id: "dataViews.action.forward",
228
+ })}
229
+ floated="right"
230
+ primary
231
+ disabled={isSubmitting}
232
+ onClick={() => moveToStep(activeStep + 1)}
233
+ />
234
+ </>
235
+ )}
236
+ {activeStep > 0 && (
237
+ <>
238
+ <Button
239
+ floated="right"
240
+ content={formatMessage({ id: "dataViews.action.back" })}
241
+ onClick={() => moveToStep(activeStep - 1)}
242
+ />
243
+ </>
244
+ )}
245
+ <CancelButton
246
+ onConfirm={() => onCancel()}
247
+ disabled={isSubmitting}
248
+ />
249
+ </Form>
250
+ </FormProvider>
251
+ </Grid.Row>
252
+ </Grid.Column>
253
+ </Grid>
254
+ </Fragment>
255
+ );
256
+ }
257
+
258
+ SimpleDataViewEditor.propTypes = {
259
+ selectedDataView: PropTypes.object,
260
+ context: PropTypes.object,
261
+ onSubmit: PropTypes.func,
262
+ onCancel: PropTypes.func,
263
+ isSubmitting: PropTypes.bool,
264
+ mode: PropTypes.string,
265
+ };