@truedat/bg 7.4.1 → 7.4.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 (25) hide show
  1. package/package.json +6 -6
  2. package/src/concepts/components/Concept.js +28 -6
  3. package/src/concepts/components/ConceptArchive.js +3 -3
  4. package/src/concepts/components/ConceptArchiveRow.js +3 -3
  5. package/src/concepts/components/ConceptContext.js +37 -0
  6. package/src/concepts/components/__tests__/Concept.spec.js +50 -1
  7. package/src/concepts/components/__tests__/ConceptArchive.spec.js +3 -3
  8. package/src/concepts/components/__tests__/ConceptContext.spec.js +47 -0
  9. package/src/concepts/components/__tests__/__snapshots__/Concept.spec.js.snap +181 -0
  10. package/src/concepts/components/__tests__/__snapshots__/ConceptArchive.spec.js.snap +2 -2
  11. package/src/concepts/components/__tests__/__snapshots__/ConceptArchiveRow.spec.js.snap +1 -7
  12. package/src/concepts/components/__tests__/__snapshots__/ConceptContext.spec.js.snap +9 -0
  13. package/src/concepts/reducers/__tests__/conceptArchive.spec.js +4 -4
  14. package/src/concepts/reducers/concept.js +1 -0
  15. package/src/concepts/reducers/conceptArchive.js +2 -2
  16. package/src/concepts/relations/components/ConceptLinkActions.js +47 -17
  17. package/src/concepts/relations/components/ConceptLinksActions.js +49 -22
  18. package/src/concepts/relations/components/ConceptLinkstRequestGrantButton.js +65 -0
  19. package/src/concepts/relations/components/ConceptStructureLinks.js +92 -9
  20. package/src/concepts/relations/components/__tests__/ConceptLinksActions.spec.js +65 -0
  21. package/src/concepts/relations/components/__tests__/ConceptLinkstRequestGrantButton.spec.js +37 -0
  22. package/src/concepts/relations/components/__tests__/ConceptStructureLinks.spec.js +82 -6
  23. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinksActions.spec.js.snap +61 -0
  24. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptLinkstRequestGrantButton.spec.js.snap +16 -0
  25. package/src/concepts/relations/components/__tests__/__snapshots__/ConceptStructureLinks.spec.js.snap +193 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/bg",
3
- "version": "7.4.1",
3
+ "version": "7.4.3",
4
4
  "description": "Truedat Web Business Glossary",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -34,7 +34,7 @@
34
34
  "@testing-library/jest-dom": "^5.16.5",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "7.4.1",
37
+ "@truedat/test": "7.4.3",
38
38
  "babel-jest": "^28.1.0",
39
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
40
40
  "babel-plugin-lodash": "^3.3.4",
@@ -86,9 +86,9 @@
86
86
  ]
87
87
  },
88
88
  "dependencies": {
89
- "@truedat/core": "7.4.1",
90
- "@truedat/df": "7.4.1",
91
- "@truedat/lm": "7.4.1",
89
+ "@truedat/core": "7.4.3",
90
+ "@truedat/df": "7.4.3",
91
+ "@truedat/lm": "7.4.3",
92
92
  "decode-uri-component": "^0.2.2",
93
93
  "file-saver": "^2.0.5",
94
94
  "moment": "^2.29.4",
@@ -111,5 +111,5 @@
111
111
  "react-dom": ">= 16.8.6 < 17",
112
112
  "semantic-ui-react": ">= 2.0.3 < 2.2"
113
113
  },
114
- "gitHead": "3f0fb3cef1d8e517ab71b741d8e4617319960f58"
114
+ "gitHead": "f1e3c9384a5f250bda208b60615aa13c0581a4bc"
115
115
  }
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Route } from "react-router-dom";
6
6
  import { Grid, Segment } from "semantic-ui-react";
7
+ import StructureGrantCart from "@truedat/dd/components/StructureGrantCart";
7
8
  import { Comments, CommentsLoader } from "@truedat/core/components";
8
9
  import { CONCEPT_VERSION } from "@truedat/core/routes";
9
10
  import { useIntl } from "react-intl";
@@ -19,6 +20,7 @@ import ConceptTabPane from "./ConceptTabPane";
19
20
  import ConceptSummary from "./ConceptSummary";
20
21
  import ConceptTaxonomy from "./ConceptTaxonomy";
21
22
  import SharedToDomains from "./SharedToDomains";
23
+ import ConceptContextProvider, { useConceptContext } from "./ConceptContext";
22
24
 
23
25
  const EventsLoader = React.lazy(() =>
24
26
  import("@truedat/audit/components/EventsLoader")
@@ -35,6 +37,9 @@ const ConceptRulesLoader = React.lazy(() =>
35
37
  export const Concept = ({ id, concept }) => {
36
38
  const { locales } = useLanguage();
37
39
  const { locale } = useIntl();
40
+ const {
41
+ conceptContext: { grantView },
42
+ } = useConceptContext();
38
43
 
39
44
  const defaultLang = _.flow(
40
45
  _.find({ is_default: true }),
@@ -128,11 +133,17 @@ export const Concept = ({ id, concept }) => {
128
133
  />
129
134
  </Grid.Column>
130
135
  <Grid.Column width={4}>
131
- <ConceptSummary />
132
- <ConceptRelationsSummary />
133
- <ConceptTaxonomy />
134
- <SharedToDomains />
135
- <ConceptCompleteness />
136
+ {grantView ? (
137
+ <StructureGrantCart allowEmptyCart />
138
+ ) : (
139
+ <>
140
+ <ConceptSummary />
141
+ <ConceptRelationsSummary />
142
+ <ConceptTaxonomy />
143
+ <SharedToDomains />
144
+ <ConceptCompleteness />
145
+ </>
146
+ )}
136
147
  </Grid.Column>
137
148
  </Grid>
138
149
  </>
@@ -144,9 +155,20 @@ Concept.propTypes = {
144
155
  concept: PropTypes.object,
145
156
  };
146
157
 
158
+ const ConceptWrapper = ({ id, concept }) => (
159
+ <ConceptContextProvider>
160
+ <Concept id={id} concept={concept} />
161
+ </ConceptContextProvider>
162
+ );
163
+
164
+ ConceptWrapper.propTypes = {
165
+ id: PropTypes.number.isRequired,
166
+ concept: PropTypes.object,
167
+ };
168
+
147
169
  const mapStateToProps = ({ concept }) => ({
148
170
  id: _.prop("business_concept_id")(concept),
149
171
  concept: concept,
150
172
  });
151
173
 
152
- export default connect(mapStateToProps)(Concept);
174
+ export default connect(mapStateToProps)(ConceptWrapper);
@@ -29,7 +29,7 @@ export const ConceptArchive = ({ conceptArchive }) => (
29
29
  />
30
30
  <Table.HeaderCell
31
31
  content={
32
- <FormattedMessage id="concepts.props.last_change_at" />
32
+ <FormattedMessage id="concepts.props.updated_at" />
33
33
  }
34
34
  />
35
35
  </Table.Row>
@@ -48,11 +48,11 @@ export const ConceptArchive = ({ conceptArchive }) => (
48
48
  );
49
49
 
50
50
  ConceptArchive.propTypes = {
51
- conceptArchive: PropTypes.array
51
+ conceptArchive: PropTypes.array,
52
52
  };
53
53
 
54
54
  const mapStateToProps = ({ conceptArchive }) => ({
55
- conceptArchive
55
+ conceptArchive,
56
56
  });
57
57
 
58
58
  export default connect(mapStateToProps)(ConceptArchive);
@@ -11,7 +11,7 @@ export const ConceptArchiveRow = ({
11
11
  business_concept_id,
12
12
  id,
13
13
  status,
14
- last_change_at,
14
+ updated_at,
15
15
  last_change_by,
16
16
  version,
17
17
  }) => {
@@ -32,7 +32,7 @@ export const ConceptArchiveRow = ({
32
32
  />
33
33
  <Table.Cell content={version} />
34
34
  <Table.Cell content={_.propOr("", "full_name")(last_change_by)} />
35
- <Table.Cell content={<DateTime value={last_change_at} />} />
35
+ <Table.Cell content={<DateTime value={updated_at} />} />
36
36
  </Table.Row>
37
37
  );
38
38
  };
@@ -41,7 +41,7 @@ ConceptArchiveRow.propTypes = {
41
41
  business_concept_id: PropTypes.number,
42
42
  id: PropTypes.number,
43
43
  status: PropTypes.string,
44
- last_change_at: PropTypes.string,
44
+ updated_at: PropTypes.string,
45
45
  last_change_by: PropTypes.string,
46
46
  version: PropTypes.number,
47
47
  };
@@ -0,0 +1,37 @@
1
+ import React, { createContext, useState, useContext } from "react";
2
+ import PropTypes from "prop-types";
3
+
4
+ export const ConceptContext = createContext("conceptContext");
5
+
6
+ const initialContext = {
7
+ grantView: false,
8
+ };
9
+
10
+ export const ConceptContextProvider = ({ children }) => {
11
+ const [context, setContext] = useState(initialContext);
12
+
13
+ const setProperty = (value) =>
14
+ setContext({
15
+ ...context,
16
+ ...value,
17
+ });
18
+
19
+ return (
20
+ <ConceptContext.Provider
21
+ value={{
22
+ conceptContext: context,
23
+ setConceptContextProperty: setProperty,
24
+ }}
25
+ >
26
+ {children}
27
+ </ConceptContext.Provider>
28
+ );
29
+ };
30
+
31
+ ConceptContextProvider.propTypes = {
32
+ children: PropTypes.node,
33
+ };
34
+
35
+ export const useConceptContext = () => useContext(ConceptContext);
36
+
37
+ export default ConceptContextProvider;
@@ -3,6 +3,31 @@ import { render } from "@truedat/test/render";
3
3
  import { waitFor } from "@testing-library/react";
4
4
  import { LangProviderWrapper } from "@truedat/core/i18n";
5
5
  import { Concept } from "../Concept";
6
+ import ConceptContextProvider, { useConceptContext } from "../ConceptContext";
7
+
8
+ jest.mock("../ConceptContext", () => {
9
+ const originalModule = jest.requireActual("../ConceptContext");
10
+
11
+ return {
12
+ __esModule: true,
13
+ ...originalModule,
14
+ useConceptContext: jest.fn(),
15
+ };
16
+ });
17
+
18
+ jest.mock("@truedat/core/hooks", () => {
19
+ const originalModule = jest.requireActual("@truedat/core/hooks");
20
+
21
+ return {
22
+ __esModule: true,
23
+ ...originalModule,
24
+ useOperators: () => ({
25
+ data: {},
26
+ error: false,
27
+ loading: false,
28
+ }),
29
+ };
30
+ });
6
31
 
7
32
  beforeAll(() => {
8
33
  jest.useFakeTimers();
@@ -116,9 +141,33 @@ describe("<Concept />", () => {
116
141
  };
117
142
 
118
143
  it("matches the latest snapshot", async () => {
144
+ useConceptContext.mockReturnValue({
145
+ conceptContext: { grantView: false },
146
+ });
147
+ const { container, queryByText } = render(
148
+ <LangProviderWrapper langs={["es", "en"]}>
149
+ <ConceptContextProvider>
150
+ <Concept {...props} />
151
+ </ConceptContextProvider>
152
+ </LangProviderWrapper>,
153
+ renderOpts
154
+ );
155
+ await waitFor(() => {
156
+ expect(queryByText(/lazy/i)).not.toBeInTheDocument();
157
+ expect(container.querySelector(".loading")).not.toBeInTheDocument();
158
+ });
159
+ expect(container).toMatchSnapshot();
160
+ });
161
+
162
+ it("matches the latest snapshot with grantView activated", async () => {
163
+ useConceptContext.mockReturnValue({
164
+ conceptContext: { grantView: true },
165
+ });
119
166
  const { container, queryByText } = render(
120
167
  <LangProviderWrapper langs={["es", "en"]}>
121
- <Concept {...props} />
168
+ <ConceptContextProvider>
169
+ <Concept {...props} />
170
+ </ConceptContextProvider>
122
171
  </LangProviderWrapper>,
123
172
  renderOpts
124
173
  );
@@ -8,10 +8,10 @@ describe("<ConceptArchive />", () => {
8
8
  {
9
9
  id: 123,
10
10
  status: "status",
11
- last_change_at: "2018-06-27T07:32:53.154377Z",
11
+ updated_at: "2018-06-27T07:32:53.154377Z",
12
12
  last_change_by: "maixu",
13
- version: 1
14
- }
13
+ version: 1,
14
+ },
15
15
  ];
16
16
  const props = { conceptArchive };
17
17
  const wrapper = shallow(<ConceptArchive {...props} />);
@@ -0,0 +1,47 @@
1
+ import React, { useEffect } from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { renderHook, act } from "@testing-library/react-hooks";
4
+ import ConceptContext, { useConceptContext } from "../ConceptContext";
5
+
6
+ describe("<ConceptContext />", () => {
7
+ it("matches the latest snapshot", async () => {
8
+ const { container } = render(
9
+ <ConceptContext>
10
+ <div>Hello world</div>
11
+ </ConceptContext>
12
+ );
13
+ expect(container).toMatchSnapshot();
14
+ });
15
+
16
+ it("should update context with new values when setProperty is called", () => {
17
+ const { result } = renderHook(() => useConceptContext(), {
18
+ wrapper: ({ children }) => <ConceptContext>{children}</ConceptContext>,
19
+ });
20
+
21
+ act(() => {
22
+ result.current.setConceptContextProperty({ newKey: "newValue" });
23
+ });
24
+
25
+ expect(result.current.conceptContext).toEqual(
26
+ expect.objectContaining({ newKey: "newValue" })
27
+ );
28
+ });
29
+
30
+ it("should provide context values to child components", () => {
31
+ const TestComponent = () => {
32
+ const { conceptContext, setConceptContextProperty } = useConceptContext();
33
+ useEffect(() => {
34
+ setConceptContextProperty({ testKey: "testValue" });
35
+ }, []);
36
+ return <div>{conceptContext.testKey}</div>;
37
+ };
38
+
39
+ const { getByText } = render(
40
+ <ConceptContext>
41
+ <TestComponent />
42
+ </ConceptContext>
43
+ );
44
+
45
+ expect(getByText("testValue")).toBeInTheDocument();
46
+ });
47
+ });
@@ -307,3 +307,184 @@ exports[`<Concept /> matches the latest snapshot 1`] = `
307
307
  </div>
308
308
  </div>
309
309
  `;
310
+
311
+ exports[`<Concept /> matches the latest snapshot with grantView activated 1`] = `
312
+ <div>
313
+ <div
314
+ class="ui breadcrumb"
315
+ >
316
+ <a
317
+ class="section"
318
+ href="/concepts"
319
+ >
320
+ Business Glossary
321
+ </a>
322
+ <i
323
+ aria-hidden="true"
324
+ class="right angle icon divider"
325
+ />
326
+ <a
327
+ class="section"
328
+ href="/concepts/pending"
329
+ >
330
+ Draft
331
+ </a>
332
+ <i
333
+ aria-hidden="true"
334
+ class="right angle icon divider"
335
+ />
336
+ <span
337
+ class="active section"
338
+ style="cursor: default;"
339
+ >
340
+ Concept_en
341
+ </span>
342
+ </div>
343
+ <div
344
+ class="ui equal width grid"
345
+ style="margin-top: 0px;"
346
+ >
347
+ <div
348
+ class="twelve wide column"
349
+ >
350
+ <div
351
+ class="ui segment"
352
+ >
353
+ <div
354
+ class="ui grid"
355
+ >
356
+ <div
357
+ class="row"
358
+ >
359
+ <div
360
+ class="eight wide column"
361
+ >
362
+ <h2
363
+ class="ui header"
364
+ >
365
+ <i
366
+ aria-hidden="true"
367
+ class="book circular icon"
368
+ />
369
+ <div
370
+ class="content"
371
+ >
372
+ Concept_es
373
+ <div
374
+ class="sub header"
375
+ >
376
+ templates.undefined
377
+ </div>
378
+ </div>
379
+ </h2>
380
+ </div>
381
+ <div
382
+ class="right aligned eight wide column"
383
+ >
384
+ <button
385
+ class="ui basic icon button button icon group-actions"
386
+ data-tooltip="Sharing"
387
+ >
388
+ <i
389
+ aria-hidden="true"
390
+ class="share alternate icon"
391
+ />
392
+ </button>
393
+ <button
394
+ class="ui basic icon button button icon group-actions structureButton"
395
+ >
396
+ <i
397
+ aria-hidden="true"
398
+ class="eye icon"
399
+ />
400
+ </button>
401
+ </div>
402
+ </div>
403
+ <div
404
+ class="row"
405
+ >
406
+ <div
407
+ class="eight wide column"
408
+ >
409
+ <div
410
+ class="ui left floated buttons"
411
+ >
412
+ <button
413
+ class="ui mini active button"
414
+ >
415
+ Spanish
416
+ </button>
417
+ <button
418
+ class="ui mini button"
419
+ >
420
+ English
421
+ </button>
422
+ </div>
423
+ </div>
424
+ <div
425
+ class="right aligned eight wide column"
426
+ />
427
+ </div>
428
+ </div>
429
+ <div
430
+ class="ui pointing secondary top attached tabular menu"
431
+ >
432
+ <a
433
+ class="item"
434
+ href="/concepts/1/versions/1"
435
+ >
436
+ Concept
437
+ </a>
438
+ <a
439
+ class="item"
440
+ href="/concepts/1/versions/1/links/structures"
441
+ >
442
+ Linkage
443
+ </a>
444
+ <a
445
+ class="item"
446
+ href="/concepts/1/versions/1/rules"
447
+ >
448
+ Quality Rules
449
+ </a>
450
+ <a
451
+ class="item"
452
+ href="/concepts/1/versions/1/archive"
453
+ >
454
+ History
455
+ </a>
456
+ <a
457
+ class="item"
458
+ href="/concepts/1/versions/1/events"
459
+ >
460
+ Audit
461
+ </a>
462
+ </div>
463
+ </div>
464
+ </div>
465
+ <div
466
+ class="four wide column"
467
+ >
468
+ <div
469
+ class="ui segment structure-grant-cart"
470
+ >
471
+ <div
472
+ class="ui header"
473
+ title="structure.grant.cart"
474
+ >
475
+ structure.grant.cart
476
+ </div>
477
+ <div
478
+ class="ui divider"
479
+ />
480
+ <div
481
+ class="list"
482
+ />
483
+ <p>
484
+ structure.grant.cart.empty
485
+ </p>
486
+ </div>
487
+ </div>
488
+ </div>
489
+ </div>
490
+ `;
@@ -46,7 +46,7 @@ exports[`<ConceptArchive /> matches the latest snapshot 1`] = `
46
46
  as="th"
47
47
  content={
48
48
  <Memo(MemoizedFormattedMessage)
49
- id="concepts.props.last_change_at"
49
+ id="concepts.props.updated_at"
50
50
  />
51
51
  }
52
52
  />
@@ -58,9 +58,9 @@ exports[`<ConceptArchive /> matches the latest snapshot 1`] = `
58
58
  <ConceptArchiveRow
59
59
  id={123}
60
60
  key="0"
61
- last_change_at="2018-06-27T07:32:53.154377Z"
62
61
  last_change_by="maixu"
63
62
  status="status"
63
+ updated_at="2018-06-27T07:32:53.154377Z"
64
64
  version={1}
65
65
  />
66
66
  </TableBody>
@@ -24,13 +24,7 @@ exports[`<ConceptArchiveRow /> matches the latest snapshot 1`] = `
24
24
  </td>
25
25
  <td
26
26
  class=""
27
- >
28
- <time
29
- datetime="1530084773154"
30
- >
31
- 2018-06-27 07:32
32
- </time>
33
- </td>
27
+ />
34
28
  </tr>
35
29
  </tbody>
36
30
  </table>
@@ -0,0 +1,9 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<ConceptContext /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <div>
6
+ Hello world
7
+ </div>
8
+ </div>
9
+ `;
@@ -21,15 +21,15 @@ describe("reducers: conceptArchive", () => {
21
21
  {
22
22
  id: 123,
23
23
  status: "status",
24
- last_change_at: "2018-06-27T07:32:53.154377Z",
24
+ updated_at: "2018-06-27T07:32:53.154377Z",
25
25
  last_change_by: "maixu",
26
- version: 1
27
- }
26
+ version: 1,
27
+ },
28
28
  ];
29
29
  expect(
30
30
  conceptArchive(fooState, {
31
31
  type: fetchConceptArchive.SUCCESS,
32
- payload: { data }
32
+ payload: { data },
33
33
  })
34
34
  ).toEqual(data);
35
35
  });
@@ -32,6 +32,7 @@ const pickFields = _.pick([
32
32
  "rule_count",
33
33
  "concept_count",
34
34
  "i18n_content",
35
+ "actions",
35
36
  ]);
36
37
 
37
38
  export const concept = (state = initialState, { type, payload, meta }) => {
@@ -6,10 +6,10 @@ const initialState = [];
6
6
  const pickFields = _.pick([
7
7
  "id",
8
8
  "business_concept_id",
9
- "last_change_at",
9
+ "updated_at",
10
10
  "last_change_by",
11
11
  "status",
12
- "version"
12
+ "version",
13
13
  ]);
14
14
 
15
15
  const conceptArchive = (state = initialState, { type, payload }) => {
@@ -1,29 +1,55 @@
1
1
  import _ from "lodash/fp";
2
- import React from "react";
2
+ import React, { useState } from "react";
3
+ import { PropTypes } from "prop-types";
3
4
  import { connect } from "react-redux";
4
- import { Icon } from "semantic-ui-react";
5
+ import { Button, Icon } from "semantic-ui-react";
5
6
  import { FormattedMessage } from "react-intl";
6
7
  import { ConfirmModal } from "@truedat/core/components";
7
8
  import { conceptLinkAction } from "../routines";
8
9
 
9
- export const DeleteLink = ({ conceptLinkAction, action, loading }) =>
10
- loading ? (
10
+ export const DeleteLink = ({ conceptLinkAction, action, loading }) => {
11
+ const [openModal, setOpenModal] = useState(false);
12
+
13
+ return loading ? (
11
14
  <Icon loading name="circle notch" color="red" />
12
15
  ) : (
13
- <ConfirmModal
14
- icon="trash"
15
- trigger={<Icon name="trash alternate outline" color="red" />}
16
- header={
17
- <FormattedMessage id="relations.actions.data_field.delete.confirmation.header" />
18
- }
19
- content={
20
- <FormattedMessage id="relations.actions.data_field.delete.confirmation.content" />
21
- }
22
- onConfirm={() => conceptLinkAction(action)}
23
- onOpen={(e) => e.stopPropagation()}
24
- onClose={(e) => e.stopPropagation()}
25
- />
16
+ <>
17
+ <ConfirmModal
18
+ open={openModal}
19
+ trigger={
20
+ <Button
21
+ basic
22
+ color="red"
23
+ icon
24
+ onClick={() => setOpenModal(true)}
25
+ size="mini"
26
+ >
27
+ <Icon name="trash alternate outline" color="red" />
28
+ </Button>
29
+ }
30
+ header={
31
+ <FormattedMessage id="relations.actions.data_field.delete.confirmation.header" />
32
+ }
33
+ content={
34
+ <FormattedMessage id="relations.actions.data_field.delete.confirmation.content" />
35
+ }
36
+ onConfirm={() => conceptLinkAction(action)}
37
+ onOpen={() => {
38
+ setOpenModal(true);
39
+ }}
40
+ onClose={() => {
41
+ setOpenModal(false);
42
+ }}
43
+ />
44
+ </>
26
45
  );
46
+ };
47
+
48
+ DeleteLink.propTypes = {
49
+ conceptLinkAction: PropTypes.func,
50
+ action: PropTypes.object,
51
+ loading: PropTypes.bool,
52
+ };
27
53
 
28
54
  const mapStateToProps = ({ conceptLinkActionLoading }, ownProps) => ({
29
55
  loading: _.pathEq("action.href")(conceptLinkActionLoading)(ownProps),
@@ -36,4 +62,8 @@ export const DeleteLinkConnected = connect(mapStateToProps, {
36
62
  export const LinkActions = ({ delete: deleteAction }) =>
37
63
  deleteAction ? <DeleteLinkConnected action={deleteAction} /> : null;
38
64
 
65
+ LinkActions.propTypes = {
66
+ delete: PropTypes.object,
67
+ };
68
+
39
69
  export default LinkActions;