@truedat/qx 5.17.2 → 5.17.3

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 (43) hide show
  1. package/package.json +3 -3
  2. package/src/api.js +24 -1
  3. package/src/components/QxRoutes.js +12 -5
  4. package/src/components/common/ClauseViewer.js +129 -0
  5. package/src/components/common/ResourceSelector.js +7 -2
  6. package/src/components/common/expressions/Clauses.js +15 -3
  7. package/src/components/common/expressions/Condition.js +8 -6
  8. package/src/components/common/expressions/ShapeSelector.js +18 -8
  9. package/src/components/common/expressions/__tests__/ShapeSelector.spec.js +2 -2
  10. package/src/components/dataViews/DataViewEditor.js +4 -3
  11. package/src/components/dataViews/__tests__/__snapshots__/DataViewEditor.spec.js.snap +2 -2
  12. package/src/components/dataViews/queryableFunctions.js +15 -9
  13. package/src/components/functions/FunctionEditor.js +3 -2
  14. package/src/components/functions/__tests__/__snapshots__/FunctionEditor.spec.js.snap +4 -4
  15. package/src/components/qualityControls/EditQualityControl.js +73 -0
  16. package/src/components/qualityControls/NewDraftQualityControl.js +77 -0
  17. package/src/components/qualityControls/NewQualityControl.js +81 -0
  18. package/src/components/qualityControls/QualityControl.js +93 -0
  19. package/src/components/qualityControls/QualityControlActions.js +67 -0
  20. package/src/components/qualityControls/QualityControlCrumbs.js +23 -0
  21. package/src/components/qualityControls/QualityControlEditor.js +271 -0
  22. package/src/components/qualityControls/QualityControlHeader.js +64 -0
  23. package/src/components/qualityControls/QualityControlHistory.js +81 -0
  24. package/src/components/qualityControls/QualityControlRoutes.js +84 -0
  25. package/src/components/qualityControls/QualityControlRow.js +24 -0
  26. package/src/components/qualityControls/QualityControlTabs.js +34 -0
  27. package/src/components/qualityControls/QualityControls.js +67 -0
  28. package/src/components/qualityControls/QualityControlsTable.js +139 -0
  29. package/src/components/qualityControls/ResultCriteria.js +120 -0
  30. package/src/components/qualityControls/ResultType.js +57 -0
  31. package/src/components/qualityControls/resultCriterias/Deviation.js +89 -0
  32. package/src/components/qualityControls/resultCriterias/ErrorsNumber.js +88 -0
  33. package/src/components/qualityControls/resultCriterias/Percentage.js +89 -0
  34. package/src/components/search/FilterDropdown.js +76 -0
  35. package/src/components/search/FilterItem.js +49 -0
  36. package/src/components/search/FilterMultilevelDropdown.js +200 -0
  37. package/src/components/search/HierarchyFilterDropdown.js +116 -0
  38. package/src/components/search/QualityControlFilters.js +60 -0
  39. package/src/components/search/QualityControlSelectedFilters.js +56 -0
  40. package/src/components/search/QualityControlsSearch.js +30 -0
  41. package/src/components/search/SearchContext.js +180 -0
  42. package/src/hooks/useQualityControls.js +74 -0
  43. package/src/styles/Expression.less +39 -4
@@ -0,0 +1,77 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import { FormattedMessage } from "react-intl";
4
+ import { useParams, useHistory } from "react-router-dom";
5
+ import { Container, Header, Icon, Segment } from "semantic-ui-react";
6
+ import { QUALITY_CONTROLS, linkTo } from "@truedat/core/routes";
7
+ import {
8
+ useQualityControlCreateDraft,
9
+ useQualityControl,
10
+ } from "../../hooks/useQualityControls";
11
+ import QualityControlEditor from "./QualityControlEditor";
12
+
13
+ export default function NewDraftQualityControl() {
14
+ const { id } = useParams();
15
+ const history = useHistory();
16
+ const { trigger, isMutating } = useQualityControlCreateDraft(id);
17
+
18
+ const { data, loading } = useQualityControl(id);
19
+ const qualityControl = data?.data;
20
+
21
+ const handlePublish = (qualityControl) =>
22
+ trigger({
23
+ quality_control: {
24
+ ...qualityControl,
25
+ status: "published",
26
+ },
27
+ }).then((data) => {
28
+ const id = _.prop("data.data.id")(data);
29
+ history.push(linkTo.QUALITY_CONTROL({ id }));
30
+ });
31
+ const handleSave = (qualityControl) => {
32
+ const resource = _.prop("resource")(qualityControl);
33
+ const validation = _.prop("validation")(qualityControl);
34
+ trigger({
35
+ quality_control: {
36
+ ...qualityControl,
37
+ status: "draft",
38
+ resource: _.conforms({ type: _.isNil })(resource) ? null : resource,
39
+ validation: _.isEqual([
40
+ {
41
+ expressions: [{ shape: "function", value: { isCondition: true } }],
42
+ },
43
+ ])(validation)
44
+ ? []
45
+ : validation,
46
+ },
47
+ }).then((data) => {
48
+ const id = _.prop("data.data.id")(data);
49
+ history.push(linkTo.QUALITY_CONTROL({ id }));
50
+ });
51
+ };
52
+ return (
53
+ <Segment floated="left" loading={isMutating || loading}>
54
+ <Container text>
55
+ <Header as="h2">
56
+ <Icon circular name="archive" />
57
+ <Header.Content>
58
+ <FormattedMessage id="quality_controls.new.header" />
59
+ <Header.Subheader>
60
+ <FormattedMessage id="quality_controls.new.subheader" />
61
+ </Header.Subheader>
62
+ </Header.Content>
63
+ </Header>
64
+ {qualityControl ? (
65
+ <QualityControlEditor
66
+ isModification
67
+ value={qualityControl}
68
+ onPublish={handlePublish}
69
+ onSave={handleSave}
70
+ onCancel={() => history.push(QUALITY_CONTROLS)}
71
+ isSubmitting={false}
72
+ />
73
+ ) : null}
74
+ </Container>
75
+ </Segment>
76
+ );
77
+ }
@@ -0,0 +1,81 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import { FormattedMessage } from "react-intl";
4
+ import { useHistory } from "react-router-dom";
5
+ import { Container, Header, Icon, Segment } from "semantic-ui-react";
6
+ import { QUALITY_CONTROLS, linkTo } from "@truedat/core/routes";
7
+ import { useQualityControlCreate } from "../../hooks/useQualityControls";
8
+ import QualityControlEditor from "./QualityControlEditor";
9
+
10
+ export default function NewQualityControl() {
11
+ const history = useHistory();
12
+ const { trigger, isMutating } = useQualityControlCreate();
13
+
14
+ const handlePublish = (qualityControl) =>
15
+ trigger({
16
+ quality_control: {
17
+ ...qualityControl,
18
+ status: "published",
19
+ },
20
+ }).then((data) => {
21
+ const id = _.prop("data.data.id")(data);
22
+ history.push(linkTo.QUALITY_CONTROL({ id }));
23
+ });
24
+ const handleSave = (qualityControl) => {
25
+ const resource = _.prop("resource")(qualityControl);
26
+ const validation = _.prop("validation")(qualityControl);
27
+ trigger({
28
+ quality_control: {
29
+ ...qualityControl,
30
+ status: "draft",
31
+ resource: _.conforms({ type: _.isNil })(resource) ? null : resource,
32
+ validation: _.isEqual([
33
+ {
34
+ expressions: [{ shape: "function", value: { isCondition: true } }],
35
+ },
36
+ ])(validation)
37
+ ? []
38
+ : validation,
39
+ },
40
+ }).then((data) => {
41
+ const id = _.prop("data.data.id")(data);
42
+ history.push(linkTo.QUALITY_CONTROL({ id }));
43
+ });
44
+ };
45
+
46
+ return (
47
+ <Segment floated="left" loading={isMutating}>
48
+ <Container text>
49
+ <Header as="h2">
50
+ <Icon circular name="archive" />
51
+ <Header.Content>
52
+ <FormattedMessage id="quality_controls.new.header" />
53
+ <Header.Subheader>
54
+ <FormattedMessage id="quality_controls.new.subheader" />
55
+ </Header.Subheader>
56
+ </Header.Content>
57
+ </Header>
58
+ <QualityControlEditor
59
+ value={{
60
+ name: "",
61
+ domain_ids: [],
62
+ // df_content: {},
63
+ df_type: null,
64
+ validation: [
65
+ {
66
+ expressions: [
67
+ { shape: "function", value: { isCondition: true } },
68
+ ],
69
+ },
70
+ ],
71
+ }}
72
+ isModification={false}
73
+ onPublish={handlePublish}
74
+ onSave={handleSave}
75
+ onCancel={() => history.push(QUALITY_CONTROLS)}
76
+ isSubmitting={false}
77
+ />
78
+ </Container>
79
+ </Segment>
80
+ );
81
+ }
@@ -0,0 +1,93 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useContext } from "react";
3
+ import { FormattedMessage } from "react-intl";
4
+ import { Header, Icon, Segment, List, Label } from "semantic-ui-react";
5
+
6
+ import ClauseViewer from "@truedat/qx/components/common/ClauseViewer";
7
+ import QxContext from "../QxContext";
8
+ import ResultCriteria from "./ResultCriteria";
9
+
10
+ const DynamicFormViewer = React.lazy(() =>
11
+ import("@truedat/df/components/DynamicFormViewer")
12
+ );
13
+
14
+ export default function QualityControl() {
15
+ const { qualityControl } = useContext(QxContext);
16
+ return (
17
+ <>
18
+ <List size="big" relaxed>
19
+ <List.Item>
20
+ <List.Header>
21
+ <FormattedMessage id="quality_control.form.domain_ids" />{" "}
22
+ {_.map((domain) => <Label key={domain.id}>{domain.name}</Label>)(
23
+ qualityControl.domains
24
+ )}
25
+ </List.Header>
26
+ </List.Item>
27
+ </List>
28
+ <ResultCriteria qualityControl={qualityControl} />
29
+ {qualityControl.df_type ? (
30
+ <>
31
+ <Header as="h3">
32
+ <Icon name="info" size="small" />
33
+ <Header.Content>
34
+ <FormattedMessage id="quality_control.form.information" />
35
+ </Header.Content>
36
+ </Header>
37
+ <DynamicFormViewer
38
+ boxLayout
39
+ template={qualityControl.df_type}
40
+ content={qualityControl.df_content}
41
+ />
42
+ </>
43
+ ) : null}
44
+ <>
45
+ <Header as="h3">
46
+ <Icon name="puzzle piece" size="small" />
47
+ <Header.Content>
48
+ <FormattedMessage id="quality_control.form.implementation" />
49
+ </Header.Content>
50
+ </Header>
51
+ <Segment>
52
+ <List>
53
+ <List.Item>
54
+ <List.Header>
55
+ <FormattedMessage id="quality_control.form.dataset" />
56
+ </List.Header>
57
+ <List.Content>
58
+ {qualityControl.resource ? (
59
+ <List.Description>
60
+ <Label horizontal>
61
+ <FormattedMessage
62
+ id={`queryables.resource.selector.${qualityControl.resource?.type}`}
63
+ />
64
+ </Label>
65
+ <Label color="blue">
66
+ {_.prop("resource.embedded.name")(qualityControl)}
67
+ </Label>
68
+ </List.Description>
69
+ ) : (
70
+ <FormattedMessage id="quality_control.form.dataset.empty" />
71
+ )}
72
+ </List.Content>
73
+ </List.Item>
74
+ <List.Item>
75
+ <List.Header>
76
+ <FormattedMessage id="quality_control.form.validation" />
77
+ </List.Header>
78
+ <List.Content>
79
+ {qualityControl.validation ? (
80
+ <List.Description>
81
+ <ClauseViewer clause={qualityControl.validation} />
82
+ </List.Description>
83
+ ) : (
84
+ <FormattedMessage id="quality_control.form.validation.empty" />
85
+ )}
86
+ </List.Content>
87
+ </List.Item>
88
+ </List>
89
+ </Segment>
90
+ </>
91
+ </>
92
+ );
93
+ }
@@ -0,0 +1,67 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import { Link } from "react-router-dom";
6
+ import { Button, Container } from "semantic-ui-react";
7
+ import { linkTo } from "@truedat/core/routes";
8
+ import { useQualityControlUpdateStatus } from "../../hooks/useQualityControls";
9
+
10
+ export default function QualityControlActions({
11
+ actions,
12
+ qualityControl,
13
+ mutate,
14
+ }) {
15
+ const { formatMessage } = useIntl();
16
+ const { trigger, isMutating } = useQualityControlUpdateStatus(
17
+ qualityControl.id
18
+ );
19
+
20
+ const updateStatus = (action) => trigger({ action }).then(() => mutate());
21
+
22
+ return (
23
+ <Container textAlign="right">
24
+ {_.map((action) =>
25
+ action === "create_draft" ? (
26
+ <Button
27
+ key={action}
28
+ primary
29
+ as={Link}
30
+ disabled={isMutating}
31
+ to={linkTo.QUALITY_CONTROL_NEW_DRAFT(qualityControl)}
32
+ content={formatMessage({
33
+ id: `quality_controls.actions.${action}`,
34
+ })}
35
+ />
36
+ ) : action === "edit" ? (
37
+ <Button
38
+ key={action}
39
+ primary
40
+ as={Link}
41
+ disabled={isMutating}
42
+ to={linkTo.QUALITY_CONTROL_EDIT(qualityControl)}
43
+ content={formatMessage({
44
+ id: `quality_controls.actions.${action}`,
45
+ })}
46
+ />
47
+ ) : (
48
+ <Button
49
+ key={action}
50
+ primary
51
+ disabled={isMutating}
52
+ onClick={() => updateStatus(action)}
53
+ content={formatMessage({
54
+ id: `quality_controls.actions.${action}`,
55
+ })}
56
+ />
57
+ )
58
+ )(actions)}
59
+ </Container>
60
+ );
61
+ }
62
+
63
+ QualityControlActions.propTypes = {
64
+ actions: PropTypes.arrayOf(PropTypes.string),
65
+ qualityControl: PropTypes.object,
66
+ mutate: PropTypes.func,
67
+ };
@@ -0,0 +1,23 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { Breadcrumb } from "semantic-ui-react";
4
+ import { Link } from "react-router-dom";
5
+ import { FormattedMessage } from "react-intl";
6
+ import { QUALITY_CONTROLS } from "@truedat/core/routes";
7
+
8
+ export default function QualityControlCrumbs({ qualityControl }) {
9
+ return (
10
+ <Breadcrumb>
11
+ <Breadcrumb.Section as={Link} to={QUALITY_CONTROLS} active={false}>
12
+ <FormattedMessage id="quality_controls.header" />
13
+ </Breadcrumb.Section>
14
+
15
+ <Breadcrumb.Divider icon="right angle" />
16
+ <Breadcrumb.Section active>{qualityControl.name}</Breadcrumb.Section>
17
+ </Breadcrumb>
18
+ );
19
+ }
20
+
21
+ QualityControlCrumbs.propTypes = {
22
+ qualityControl: PropTypes.object,
23
+ };
@@ -0,0 +1,271 @@
1
+ import _ from "lodash/fp";
2
+ import React, { Fragment } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { useIntl } from "react-intl";
5
+ import { useQuery } from "@apollo/client";
6
+ import { Button, Container, Divider, Form } from "semantic-ui-react";
7
+ import { FormProvider, useForm, Controller } from "react-hook-form";
8
+ import {
9
+ ConfirmModal,
10
+ DomainSelector,
11
+ FieldLabel,
12
+ } from "@truedat/core/components";
13
+ import { lowerDeburrTrim } from "@truedat/core/services/sort";
14
+ import useActionDomains from "@truedat/core/hooks/useActionDomains";
15
+ import { REFERENCE_DATASETS_HEADERS_QUERY } from "@truedat/dd/api/queries";
16
+ import QxContext from "@truedat/qx/components/QxContext";
17
+ import { useDataViews } from "@truedat/qx/hooks/useDataViews";
18
+ import { useFunctions } from "@truedat/qx/hooks/useFunctions";
19
+ import ResourceSelector from "@truedat/qx/components/common/ResourceSelector";
20
+ import { Clauses } from "@truedat/qx/components/common/expressions";
21
+ import { fieldsFromResource } from "@truedat/qx/components/dataViews/queryableFunctions";
22
+ import ResultType from "./ResultType";
23
+
24
+ const SelectableDynamicForm = React.lazy(() =>
25
+ import("@truedat/df/components/SelectableDynamicForm")
26
+ );
27
+
28
+ export default function QualityControlEditor({
29
+ value,
30
+ onPublish,
31
+ onSave,
32
+ onCancel,
33
+ isModification,
34
+ isSubmitting,
35
+ }) {
36
+ const { formatMessage } = useIntl();
37
+ const { data: publishDomainsData, loading: loadingDomains } =
38
+ useActionDomains({
39
+ action: "publishQualityControls",
40
+ });
41
+ const publishDomains = _.propOr([], "domains")(publishDomainsData);
42
+ const form = useForm({
43
+ mode: "onTouched",
44
+ defaultValues: value,
45
+ });
46
+ const {
47
+ control,
48
+ handleSubmit,
49
+ formState,
50
+ watch,
51
+ setValue,
52
+ setError,
53
+ clearErrors,
54
+ } = form;
55
+ const { isDirty, isValid } = formState;
56
+
57
+ const { data, loading: dataViewsLoading } = useDataViews();
58
+ const { data: functionsData, loading: functionsLoading } = useFunctions();
59
+ const { data: referenceDatasetsData, loading: referenceDatasetsLoading } =
60
+ useQuery(REFERENCE_DATASETS_HEADERS_QUERY);
61
+
62
+ const loading =
63
+ dataViewsLoading || functionsLoading || referenceDatasetsLoading;
64
+
65
+ const submitLoading = isSubmitting || loadingDomains;
66
+
67
+ const dataViews = _.orderBy(["id"], ["asc"])(data?.data);
68
+ const functions = functionsData?.data;
69
+ const referenceDatasets = _.flow(
70
+ _.getOr([], "referenceDatasets"),
71
+ _.sortBy([({ name }) => lowerDeburrTrim(name), "name"]),
72
+ _.map((row) => ({ ...row, id: Number(row?.id) }))
73
+ )(referenceDatasetsData);
74
+
75
+ const context = {
76
+ dataViews,
77
+ referenceDatasets,
78
+ functions,
79
+ };
80
+
81
+ if (!value) return null;
82
+
83
+ const formData = watch();
84
+
85
+ const {
86
+ resource,
87
+ name,
88
+ df_content: dfContent,
89
+ domain_ids: domainIds,
90
+ } = formData;
91
+
92
+ const allowedToPublish = _.isEmpty(domainIds)
93
+ ? !_.isEmpty(publishDomains)
94
+ : _.every((domainId) => _.find({ id: `${domainId}` })(publishDomains))(
95
+ domainIds
96
+ );
97
+
98
+ const setDfContent = ({ content, valid }) => {
99
+ clearErrors("df_content");
100
+ if (!_.isEmpty(valid)) {
101
+ setError("df_content", { type: "invalidDfContent" });
102
+ setValue("df_content", content);
103
+ } else {
104
+ setValue("df_content", content, {
105
+ shouldValidate: true,
106
+ shouldDirty: true,
107
+ });
108
+ }
109
+ };
110
+ const fields = fieldsFromResource(
111
+ _.prop("embedded.name")(resource),
112
+ 0
113
+ )({ resource });
114
+
115
+ return (
116
+ <Fragment>
117
+ <FormProvider {...form}>
118
+ <Form loading={loading}>
119
+ <Controller
120
+ control={control}
121
+ name="name"
122
+ rules={{
123
+ required: formatMessage({ id: "form.validation.empty_required" }),
124
+ }}
125
+ render={({
126
+ field: { onBlur, onChange, value },
127
+ fieldState: { error },
128
+ }) => (
129
+ <FieldLabel
130
+ label={formatMessage({ id: "quality_control.form.name" })}
131
+ required
132
+ error={error?.message}
133
+ >
134
+ <Form.Input
135
+ autoComplete="off"
136
+ placeholder={formatMessage({ id: "dataViews.form.name" })}
137
+ error={!!error}
138
+ onBlur={onBlur}
139
+ onChange={(_e, { value }) => onChange(value)}
140
+ value={value}
141
+ />
142
+ </FieldLabel>
143
+ )}
144
+ />
145
+
146
+ {isModification ? null : (
147
+ <Controller
148
+ control={control}
149
+ name="domain_ids"
150
+ rules={{
151
+ required: formatMessage({
152
+ id: "form.validation.empty_required",
153
+ }),
154
+ }}
155
+ render={({
156
+ field: { onBlur, onChange, value },
157
+ fieldState: { error },
158
+ }) => (
159
+ <FieldLabel
160
+ label={formatMessage({
161
+ id: "quality_control.form.domain_ids",
162
+ })}
163
+ required
164
+ error={error?.message}
165
+ >
166
+ <DomainSelector
167
+ action="createQualityControls"
168
+ value={value}
169
+ error={!!error}
170
+ multiple
171
+ onBlur={onBlur}
172
+ onChange={(_e, { value }) => onChange(value)}
173
+ labels
174
+ />
175
+ </FieldLabel>
176
+ )}
177
+ />
178
+ )}
179
+ <ResultType />
180
+
181
+ <Controller
182
+ control={control}
183
+ name="df_type"
184
+ rules={{ required: true }}
185
+ render={({ field: { onChange, value } }) => (
186
+ <SelectableDynamicForm
187
+ scope="quality_control"
188
+ content={dfContent}
189
+ domainIds={domainIds}
190
+ isModification={isModification}
191
+ name={value}
192
+ onChange={setDfContent}
193
+ onNameChange={onChange}
194
+ required
195
+ />
196
+ )}
197
+ />
198
+
199
+ <QxContext.Provider value={{ ...context, field: "resource" }}>
200
+ <ResourceSelector required labelId="quality_control.form.dataset" />
201
+ </QxContext.Provider>
202
+ {resource?.id ? (
203
+ <div className="vertical-space">
204
+ <QxContext.Provider
205
+ value={{ ...context, fields, field: "validation" }}
206
+ >
207
+ <Clauses labelId="quality_control.form.validation" />
208
+ </QxContext.Provider>
209
+ </div>
210
+ ) : null}
211
+
212
+ <Divider hidden />
213
+ <Container textAlign="right">
214
+ {onPublish && allowedToPublish ? (
215
+ <Button
216
+ onClick={handleSubmit((data) => onPublish(data))}
217
+ primary
218
+ loading={submitLoading}
219
+ disabled={!isValid || !isDirty}
220
+ content={formatMessage({ id: "actions.publish" })}
221
+ />
222
+ ) : null}
223
+ {onSave ? (
224
+ <Button
225
+ onClick={() => onSave(formData)}
226
+ primary
227
+ loading={submitLoading}
228
+ disabled={!name || !isDirty}
229
+ content={formatMessage({ id: "actions.save" })}
230
+ />
231
+ ) : null}
232
+ {isDirty ? (
233
+ <ConfirmModal
234
+ trigger={
235
+ <Button
236
+ content={formatMessage({ id: "actions.cancel" })}
237
+ disabled={isSubmitting}
238
+ />
239
+ }
240
+ header={formatMessage({
241
+ id: "actions.discard.confirmation.header",
242
+ })}
243
+ content={formatMessage({
244
+ id: "actions.discard.confirmation.content",
245
+ })}
246
+ onConfirm={onCancel}
247
+ onOpen={(e) => e.stopPropagation()}
248
+ onClose={(e) => e.stopPropagation()}
249
+ />
250
+ ) : (
251
+ <Button
252
+ content={formatMessage({ id: "actions.cancel" })}
253
+ disabled={isSubmitting}
254
+ onClick={onCancel}
255
+ />
256
+ )}
257
+ </Container>
258
+ </Form>
259
+ </FormProvider>
260
+ </Fragment>
261
+ );
262
+ }
263
+
264
+ QualityControlEditor.propTypes = {
265
+ value: PropTypes.object,
266
+ onPublish: PropTypes.func,
267
+ onSave: PropTypes.func,
268
+ onCancel: PropTypes.func,
269
+ isSubmitting: PropTypes.bool,
270
+ isModification: PropTypes.bool,
271
+ };
@@ -0,0 +1,64 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { FormattedMessage } from "react-intl";
5
+ import { useParams } from "react-router-dom";
6
+ import { Header, Icon, Segment, Grid, Label } from "semantic-ui-react";
7
+ import { colorForStatus } from "@truedat/core/services/statusColor";
8
+
9
+ import { useQualityControl } from "../../hooks/useQualityControls";
10
+ import QxContext from "../QxContext";
11
+ import QualityControlCrumbs from "./QualityControlCrumbs";
12
+ import QualityControlActions from "./QualityControlActions";
13
+ import QualityControlTabs from "./QualityControlTabs";
14
+
15
+ export default function QualityControl({ children }) {
16
+ const { id } = useParams();
17
+ const { data, loading, mutate } = useQualityControl(id);
18
+
19
+ const qualityControl = _.propOr({}, "data")(data);
20
+ const actions = _.propOr([], "_actions")(data);
21
+ const context = { qualityControl, loading, id };
22
+
23
+ return (
24
+ <QxContext.Provider value={context}>
25
+ <QualityControlCrumbs qualityControl={qualityControl} />
26
+ <Segment loading={loading}>
27
+ {!_.isEmpty(qualityControl) ? (
28
+ <>
29
+ <Grid>
30
+ <Grid.Column width={8}>
31
+ <Header as="h2">
32
+ <Icon circular name="archive" />
33
+ <Header.Content>{qualityControl.name}</Header.Content>
34
+ </Header>
35
+ </Grid.Column>
36
+ <Grid.Column width={8}>
37
+ <QualityControlActions
38
+ actions={actions}
39
+ qualityControl={qualityControl}
40
+ mutate={mutate}
41
+ />
42
+ </Grid.Column>
43
+ </Grid>
44
+ <Label
45
+ className="float-right"
46
+ tag
47
+ color={colorForStatus(qualityControl.status)}
48
+ >
49
+ <FormattedMessage
50
+ id={`quality_control.status.${qualityControl.status}`}
51
+ />
52
+ </Label>
53
+ <QualityControlTabs />
54
+ {children}
55
+ </>
56
+ ) : null}
57
+ </Segment>
58
+ </QxContext.Provider>
59
+ );
60
+ }
61
+
62
+ QualityControl.propTypes = {
63
+ children: PropTypes.node,
64
+ };