@truedat/qx 7.13.7 → 7.13.8

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
@@ -60,38 +60,42 @@ exports[`<Queryables /> matches the latest snapshot with from queryable 1`] = `
60
60
  queryables.form.resource
61
61
  </label>
62
62
  <div
63
- aria-expanded="false"
64
- class="ui selection dropdown"
65
- role="listbox"
66
- tabindex="0"
63
+ class="field"
67
64
  >
68
65
  <div
69
- aria-atomic="true"
70
- aria-live="polite"
71
- class="divider default text"
72
- role="alert"
73
- >
74
- queryables.resource.type
75
- </div>
76
- <i
77
- aria-hidden="true"
78
- class="dropdown icon"
79
- />
80
- <div
81
- class="menu transition"
66
+ aria-expanded="false"
67
+ class="ui selection dropdown"
68
+ role="listbox"
69
+ tabindex="0"
82
70
  >
83
71
  <div
84
- aria-checked="false"
85
- aria-selected="true"
86
- class="selected item"
87
- role="option"
88
- style="pointer-events: all;"
72
+ aria-atomic="true"
73
+ aria-live="polite"
74
+ class="divider default text"
75
+ role="alert"
89
76
  >
90
- <span
91
- class="text"
77
+ queryables.resource.type
78
+ </div>
79
+ <i
80
+ aria-hidden="true"
81
+ class="dropdown icon"
82
+ />
83
+ <div
84
+ class="menu transition"
85
+ >
86
+ <div
87
+ aria-checked="false"
88
+ aria-selected="true"
89
+ class="selected item"
90
+ role="option"
91
+ style="pointer-events: all;"
92
92
  >
93
- queryables.resource.type.data_structure
94
- </span>
93
+ <span
94
+ class="text"
95
+ >
96
+ queryables.resource.type.data_structure
97
+ </span>
98
+ </div>
95
99
  </div>
96
100
  </div>
97
101
  </div>
@@ -202,11 +206,19 @@ exports[`<Queryables /> matches the latest snapshot with from queryable 2`] = `
202
206
  class="item"
203
207
  role="listitem"
204
208
  >
205
- <button
206
- class="ui button"
209
+ <div
210
+ class="ui medium basic buttons"
207
211
  >
208
- queryables.group_by.form.add_group_field
209
- </button>
212
+ <button
213
+ class="ui button"
214
+ >
215
+ <i
216
+ aria-hidden="true"
217
+ class="plus icon"
218
+ />
219
+ queryables.group_by.form.add_group_field
220
+ </button>
221
+ </div>
210
222
  </div>
211
223
  </div>
212
224
  </div>
@@ -224,11 +236,19 @@ exports[`<Queryables /> matches the latest snapshot with from queryable 2`] = `
224
236
  class="item"
225
237
  role="listitem"
226
238
  >
227
- <button
228
- class="ui button"
239
+ <div
240
+ class="ui medium basic buttons"
229
241
  >
230
- queryables.group_by.form.add_aggregate_field
231
- </button>
242
+ <button
243
+ class="ui button"
244
+ >
245
+ <i
246
+ aria-hidden="true"
247
+ class="plus icon"
248
+ />
249
+ queryables.group_by.form.add_aggregate_field
250
+ </button>
251
+ </div>
232
252
  </div>
233
253
  </div>
234
254
  </div>
@@ -331,38 +351,42 @@ exports[`<Queryables /> matches the latest snapshot with join queryable 1`] = `
331
351
  queryables.form.resource
332
352
  </label>
333
353
  <div
334
- aria-expanded="false"
335
- class="ui selection dropdown"
336
- role="listbox"
337
- tabindex="0"
354
+ class="field"
338
355
  >
339
356
  <div
340
- aria-atomic="true"
341
- aria-live="polite"
342
- class="divider default text"
343
- role="alert"
344
- >
345
- queryables.resource.type
346
- </div>
347
- <i
348
- aria-hidden="true"
349
- class="dropdown icon"
350
- />
351
- <div
352
- class="menu transition"
357
+ aria-expanded="false"
358
+ class="ui selection dropdown"
359
+ role="listbox"
360
+ tabindex="0"
353
361
  >
354
362
  <div
355
- aria-checked="false"
356
- aria-selected="true"
357
- class="selected item"
358
- role="option"
359
- style="pointer-events: all;"
363
+ aria-atomic="true"
364
+ aria-live="polite"
365
+ class="divider default text"
366
+ role="alert"
360
367
  >
361
- <span
362
- class="text"
368
+ queryables.resource.type
369
+ </div>
370
+ <i
371
+ aria-hidden="true"
372
+ class="dropdown icon"
373
+ />
374
+ <div
375
+ class="menu transition"
376
+ >
377
+ <div
378
+ aria-checked="false"
379
+ aria-selected="true"
380
+ class="selected item"
381
+ role="option"
382
+ style="pointer-events: all;"
363
383
  >
364
- queryables.resource.type.data_structure
365
- </span>
384
+ <span
385
+ class="text"
386
+ >
387
+ queryables.resource.type.data_structure
388
+ </span>
389
+ </div>
366
390
  </div>
367
391
  </div>
368
392
  </div>
@@ -379,7 +403,6 @@ exports[`<Queryables /> matches the latest snapshot with join queryable 1`] = `
379
403
  <div
380
404
  aria-expanded="false"
381
405
  class="ui selection dropdown select-field-dropdown"
382
- label="dataViews.form.queryable.alias"
383
406
  role="listbox"
384
407
  tabindex="0"
385
408
  >
@@ -536,11 +559,19 @@ exports[`<Queryables /> matches the latest snapshot with join queryable 1`] = `
536
559
  <div
537
560
  class="ui horizontal divider"
538
561
  >
539
- <button
540
- class="ui mini button"
562
+ <div
563
+ class="ui medium basic buttons"
541
564
  >
542
- expression.clause.action.addGroup
543
- </button>
565
+ <button
566
+ class="ui button"
567
+ >
568
+ <i
569
+ aria-hidden="true"
570
+ class="plus icon"
571
+ />
572
+ expression.clause.action.addGroup
573
+ </button>
574
+ </div>
544
575
  </div>
545
576
  </div>
546
577
  </div>
@@ -757,38 +788,42 @@ exports[`<Queryables /> test delete queryable 1`] = `
757
788
  queryables.form.resource
758
789
  </label>
759
790
  <div
760
- aria-expanded="false"
761
- class="ui selection dropdown"
762
- role="listbox"
763
- tabindex="0"
791
+ class="field"
764
792
  >
765
793
  <div
766
- aria-atomic="true"
767
- aria-live="polite"
768
- class="divider default text"
769
- role="alert"
770
- >
771
- queryables.resource.type
772
- </div>
773
- <i
774
- aria-hidden="true"
775
- class="dropdown icon"
776
- />
777
- <div
778
- class="menu transition"
794
+ aria-expanded="false"
795
+ class="ui selection dropdown"
796
+ role="listbox"
797
+ tabindex="0"
779
798
  >
780
799
  <div
781
- aria-checked="false"
782
- aria-selected="true"
783
- class="selected item"
784
- role="option"
785
- style="pointer-events: all;"
800
+ aria-atomic="true"
801
+ aria-live="polite"
802
+ class="divider default text"
803
+ role="alert"
804
+ >
805
+ queryables.resource.type
806
+ </div>
807
+ <i
808
+ aria-hidden="true"
809
+ class="dropdown icon"
810
+ />
811
+ <div
812
+ class="menu transition"
786
813
  >
787
- <span
788
- class="text"
814
+ <div
815
+ aria-checked="false"
816
+ aria-selected="true"
817
+ class="selected item"
818
+ role="option"
819
+ style="pointer-events: all;"
789
820
  >
790
- queryables.resource.type.data_structure
791
- </span>
821
+ <span
822
+ class="text"
823
+ >
824
+ queryables.resource.type.data_structure
825
+ </span>
826
+ </div>
792
827
  </div>
793
828
  </div>
794
829
  </div>
@@ -0,0 +1,33 @@
1
+ import { Button } from "semantic-ui-react";
2
+ import { useIntl } from "react-intl";
3
+ import PropTypes from "prop-types";
4
+ import { ConfirmModal } from "@truedat/core/components";
5
+
6
+ export const CancelButton = ({ onConfirm, disabled }) => {
7
+ const { formatMessage } = useIntl();
8
+ return (
9
+ <ConfirmModal
10
+ trigger={
11
+ <Button
12
+ floated="right"
13
+ secondary
14
+ content={formatMessage({ id: "actions.cancel" })}
15
+ disabled={disabled}
16
+ />
17
+ }
18
+ header={formatMessage({ id: "actions.discard.confirmation.header" })}
19
+ size="small"
20
+ content={formatMessage({ id: "actions.discard.confirmation.content" })}
21
+ onConfirm={() => onConfirm()}
22
+ onOpen={(e) => e.stopPropagation()}
23
+ onClose={(e) => e.stopPropagation()}
24
+ />
25
+ );
26
+ };
27
+
28
+ CancelButton.propTypes = {
29
+ onConfirm: PropTypes.func,
30
+ disabled: PropTypes.bool,
31
+ };
32
+
33
+ export default CancelButton;
@@ -0,0 +1,33 @@
1
+ import { Button } from "semantic-ui-react";
2
+ import { useIntl } from "react-intl";
3
+ import PropTypes from "prop-types";
4
+ import { ConfirmModal } from "@truedat/core/components";
5
+
6
+ export const DeleteButton = ({ disabled, onConfirm, style = {} }) => {
7
+ const { formatMessage } = useIntl();
8
+
9
+ return (
10
+ <ConfirmModal
11
+ trigger={
12
+ <Button
13
+ icon="trash alternate outline"
14
+ basic
15
+ color="red"
16
+ disabled={disabled}
17
+ />
18
+ }
19
+ header={formatMessage({ id: "dataViews.action.delete.header" })}
20
+ content={formatMessage({ id: "dataViews.action.delete.content" })}
21
+ onConfirm={onConfirm}
22
+ onOpen={(e) => e.stopPropagation()}
23
+ onClose={(e) => e.stopPropagation()}
24
+ />
25
+ );
26
+ };
27
+
28
+ DeleteButton.propTypes = {
29
+ onConfirm: PropTypes.func,
30
+ disabled: PropTypes.bool,
31
+ };
32
+
33
+ export default DeleteButton;
@@ -0,0 +1,159 @@
1
+ import _ from "lodash/fp";
2
+ import { lazy, Fragment } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import {
6
+ Button,
7
+ Container,
8
+ Divider,
9
+ Grid,
10
+ Header,
11
+ Form,
12
+ } from "semantic-ui-react";
13
+ import { FormProvider, useForm, Controller } from "react-hook-form";
14
+ import QxContext from "@truedat/qx/components/QxContext";
15
+ import DataViewSelect from "./DataViewSelect";
16
+ import Queryables from "./Queryables";
17
+
18
+ const SourceSelector = lazy(
19
+ () => import("@truedat/cx/sources/components/SourceSelector")
20
+ );
21
+
22
+ export default function AdvancedDataViewEditor({
23
+ selectedDataView,
24
+ context,
25
+ onSubmit,
26
+ onCancel,
27
+ isSubmitting,
28
+ mode,
29
+ }) {
30
+ const { formatMessage } = useIntl();
31
+ const form = useForm({
32
+ mode: "onTouched",
33
+ defaultValues: selectedDataView,
34
+ });
35
+ const { control, handleSubmit, watch, formState } = form;
36
+ const { isDirty, isValid } = formState;
37
+
38
+ const isEditForm = !_.isNil(selectedDataView?.id);
39
+ const sourceId = watch("source_id");
40
+ if (!selectedDataView) return null;
41
+
42
+ return (
43
+ <Fragment>
44
+ <FormProvider {...form}>
45
+ <Form>
46
+ <Header as="h3" dividing>
47
+ {watch("name") || formatMessage({ id: "dataViews.action.new" })}
48
+ </Header>
49
+ <Grid>
50
+ <Grid.Column>
51
+ <Grid.Row className="vertical-space">
52
+ <Controller
53
+ control={control}
54
+ name="name"
55
+ rules={{
56
+ required: formatMessage(
57
+ { id: "form.validation.required" },
58
+ { prop: formatMessage({ id: "dataViews.form.name" }) }
59
+ ),
60
+ }}
61
+ render={({
62
+ field: { onBlur, onChange, value },
63
+ fieldState: { error },
64
+ }) => (
65
+ <Form.Field required>
66
+ <label>{formatMessage({ id: "group.props.name" })}</label>
67
+ <Form.Input
68
+ autoComplete="off"
69
+ placeholder={formatMessage({
70
+ id: "dataViews.form.name",
71
+ })}
72
+ error={error?.message}
73
+ onBlur={onBlur}
74
+ onChange={(_e, { value }) => onChange(value)}
75
+ value={value}
76
+ />
77
+ </Form.Field>
78
+ )}
79
+ />
80
+ </Grid.Row>
81
+ <Grid.Row className="vertical-space">
82
+ <Controller
83
+ control={control}
84
+ name="description"
85
+ render={({
86
+ field: { onBlur, onChange, value },
87
+ fieldState: { error },
88
+ }) => (
89
+ <Form.Field>
90
+ <label>
91
+ {formatMessage({ id: "dataViews.form.description" })}
92
+ </label>
93
+ <Form.Input
94
+ autoComplete="off"
95
+ placeholder={formatMessage({
96
+ id: "dataViews.form.description",
97
+ })}
98
+ error={error?.message}
99
+ onBlur={onBlur}
100
+ onChange={(_e, { value }) => onChange(value)}
101
+ value={value}
102
+ />
103
+ </Form.Field>
104
+ )}
105
+ />
106
+ </Grid.Row>
107
+ </Grid.Column>
108
+ </Grid>
109
+ <Controller
110
+ control={control}
111
+ name="source_id"
112
+ rules={{ required: true }}
113
+ render={({ field: { onChange, value } }) => (
114
+ <Form.Field required>
115
+ <label>{formatMessage({ id: "dataViews.form.source" })}</label>
116
+ <SourceSelector
117
+ disabled={isEditForm}
118
+ value={value + ""}
119
+ onChange={(_e, { value }) => onChange(value)}
120
+ />
121
+ </Form.Field>
122
+ )}
123
+ />
124
+ {!_.isNil(sourceId) ? (
125
+ <QxContext value={{ ...context, sourceId }}>
126
+ <Queryables />
127
+ <DataViewSelect />
128
+ </QxContext>
129
+ ) : null}
130
+ <Divider hidden />
131
+ <Container textAlign="right">
132
+ <Button
133
+ content={formatMessage({ id: "actions.cancel" })}
134
+ disabled={isSubmitting}
135
+ onClick={onCancel}
136
+ />
137
+
138
+ <Button
139
+ onClick={handleSubmit((data) => onSubmit({ ...data, mode }))}
140
+ primary
141
+ loading={isSubmitting}
142
+ disabled={!isValid || !isDirty}
143
+ content={formatMessage({ id: "actions.save" })}
144
+ />
145
+ </Container>
146
+ </Form>
147
+ </FormProvider>
148
+ </Fragment>
149
+ );
150
+ }
151
+
152
+ AdvancedDataViewEditor.propTypes = {
153
+ selectedDataView: PropTypes.object,
154
+ context: PropTypes.object,
155
+ onSubmit: PropTypes.func,
156
+ onCancel: PropTypes.func,
157
+ isSubmitting: PropTypes.bool,
158
+ setDirty: PropTypes.func,
159
+ };
@@ -4,8 +4,8 @@ import { useIntl } from "react-intl";
4
4
  import { useFormContext } from "react-hook-form";
5
5
  import { Grid, Label, Segment } from "semantic-ui-react";
6
6
  import QxContext from "@truedat/qx/components/QxContext";
7
- import { Select } from "./queryableProperties";
8
- import { reduceQueryableFields } from "./queryableFunctions";
7
+ import { Select } from "../queryableProperties";
8
+ import { reduceQueryableFields } from "../queryableFunctions";
9
9
 
10
10
  export default function DataViewSelect() {
11
11
  const { formatMessage } = useIntl();
@@ -5,8 +5,8 @@ import { useIntl } from "react-intl";
5
5
  import { Controller, useFormContext } from "react-hook-form";
6
6
  import { Button, Grid, Form, Label, Segment } from "semantic-ui-react";
7
7
  import QxContext from "@truedat/qx/components/QxContext";
8
- import { From, GroupBy, Join, Select, Where } from "./queryableProperties";
9
- import { getColorById, reduceQueryableFields } from "./queryableFunctions";
8
+ import { From, GroupBy, Join, Select, Where } from "../queryableProperties";
9
+ import { getColorById, reduceQueryableFields } from "../queryableFunctions";
10
10
 
11
11
  const queryableComponents = {
12
12
  from: <From />,
@@ -85,3 +85,10 @@ export const getColorById = (id) =>
85
85
  "olive",
86
86
  "pink",
87
87
  ][id];
88
+
89
+ export const hasErrors = (fields, errors) => {
90
+ return _.any((f) => {
91
+ const error = _.get(f)(errors);
92
+ return !_.isEmpty(error);
93
+ })(fields);
94
+ };
@@ -2,7 +2,7 @@ import _ from "lodash/fp";
2
2
  import { use } from "react";
3
3
  import { useIntl } from "react-intl";
4
4
  import { useFieldArray, useFormState } from "react-hook-form";
5
- import { Button, Form, List, Popup } from "semantic-ui-react";
5
+ import { Button, Form, List, Label } from "semantic-ui-react";
6
6
  import QxContext from "@truedat/qx/components/QxContext";
7
7
  import { calculateGroupByFieldId } from "../queryableFunctions";
8
8
  import SelectField, { newSelectField } from "./SelectField";
@@ -44,11 +44,6 @@ export default function GroupBy() {
44
44
  "aggregate"
45
45
  );
46
46
 
47
- const addGroupFieldButton = (
48
- <Button onClick={() => appendGroupField(newSelectField(nextGroupId))}>
49
- {formatMessage({ id: "queryables.group_by.form.add_group_field" })}
50
- </Button>
51
- );
52
47
  return (
53
48
  <>
54
49
  <Form.Field required>
@@ -70,16 +65,15 @@ export default function GroupBy() {
70
65
  </List.Item>
71
66
  ))}
72
67
  <List.Item>
73
- {requiredError ? (
74
- <Popup
75
- content={requiredError}
76
- open
77
- pinned
78
- position="bottom center"
79
- trigger={addGroupFieldButton}
68
+ <Button.Group basic size="medium">
69
+ <Button
70
+ icon="plus"
71
+ onClick={() => appendGroupField(newSelectField(nextGroupId))}
72
+ content={formatMessage({ id: "queryables.group_by.form.add_group_field" })}
80
73
  />
81
- ) : (
82
- addGroupFieldButton
74
+ </Button.Group>
75
+ {requiredError && (
76
+ <Label content={requiredError} prompt pointing="left" />
83
77
  )}
84
78
  </List.Item>
85
79
  </List>
@@ -104,18 +98,20 @@ export default function GroupBy() {
104
98
  </List.Item>
105
99
  ))}
106
100
  <List.Item>
107
- <Button
108
- onClick={() =>
109
- appendAggregateField({
110
- ...newSelectField(nextAggregateId),
111
- expression: { shape: "function" },
112
- })
113
- }
114
- >
115
- {formatMessage({
116
- id: "queryables.group_by.form.add_aggregate_field",
117
- })}
118
- </Button>
101
+ <Button.Group basic size="medium">
102
+ <Button
103
+ icon="plus"
104
+ content={formatMessage({
105
+ id: "queryables.group_by.form.add_aggregate_field",
106
+ })}
107
+ onClick={() =>
108
+ appendAggregateField({
109
+ ...newSelectField(nextAggregateId),
110
+ expression: { shape: "function" },
111
+ })
112
+ }
113
+ />
114
+ </Button.Group>
119
115
  </List.Item>
120
116
  </List>
121
117
  </Form.Field>
@@ -44,9 +44,6 @@ export default function Join() {
44
44
  options={joinTypeOptions}
45
45
  onChange={(_e, { value }) => onChange(value)}
46
46
  onBlur={onBlur}
47
- label={formatMessage({
48
- id: "dataViews.form.queryable.alias",
49
- })}
50
47
  />
51
48
  </Form.Field>
52
49
  )}