@truedat/core 4.44.3 → 4.45.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.44.5] 2022-05-20
4
+
5
+ ### Changed
6
+
7
+ - [TD-4230] `TemplateSelector` GraphQL fetchPolicy changed to
8
+ `cache-and-network` and changed hidden logic
9
+
10
+ ## [4.44.4] 2022-05-19
11
+
12
+ ### Added
13
+
14
+ - [TD-4660] `lowerDeburrTrim` function, reference data routes and i18n messages
15
+
3
16
  ## [4.44.1] 2022-05-11
4
17
 
5
18
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "4.44.3",
3
+ "version": "4.45.0",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -17,23 +17,26 @@
17
17
  "scripts": {
18
18
  "clean": "rimraf yarn-error.log",
19
19
  "debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
20
- "test": "jest --coverage",
21
- "test:watch": "jest --watch",
20
+ "test": "TZ=UTC jest --coverage",
21
+ "test:watch": "TZ=UTC jest --watch",
22
22
  "eslint": "eslint src/**",
23
23
  "eslint:fix": "eslint --fix src/**"
24
24
  },
25
25
  "devDependencies": {
26
- "@babel/cli": "^7.14.8",
27
- "@babel/core": "^7.15.0",
28
- "@babel/plugin-proposal-class-properties": "^7.14.5",
29
- "@babel/plugin-proposal-object-rest-spread": "^7.14.7",
30
- "@babel/plugin-proposal-optional-chaining": "^7.14.5",
26
+ "@babel/cli": "^7.17.10",
27
+ "@babel/core": "^7.18.0",
28
+ "@babel/plugin-proposal-class-properties": "^7.17.12",
29
+ "@babel/plugin-proposal-object-rest-spread": "^7.18.0",
30
+ "@babel/plugin-proposal-optional-chaining": "^7.17.12",
31
31
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
32
- "@babel/plugin-transform-modules-commonjs": "^7.15.0",
33
- "@babel/preset-env": "^7.15.0",
34
- "@babel/preset-react": "^7.14.5",
35
- "@truedat/test": "4.44.3",
36
- "babel-jest": "^27.0.6",
32
+ "@babel/plugin-transform-modules-commonjs": "^7.18.0",
33
+ "@babel/preset-env": "^7.18.0",
34
+ "@babel/preset-react": "^7.17.12",
35
+ "@testing-library/jest-dom": "^5.16.4",
36
+ "@testing-library/react": "^12.0.0",
37
+ "@testing-library/user-event": "^13.2.1",
38
+ "@truedat/test": "4.45.0",
39
+ "babel-jest": "^28.1.0",
37
40
  "babel-plugin-dynamic-import-node": "^2.3.3",
38
41
  "babel-plugin-lodash": "^3.3.4",
39
42
  "babel-plugin-react-intl": "^5.1.18",
@@ -41,7 +44,8 @@
41
44
  "enzyme": "^3.11.0",
42
45
  "enzyme-to-json": "^3.6.2",
43
46
  "identity-obj-proxy": "^3.0.0",
44
- "jest": "^27.0.6",
47
+ "jest": "^28.1.0",
48
+ "jest-environment-jsdom": "^28.1.0",
45
49
  "jest-localstorage-mock": "^2.4.14",
46
50
  "react": "^16.14.0",
47
51
  "react-dom": "^16.14.0",
@@ -50,6 +54,8 @@
50
54
  "semantic-ui-react": "^2.0.3"
51
55
  },
52
56
  "jest": {
57
+ "maxWorkers": "50%",
58
+ "testTimeout": 10000,
53
59
  "moduleDirectories": [
54
60
  "<rootDir>/src",
55
61
  "../../node_modules"
@@ -82,16 +88,16 @@
82
88
  }
83
89
  },
84
90
  "dependencies": {
85
- "@apollo/client": "^3.4.10",
91
+ "@apollo/client": "^3.6.4",
86
92
  "axios": "^0.19.2",
87
93
  "immutable": "^4.0.0-rc.12",
88
94
  "is-hotkey": "^0.1.6",
89
95
  "is-url": "^1.2.4",
90
- "prop-types": "^15.7.2",
96
+ "prop-types": "^15.8.1",
91
97
  "react-csv": "^2.2.2",
92
98
  "react-dropzone": "^4.2.13",
93
99
  "react-intl": "^5.20.10",
94
- "react-moment": "^0.9.7",
100
+ "react-moment": "^1.1.2",
95
101
  "react-redux": "^7.2.4",
96
102
  "react-router-dom": "^5.2.0",
97
103
  "redux": "^4.1.1",
@@ -106,5 +112,5 @@
106
112
  "react-dom": ">= 16.8.6 < 17",
107
113
  "semantic-ui-react": ">= 0.88.2 < 2.1"
108
114
  },
109
- "gitHead": "d5e72d523389c6e66d6f7168d7e3546b5d2ffdda"
115
+ "gitHead": "b8a49c6bae0bbde203dfb4763a5657fc398e3b7a"
110
116
  }
@@ -11,8 +11,8 @@ export const DOMAINS_QUERY = gql`
11
11
  `;
12
12
 
13
13
  export const TEMPLATES_QUERY = gql`
14
- query Templates($scope: String!) {
15
- templates(scope: $scope) {
14
+ query Templates($scope: String, $domainIds: [ID]) {
15
+ templates(scope: $scope, domainIds: $domainIds) {
16
16
  id
17
17
  name
18
18
  label
@@ -1,12 +1,12 @@
1
- import _ from "lodash/fp";
2
1
  import React from "react";
3
2
  import { useAuthorized } from "../hooks";
4
3
  import {
5
- STRUCTURES_UPLOAD_EVENTS,
6
4
  PENDING_STRUCTURE_NOTES,
5
+ REFERENCE_DATASETS,
6
+ STRUCTURES,
7
+ STRUCTURES_UPLOAD_EVENTS,
7
8
  STRUCTURE_TAGS,
8
9
  STRUCTURE_TYPES,
9
- STRUCTURES,
10
10
  SYSTEMS,
11
11
  } from "../routes";
12
12
  import Submenu from "./Submenu";
@@ -16,6 +16,7 @@ const items = [{ name: "structures", routes: [STRUCTURES, SYSTEMS] }];
16
16
  const adminItems = [
17
17
  { name: "structureTypes", routes: [STRUCTURE_TYPES] },
18
18
  { name: "structureTags", routes: [STRUCTURE_TAGS] },
19
+ { name: "referenceData", routes: [REFERENCE_DATASETS] },
19
20
  ];
20
21
 
21
22
  const structureNoteItems = [
@@ -27,7 +27,7 @@ export const TemplateSelector = ({
27
27
  }) => {
28
28
  const { formatMessage } = useIntl();
29
29
  const options = makeOptions(templates);
30
- const hidden = _.size(templates) <= 1;
30
+ const hidden = loading ? false : _.size(templates) <= 1;
31
31
 
32
32
  const handleChange = (e, { value, ...data }) => {
33
33
  const template = _.find({ id: value })(templates);
@@ -50,7 +50,9 @@ export const TemplateSelector = ({
50
50
  name={name}
51
51
  onChange={handleChange}
52
52
  options={options}
53
- placeholder={formatMessage({ id: "template.selector.placeholder" })}
53
+ placeholder={formatMessage({
54
+ id: loading ? "loading" : "template.selector.placeholder",
55
+ })}
54
56
  search
55
57
  selection
56
58
  value={_.toString(selectedValue)}
@@ -69,19 +71,27 @@ TemplateSelector.propTypes = {
69
71
  templates: PropTypes.array,
70
72
  };
71
73
 
72
- export const TemplateSelectorLoader = ({ scope, onLoad, ...props }) => {
74
+ const emptyTemplates = [];
75
+ export const TemplateSelectorLoader = ({
76
+ scope,
77
+ onLoad,
78
+ domainIds,
79
+ ...props
80
+ }) => {
73
81
  const { loading, error, data } = useQuery(TEMPLATES_QUERY, {
74
- variables: { scope },
82
+ fetchPolicy: "cache-and-network",
83
+ variables: { scope, domainIds },
75
84
  onCompleted: onLoad,
76
85
  });
77
86
  if (error) return null;
78
- const templates = data?.templates || [];
87
+ const templates = data?.templates || emptyTemplates;
79
88
  return (
80
89
  <TemplateSelector loading={loading} templates={templates} {...props} />
81
90
  );
82
91
  };
83
92
 
84
93
  TemplateSelectorLoader.propTypes = {
94
+ domainIds: PropTypes.array,
85
95
  scope: PropTypes.string.isRequired,
86
96
  onLoad: PropTypes.func,
87
97
  };
@@ -1,10 +1,12 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
2
+ import { render } from "@truedat/test/render";
3
3
  import { DateTime } from "..";
4
4
 
5
5
  describe("<DateTime />", () => {
6
6
  it("matches the latest snapshot", () => {
7
- const wrapper = shallow(<DateTime value="2018-06-27T07:32:53.154377Z" />);
8
- expect(wrapper).toMatchSnapshot();
7
+ const { container } = render(
8
+ <DateTime value="2018-06-27T07:32:53.154377Z" />
9
+ );
10
+ expect(container).toMatchSnapshot();
9
11
  });
10
12
  });
@@ -1,51 +1,80 @@
1
- import React, { Suspense } from "react";
2
- import { waitFor } from "@testing-library/react";
1
+ import React from "react";
2
+ import { waitForElementToBeRemoved } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
3
4
  import { render } from "@truedat/test/render";
4
- import { TEMPLATES_QUERY } from "@truedat/core/api/queries";
5
+ import {
6
+ errorTemplateMock,
7
+ multipleTemplatesMock,
8
+ singleTemplateMock,
9
+ } from "@truedat/test/mocks";
5
10
  import TemplateSelector from "../TemplateSelector";
6
11
 
7
12
  const scope = "foo";
8
- const templates = [
9
- {
10
- id: "1",
11
- name: "template1",
12
- label: "template1",
13
- content: [{ name: "g1", fields: [{ name: "field1", label: "field1" }] }],
14
- scope,
15
- },
16
- {
17
- id: "2",
18
- name: "template2",
19
- label: "template2",
20
- content: {},
21
- scope,
22
- },
23
- ];
24
- const templatesMock = {
25
- request: { query: TEMPLATES_QUERY, variables: { scope } },
26
- result: { data: { templates } },
27
- };
28
-
29
- const renderOpts = {
30
- mocks: [templatesMock],
31
- };
13
+ const domainIds = [1];
14
+ const variables = { scope, domainIds };
32
15
 
33
16
  describe("<TemplateSelector />", () => {
34
17
  const onChange = jest.fn();
35
- const onLoad = jest.fn();
36
- const props = { onChange, onLoad, scope: "foo" };
18
+ const props = { onChange, domainIds, scope };
19
+
20
+ it("matches the latest snapshot (loading)", () => {
21
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
22
+ const { container, queryByText } = render(
23
+ <TemplateSelector {...props} />,
24
+ renderOpts
25
+ );
26
+ expect(queryByText(/loading/i)).toBeInTheDocument();
27
+ expect(container).toMatchSnapshot();
28
+ });
37
29
 
38
30
  it("matches the latest snapshot", async () => {
31
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
32
+ const onLoad = jest.fn();
39
33
  const { container, queryByText } = render(
40
- <Suspense fallback="loading...">
41
- <TemplateSelector {...props} />
42
- </Suspense>,
34
+ <TemplateSelector {...props} onLoad={onLoad} />,
43
35
  renderOpts
44
36
  );
45
- await waitFor(() => {
46
- expect(queryByText(/template1/i)).toBeInTheDocument();
47
- });
37
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
38
+ expect(queryByText("template1")).toBeInTheDocument();
48
39
  expect(container).toMatchSnapshot();
49
40
  expect(onLoad.mock.calls.length).toBe(1);
50
41
  });
42
+
43
+ it("matches the latest snapshot when required", async () => {
44
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
45
+ const { container, queryByText } = render(
46
+ <TemplateSelector {...props} required />,
47
+ renderOpts
48
+ );
49
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
50
+ expect(queryByText("template1")).toBeInTheDocument();
51
+ expect(container).toMatchSnapshot();
52
+ });
53
+
54
+ it("is empty if templates query returns an error", async () => {
55
+ const renderOpts = { mocks: [errorTemplateMock(variables)] };
56
+ const { queryByText } = render(
57
+ <TemplateSelector {...props} required />,
58
+ renderOpts
59
+ );
60
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
61
+ expect(queryByText("template1")).not.toBeInTheDocument();
62
+ });
63
+
64
+ it("calls onChange when template is selected", async () => {
65
+ const renderOpts = { mocks: [multipleTemplatesMock(variables)] };
66
+ const { findByRole } = render(<TemplateSelector {...props} />, renderOpts);
67
+
68
+ userEvent.click(await findByRole("option", { name: "template1" }));
69
+ expect(onChange.mock.calls[0][1]).toMatchObject({
70
+ template: { id: "1", label: "template1" },
71
+ });
72
+ });
73
+
74
+ it("is empty when query returns a single template", async () => {
75
+ const renderOpts = { mocks: [singleTemplateMock(variables)] };
76
+ const { queryByText } = render(<TemplateSelector {...props} />, renderOpts);
77
+ await waitForElementToBeRemoved(() => queryByText(/loading/i));
78
+ expect(queryByText("template1")).not.toBeInTheDocument();
79
+ });
51
80
  });
@@ -68,6 +68,19 @@ exports[`<CatalogMenu /> matches the latest snapshot 1`] = `
68
68
  structureTags
69
69
  </span>
70
70
  </a>
71
+ <a
72
+ aria-checked="false"
73
+ class="item"
74
+ href="/referenceDatasets"
75
+ name="referenceData"
76
+ role="option"
77
+ >
78
+ <span
79
+ class="text"
80
+ >
81
+ referenceData
82
+ </span>
83
+ </a>
71
84
  <a
72
85
  aria-checked="false"
73
86
  class="item"
@@ -1,23 +1,11 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<DateTime /> matches the latest snapshot 1`] = `
4
- <t
5
- ago={false}
6
- calendar={false}
7
- date="2018-06-27T07:32:53.154377Z"
8
- decimal={false}
9
- element={null}
10
- filter={[Function]}
11
- format="YYYY-MM-DD HH:mm"
12
- fromNow={false}
13
- interval={60000}
14
- local={false}
15
- onChange={[Function]}
16
- titleFormat=""
17
- toNow={false}
18
- unit={null}
19
- unix={false}
20
- utc={false}
21
- withTitle={false}
22
- />
4
+ <div>
5
+ <time
6
+ datetime="1530084773154"
7
+ >
8
+ 2018-06-27 07:32
9
+ </time>
10
+ </div>
23
11
  `;
@@ -1,5 +1,59 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`<TemplateSelector /> matches the latest snapshot (loading) 1`] = `
4
+ <div>
5
+ <div
6
+ class="field"
7
+ >
8
+ <label>
9
+ Template
10
+ </label>
11
+ <div
12
+ class="field"
13
+ >
14
+ <div
15
+ aria-busy="true"
16
+ aria-expanded="false"
17
+ class="ui loading search selection dropdown"
18
+ name="template"
19
+ role="combobox"
20
+ >
21
+ <input
22
+ aria-autocomplete="list"
23
+ autocomplete="off"
24
+ class="search"
25
+ tabindex="0"
26
+ type="text"
27
+ value=""
28
+ />
29
+ <div
30
+ aria-atomic="true"
31
+ aria-live="polite"
32
+ class="divider default text"
33
+ role="alert"
34
+ >
35
+ loading...
36
+ </div>
37
+ <i
38
+ aria-hidden="true"
39
+ class="dropdown icon"
40
+ />
41
+ <div
42
+ class="menu transition"
43
+ role="listbox"
44
+ >
45
+ <div
46
+ class="message"
47
+ >
48
+ No results found.
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ `;
56
+
3
57
  exports[`<TemplateSelector /> matches the latest snapshot 1`] = `
4
58
  <div>
5
59
  <div
@@ -74,3 +128,83 @@ exports[`<TemplateSelector /> matches the latest snapshot 1`] = `
74
128
  </div>
75
129
  </div>
76
130
  `;
131
+
132
+ exports[`<TemplateSelector /> matches the latest snapshot when required 1`] = `
133
+ <div>
134
+ <div
135
+ class="required field"
136
+ >
137
+ <label>
138
+ Template
139
+ <div
140
+ class="ui left pointing label"
141
+ >
142
+ Empty required field
143
+ </div>
144
+ </label>
145
+ <div
146
+ class="field"
147
+ >
148
+ <div
149
+ aria-busy="false"
150
+ aria-expanded="false"
151
+ class="ui search selection dropdown"
152
+ name="template"
153
+ role="combobox"
154
+ >
155
+ <input
156
+ aria-autocomplete="list"
157
+ autocomplete="off"
158
+ class="search"
159
+ tabindex="0"
160
+ type="text"
161
+ value=""
162
+ />
163
+ <div
164
+ aria-atomic="true"
165
+ aria-live="polite"
166
+ class="divider default text"
167
+ role="alert"
168
+ >
169
+ Select a template...
170
+ </div>
171
+ <i
172
+ aria-hidden="true"
173
+ class="dropdown icon"
174
+ />
175
+ <div
176
+ class="menu transition"
177
+ role="listbox"
178
+ >
179
+ <div
180
+ aria-checked="false"
181
+ aria-selected="true"
182
+ class="selected item"
183
+ role="option"
184
+ style="pointer-events: all;"
185
+ >
186
+ <span
187
+ class="text"
188
+ >
189
+ template1
190
+ </span>
191
+ </div>
192
+ <div
193
+ aria-checked="false"
194
+ aria-selected="false"
195
+ class="item"
196
+ role="option"
197
+ style="pointer-events: all;"
198
+ >
199
+ <span
200
+ class="text"
201
+ >
202
+ template2
203
+ </span>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+ </div>
209
+ </div>
210
+ `;
@@ -4,6 +4,7 @@ export default {
4
4
  "actions.confirm": "Are you sure?",
5
5
  "actions.create": "Create",
6
6
  "actions.delete": "Delete",
7
+ "actions.download": "Download",
7
8
  "actions.edit": "Edit",
8
9
  "actions.next": "Next",
9
10
  "actions.prev": "Previous",
@@ -44,6 +45,7 @@ export default {
44
45
  filters: "Filters",
45
46
  "filters.class.raw.field": "Field",
46
47
  "filters.reset": "(reset all filters)",
48
+ loading: "loading...",
47
49
  "form.validation.required": "{prop} is required",
48
50
  "form.validation.minLength": "{prop} must have at least {value} characters",
49
51
  "form.validation.email.invalid": "Invalid email address",
@@ -91,6 +93,7 @@ export default {
91
93
  "sidemenu.pending_structure_notes": "Pending notes",
92
94
  "sidemenu.quality_dashboard": "Quality Dashboard",
93
95
  "sidemenu.quality": "Data Quality",
96
+ "sidemenu.referenceData": "Reference Data",
94
97
  "sidemenu.roles": "Roles",
95
98
  "sidemenu.rules": "Quality Rules",
96
99
  "sidemenu.search": "Search",
@@ -4,6 +4,7 @@ export default {
4
4
  "actions.confirm": "¿Estás seguro?",
5
5
  "actions.create": "Crear",
6
6
  "actions.delete": "Eliminar",
7
+ "actions.download": "Descargar",
7
8
  "actions.edit": "Editar",
8
9
  "actions.next": "Siguiente",
9
10
  "actions.prev": "Anterior",
@@ -48,6 +49,7 @@ export default {
48
49
  "form.validation.required": "{prop} es un campo requerido",
49
50
  "form.validation.minLength": "{prop} debe tener al menos {value} elementos",
50
51
  "form.validation.email.invalid": "Dirección de email inválida",
52
+ loading: "cargando...",
51
53
  "navigation.dashboard": "Dashboard",
52
54
  "navigation.menu": "Menú",
53
55
  "search.applied_filters": "Filtros aplicados:",
@@ -94,6 +96,7 @@ export default {
94
96
  "sidemenu.pending_structure_notes": "Notas pendientes",
95
97
  "sidemenu.quality_dashboard": "Dashboard de Calidad",
96
98
  "sidemenu.quality": "Calidad",
99
+ "sidemenu.referenceData": "Datos de referencia",
97
100
  "sidemenu.roles": "Roles",
98
101
  "sidemenu.rules": "Reglas",
99
102
  "sidemenu.search": "Búsqueda",
package/src/routes.js CHANGED
@@ -109,6 +109,10 @@ export const PROFILE_EXECUTION =
109
109
  "/profileGroups/:group_id/profileExecutions/:id";
110
110
  export const PROFILE_GROUP = "/profileGroups/:id";
111
111
  export const QUALITY_DASHBOARD = "/quality_dashboard";
112
+ export const REFERENCE_DATASETS = "/referenceDatasets";
113
+ export const REFERENCE_DATASET_EDIT = "/referenceDatasets/:id/edit";
114
+ export const REFERENCE_DATASET_NEW = "/referenceDatasets/new";
115
+ export const REFERENCE_DATASET = "/referenceDatasets/:id";
112
116
  export const REMEDIATION_EDIT =
113
117
  "/rules/:id/implementations/:implementation_id/results/:rule_result_id/remediation/edit";
114
118
  export const REMEDIATION_NEW =
@@ -229,19 +233,23 @@ const routes = {
229
233
  GROUPS,
230
234
  GROUP_CREATE,
231
235
  GROUP_EDIT,
232
- IMPLEMENTATIONS,
233
- IMPLEMENTATION_NEW,
234
- IMPLEMENTATION_NEW_RAW,
235
236
  IMPLEMENTATION,
237
+ IMPLEMENTATIONS,
238
+ IMPLEMENTATION_CLONE,
239
+ IMPLEMENTATION_CONCEPT_LINKS,
240
+ IMPLEMENTATION_CONCEPT_LINKS_NEW,
236
241
  IMPLEMENTATION_EDIT,
237
242
  IMPLEMENTATION_EVENTS,
238
- IMPLEMENTATION_CLONE,
239
243
  IMPLEMENTATION_MOVE,
240
- IMPLEMENTATION_RESULT_DETAILS,
241
- IMPLEMENTATION_RESULT_SEGMENTS_RESULTS,
242
- IMPLEMENTATION_RESULT_REMEDIATION_PLAN,
244
+ IMPLEMENTATION_NEW,
245
+ IMPLEMENTATION_NEW_RAW,
243
246
  IMPLEMENTATION_RESULTS,
244
247
  IMPLEMENTATION_RESULTS_DETAILS,
248
+ IMPLEMENTATION_RESULT_DETAILS,
249
+ IMPLEMENTATION_RESULT_REMEDIATION_PLAN,
250
+ IMPLEMENTATION_RESULT_SEGMENTS_RESULTS,
251
+ IMPLEMENTATION_STRUCTURES,
252
+ IMPLEMENTATION_STRUCTURES_NEW,
245
253
  INGEST,
246
254
  INGESTS,
247
255
  INGESTS_NEW,
@@ -266,6 +274,10 @@ const routes = {
266
274
  PROFILE_EXECUTION,
267
275
  PROFILE_GROUP,
268
276
  QUALITY_DASHBOARD,
277
+ REFERENCE_DATASET,
278
+ REFERENCE_DATASETS,
279
+ REFERENCE_DATASET_EDIT,
280
+ REFERENCE_DATASET_NEW,
269
281
  REMEDIATION_EDIT,
270
282
  REMEDIATION_NEW,
271
283
  REMEDIATION_PLAN,
@@ -276,13 +288,9 @@ const routes = {
276
288
  RULES,
277
289
  RULE_EDIT,
278
290
  RULE_EVENTS,
279
- IMPLEMENTATION_CONCEPT_LINKS,
280
- IMPLEMENTATION_CONCEPT_LINKS_NEW,
281
- IMPLEMENTATION_STRUCTURES,
282
- IMPLEMENTATION_STRUCTURES_NEW,
291
+ RULE_IMPLEMENTATIONS,
283
292
  RULE_IMPLEMENTATION_NEW,
284
293
  RULE_IMPLEMENTATION_NEW_RAW,
285
- RULE_IMPLEMENTATIONS,
286
294
  RULE_NEW,
287
295
  SAMPLE,
288
296
  SEARCH,
@@ -300,6 +308,7 @@ const routes = {
300
308
  STRUCTURE,
301
309
  STRUCTURES,
302
310
  STRUCTURES_BULK_UPDATE,
311
+ STRUCTURES_UPLOAD_EVENTS,
303
312
  STRUCTURE_CHILDREN,
304
313
  STRUCTURE_EVENTS,
305
314
  STRUCTURE_GRANTS,
@@ -321,12 +330,6 @@ const routes = {
321
330
  STRUCTURE_VERSION,
322
331
  STRUCTURE_VERSIONS,
323
332
  STRUCTURE_VERSION_VERSIONS,
324
- STRUCTURE,
325
- STRUCTURES_BULK_UPDATE,
326
- STRUCTURES,
327
- STRUCTURES_UPLOAD_EVENTS,
328
- SUBSCRIPTION_EDIT,
329
- SUBSCRIPTION_NEW,
330
333
  SUBSCRIPTION,
331
334
  SUBSCRIPTIONS,
332
335
  SUBSCRIPTION_EDIT,
@@ -0,0 +1,9 @@
1
+ export const toBase64 = (file) =>
2
+ new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+ reader.readAsDataURL(file);
5
+ // eslint-disable-next-line fp/no-mutation
6
+ reader.onload = () => resolve(reader.result);
7
+ // eslint-disable-next-line fp/no-mutation
8
+ reader.onerror = (error) => reject(error);
9
+ });
@@ -2,6 +2,8 @@ import _ from "lodash/fp";
2
2
 
3
3
  export const lowerDeburr = _.flow(_.toLower, _.deburr);
4
4
 
5
+ export const lowerDeburrTrim = _.flow(_.toLower, _.deburr, _.trim);
6
+
5
7
  export const lowerDeburrPath = (path) =>
6
8
  _.flow(_.path(path), _.toLower, _.deburr);
7
9