@truedat/dd 8.5.8 → 8.5.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dd",
3
- "version": "8.5.8",
3
+ "version": "8.5.10",
4
4
  "description": "Truedat Web Data Dictionary",
5
5
  "sideEffects": false,
6
6
  "module": "src/index.js",
@@ -51,22 +51,22 @@
51
51
  "@testing-library/jest-dom": "^6.6.3",
52
52
  "@testing-library/react": "^16.3.0",
53
53
  "@testing-library/user-event": "^14.6.1",
54
- "@truedat/test": "8.5.8",
54
+ "@truedat/test": "8.5.10",
55
55
  "identity-obj-proxy": "^3.0.0",
56
56
  "jest": "^29.7.0",
57
57
  "redux-saga-test-plan": "^4.0.6"
58
58
  },
59
59
  "dependencies": {
60
60
  "@apollo/client": "^3.13.8",
61
- "axios": "^1.15.0",
61
+ "axios": "^1.15.2",
62
62
  "file-saver": "^2.0.5",
63
63
  "graphql": "^16.11.0",
64
64
  "is-hotkey": "^0.2.0",
65
65
  "is-url": "^1.2.4",
66
- "lodash": "^4.17.21",
66
+ "lodash": "^4.18.1",
67
67
  "match-sorter": "^8.0.1",
68
68
  "moment": "^2.30.1",
69
- "path-to-regexp": "^8.2.0",
69
+ "path-to-regexp": "^8.4.0",
70
70
  "prop-types": "^15.8.1",
71
71
  "query-string": "^7.1.3",
72
72
  "react": "^19.1.0",
@@ -86,5 +86,5 @@
86
86
  "svg-pan-zoom": "^3.6.2",
87
87
  "swr": "^2.3.3"
88
88
  },
89
- "gitHead": "61ad9443b3d822d30dcfa977f5fad3494b3ed5b4"
89
+ "gitHead": "7f20176d7fdde8bc45181689840e2766e68036ba"
90
90
  }
@@ -243,6 +243,7 @@ export const LEGACY_DATA_STRUCTURE_VERSION_QUERY = gql`
243
243
  $dataStructureId: ID!
244
244
  $version: String!
245
245
  $note_fields: [String]
246
+ $withoutGrants: Boolean!
246
247
  ) {
247
248
  dataStructureVersion(dataStructureId: $dataStructureId, version: $version) {
248
249
  id
@@ -324,7 +325,7 @@ export const LEGACY_DATA_STRUCTURE_VERSION_QUERY = gql`
324
325
  }
325
326
  ancestry
326
327
 
327
- grants {
328
+ grants @skip(if: $withoutGrants) {
328
329
  data_structure {
329
330
  external_id
330
331
  id
@@ -355,7 +356,7 @@ export const LEGACY_DATA_STRUCTURE_VERSION_QUERY = gql`
355
356
  }
356
357
  user_id
357
358
  }
358
- grant {
359
+ grant @skip(if: $withoutGrants) {
359
360
  data_structure {
360
361
  external_id
361
362
  id
@@ -14,7 +14,7 @@ export const ImplementationStructuresLoader = ({
14
14
  const structures = _.flow(
15
15
  _.concat(structuresFields),
16
16
  _.map(_.toInteger),
17
- _.uniq
17
+ _.uniq,
18
18
  )(structuresSiblings);
19
19
  const [structureIndex, setStructureIndex] = useState(0);
20
20
  const [requestedStructures, setRequestedStructures] = useState([]);
@@ -23,7 +23,7 @@ export const ImplementationStructuresLoader = ({
23
23
  // check structure_ids, will be undefined if structureIds is an empty Array
24
24
  if (structure_id && !_.includes(structure_id)(structures)) {
25
25
  if (!_.includes(structure_id)(requestedStructures)) {
26
- legacyFetchStructure({ id: structure_id });
26
+ legacyFetchStructure({ id: structure_id, withoutGrants: true });
27
27
  setRequestedStructures([...requestedStructures, structure_id]);
28
28
  }
29
29
  } else if (structureIndex + 1 < _.size(structureIds)) {
@@ -57,6 +57,7 @@ export const mapStateToProps = ({ structuresFields, structuresSiblings }) => ({
57
57
  structuresSiblings: _.keys(structuresSiblings),
58
58
  });
59
59
 
60
- export default connect(mapStateToProps, { legacyFetchStructure, clearStructure })(
61
- ImplementationStructuresLoader
62
- );
60
+ export default connect(mapStateToProps, {
61
+ legacyFetchStructure,
62
+ clearStructure,
63
+ })(ImplementationStructuresLoader);
@@ -36,6 +36,11 @@ const enablePanZoom = (svg) => {
36
36
  svg && svg.enablePan();
37
37
  svg && svg.enableZoom();
38
38
  };
39
+ const isInteractiveGraphElement = (target) =>
40
+ target &&
41
+ target.closest &&
42
+ target.closest("g.resource, g.group, path.link, a");
43
+
39
44
  const togglePanZoom = (svg) => (selectedNode) => {
40
45
  _.isEmpty(selectedNode) ? enablePanZoom(svg) : disablePanZoom(svg);
41
46
  };
@@ -93,6 +98,7 @@ export const LineageGraph = ({
93
98
  instance.resize();
94
99
  instance.fit();
95
100
  instance.zoomBy(initialScale);
101
+ instance.center();
96
102
  const currentPan = instance.getPan();
97
103
  instance.pan({ x: currentPan.x, y: topMargin });
98
104
  } catch (_error) {
@@ -168,15 +174,21 @@ export const LineageGraph = ({
168
174
  const onHover = (g) =>
169
175
  selectedNode ? undefined : () => dispatch(hoverNode.trigger(g));
170
176
  const onPointerDown = (event) => {
171
- if (event.currentTarget.setPointerCapture && event.pointerId !== undefined) {
177
+ if (
178
+ !isInteractiveGraphElement(event.target) &&
179
+ event.currentTarget.setPointerCapture &&
180
+ event.pointerId !== undefined
181
+ ) {
172
182
  event.currentTarget.setPointerCapture(event.pointerId);
173
183
  }
174
184
  };
175
185
 
176
186
  const onPointerUp = (event) => {
177
187
  if (
188
+ event.pointerId !== undefined &&
178
189
  event.currentTarget.releasePointerCapture &&
179
- event.pointerId !== undefined
190
+ event.currentTarget.hasPointerCapture &&
191
+ event.currentTarget.hasPointerCapture(event.pointerId)
180
192
  ) {
181
193
  event.currentTarget.releasePointerCapture(event.pointerId);
182
194
  }
@@ -36,10 +36,8 @@ export const LineageGroup = ({
36
36
  </text>
37
37
  );
38
38
  const trigger =
39
- z == 0 ? null : handleClick ? (
40
- <a onContextMenu={handleClick} onClick={handleClick}>
41
- {text}
42
- </a>
39
+ z === 0 ? null : handleClick ? (
40
+ <a>{text}</a>
43
41
  ) : (
44
42
  text
45
43
  );
@@ -69,7 +67,12 @@ export const LineageGroup = ({
69
67
  active ? ["active"] : [],
70
68
  ]);
71
69
  return (
72
- <g className={classNames} onMouseOver={onHover} onContextMenu={handleClick}>
70
+ <g
71
+ className={classNames}
72
+ onMouseOver={onHover}
73
+ onClick={z === 0 ? undefined : handleClick}
74
+ onContextMenu={handleClick}
75
+ >
73
76
  <title>{name}</title>
74
77
  <rect x={x} y={y} rx="6" ry="6" width={w} height={h} />
75
78
  {content}
@@ -54,6 +54,7 @@ export const LineageResource = ({
54
54
  <g
55
55
  className={`resource ${active ? "active" : ""}`}
56
56
  onMouseOver={onHover}
57
+ onClick={handleClick}
57
58
  onContextMenu={handleClick}
58
59
  >
59
60
  <title>{name}</title>
@@ -25,7 +25,8 @@ export const StructureSelectorInputField = ({
25
25
  }) => {
26
26
  const { formatMessage } = useIntl();
27
27
  const handleSelectStructure = (value) => {
28
- value && legacyFetchStructure({ id: _.prop("id")(value) });
28
+ value &&
29
+ legacyFetchStructure({ id: _.prop("id")(value), withoutGrants: true });
29
30
  value && onChange(value);
30
31
  };
31
32
 
@@ -40,7 +41,7 @@ export const StructureSelectorInputField = ({
40
41
  const aliasIsNeeded =
41
42
  _.flow(
42
43
  _.map(_.path("structure.id")),
43
- _.filter((s) => s === selectedStructure?.structure?.id)
44
+ _.filter((s) => s === selectedStructure?.structure?.id),
44
45
  )(structures).length > 1;
45
46
 
46
47
  return (
@@ -140,5 +141,5 @@ StructureSelectorInputField.propTypes = {
140
141
  };
141
142
 
142
143
  export default connect(null, { legacyFetchStructure })(
143
- StructureSelectorInputField
144
+ StructureSelectorInputField,
144
145
  );
@@ -28,6 +28,8 @@ jest.mock("@truedat/core/components/SystemsLoader", () => () => (
28
28
  jest.mock("@truedat/core/components/TemplatesLoader", () => () => (
29
29
  <div>TemplatesLoader</div>
30
30
  ));
31
+ jest.mock("@truedat/core/components/UploadJobs", () => () => <div>UploadJobs</div>);
32
+ jest.mock("@truedat/core/components/UploadJob", () => () => <div>UploadJob</div>);
31
33
 
32
34
  jest.mock("../CatalogViewConfigs", () => () => <div>CatalogViewConfigs</div>);
33
35
  jest.mock("../CatalogViewConfigForm", () => ({
@@ -11,7 +11,10 @@ describe("<ImplementationStructuresLoader/>", () => {
11
11
  const { unmount } = render(<ImplementationStructuresLoader {...props} />);
12
12
  expect(props.clearStructure).toHaveBeenCalledTimes(0);
13
13
  expect(props.legacyFetchStructure).toHaveBeenCalledTimes(1);
14
- expect(props.legacyFetchStructure).toHaveBeenCalledWith({ id: 42 });
14
+ expect(props.legacyFetchStructure).toHaveBeenCalledWith({
15
+ id: 42,
16
+ withoutGrants: true,
17
+ });
15
18
 
16
19
  unmount();
17
20
  expect(props.clearStructure).toHaveBeenCalledTimes(1);
@@ -1,4 +1,5 @@
1
1
  import { render, waitForLoad } from "@truedat/test/render";
2
+ import { fireEvent } from "@testing-library/react";
2
3
  import { LineageGroup } from "../LineageGroup";
3
4
 
4
5
  // Mock LineageContextMenu component
@@ -36,6 +37,10 @@ describe("<LineageGroup />", () => {
36
37
  onHover,
37
38
  };
38
39
 
40
+ beforeEach(() => {
41
+ jest.clearAllMocks();
42
+ });
43
+
39
44
  it("matches the latest snapshot", async () => {
40
45
  const rendered = render(
41
46
  <svg>
@@ -76,4 +81,30 @@ describe("<LineageGroup />", () => {
76
81
  await waitForLoad(rendered);
77
82
  expect(rendered.container.querySelector(".popup")).not.toBeInTheDocument();
78
83
  });
84
+
85
+ it("selects the group when clicking the node body", async () => {
86
+ const rendered = render(
87
+ <svg>
88
+ <LineageGroup {...props} />
89
+ </svg>
90
+ );
91
+ await waitForLoad(rendered);
92
+
93
+ fireEvent.click(rendered.container.querySelector("rect"));
94
+
95
+ expect(onClick).toHaveBeenCalledTimes(1);
96
+ });
97
+
98
+ it("does not select the group when z is 0", async () => {
99
+ const rendered = render(
100
+ <svg>
101
+ <LineageGroup {...props} z={0} />
102
+ </svg>
103
+ );
104
+ await waitForLoad(rendered);
105
+
106
+ fireEvent.click(rendered.container.querySelector("rect"));
107
+
108
+ expect(onClick).not.toHaveBeenCalled();
109
+ });
79
110
  });
@@ -1,4 +1,5 @@
1
1
  import { render, waitForLoad } from "@truedat/test/render";
2
+ import { fireEvent } from "@testing-library/react";
2
3
  import { LineageResource } from "../LineageResource";
3
4
 
4
5
  // Mock LineageContextMenu component
@@ -32,6 +33,10 @@ describe("<LineageResource />", () => {
32
33
  onHover,
33
34
  };
34
35
 
36
+ beforeEach(() => {
37
+ jest.clearAllMocks();
38
+ });
39
+
35
40
  it("matches the latest snapshot", async () => {
36
41
  const rendered = render(
37
42
  <svg>
@@ -72,4 +77,17 @@ describe("<LineageResource />", () => {
72
77
  await waitForLoad(rendered);
73
78
  expect(rendered.container.querySelector(".popup")).not.toBeInTheDocument();
74
79
  });
80
+
81
+ it("selects the resource when clicking the node body", async () => {
82
+ const rendered = render(
83
+ <svg>
84
+ <LineageResource {...props} />
85
+ </svg>
86
+ );
87
+ await waitForLoad(rendered);
88
+
89
+ fireEvent.click(rendered.container.querySelector("rect"));
90
+
91
+ expect(onClick).toHaveBeenCalledTimes(1);
92
+ });
75
93
  });
@@ -120,45 +120,8 @@ exports[`<DictionaryRoutes /> renders correctly with structures route 1`] = `
120
120
 
121
121
  exports[`<DictionaryRoutes /> renders correctly with structures upload events route 1`] = `
122
122
  <div>
123
- <div
124
- class="ui breadcrumb"
125
- >
126
- <a
127
- class="section"
128
- data-discover="true"
129
- href="/structureNotes/uploadJobs"
130
- >
131
- uploadJobs.notes.header
132
- </a>
133
- </div>
134
- <div
135
- class="ui segment"
136
- >
137
- <h2
138
- class="ui header"
139
- >
140
- <i
141
- aria-hidden="true"
142
- class="cogs circular icon"
143
- />
144
- <div
145
- class="content"
146
- >
147
- uploadJobs.notes.header
148
- <div
149
- class="sub header"
150
- >
151
- uploadJobs.subheader
152
- </div>
153
- </div>
154
- </h2>
155
- <div
156
- class="dimmable"
157
- >
158
- <div
159
- class="ui bottom attached segment"
160
- />
161
- </div>
123
+ <div>
124
+ UploadJobs
162
125
  </div>
163
126
  </div>
164
127
  `;
@@ -37,6 +37,7 @@ describe("sagas: legacyFetchStructureSaga", () => {
37
37
  dataStructureId: id,
38
38
  version,
39
39
  note_fields: ["note_field"],
40
+ withoutGrants: false,
40
41
  };
41
42
 
42
43
  const structureFieldColumns = [{ name: "id" }, { name: "note.note_field" }];
@@ -94,6 +95,41 @@ describe("sagas: legacyFetchStructureSaga", () => {
94
95
  dataStructureId: id,
95
96
  version,
96
97
  note_fields: ["note_field"],
98
+ withoutGrants: false,
99
+ };
100
+
101
+ expect(() => {
102
+ testSaga(legacyFetchStructureSaga, { payload })
103
+ .next()
104
+ .select(getStructureFieldColumns)
105
+ .next(structureFieldColumns)
106
+ .getContext("client")
107
+ .next(client)
108
+ .put(legacyFetchStructure.request())
109
+ .next()
110
+ .call(client.query, {
111
+ fetchPolicy: "network-only",
112
+ query: LEGACY_DATA_STRUCTURE_VERSION_QUERY,
113
+ variables,
114
+ })
115
+ .next({ data: { dataStructureVersion } })
116
+ .put({ meta, ...legacyFetchStructure.success(data) })
117
+ .next()
118
+ .put(legacyFetchStructure.fulfill())
119
+ .next()
120
+ .isDone();
121
+ }).not.toThrow();
122
+ });
123
+
124
+ it("should forward withoutGrants when set in payload", () => {
125
+ const payload = { id, withoutGrants: true };
126
+ const meta = { version };
127
+
128
+ const variables = {
129
+ dataStructureId: id,
130
+ version,
131
+ note_fields: ["note_field"],
132
+ withoutGrants: true,
97
133
  };
98
134
 
99
135
  expect(() => {
@@ -9,14 +9,14 @@ export function* legacyFetchStructureSaga({ payload }) {
9
9
  const structureFieldColumns = yield select(getStructureFieldColumns);
10
10
  const note_fields = _.flow(
11
11
  _.filter(({ name }) => name.startsWith("note.")),
12
- _.map(({ name }) => name.split(".")[1])
12
+ _.map(({ name }) => name.split(".")[1]),
13
13
  )(structureFieldColumns);
14
14
 
15
15
  const client = yield getContext("client");
16
16
 
17
17
  yield put(legacyFetchStructure.request());
18
18
 
19
- const { id, version = "latest" } = payload;
19
+ const { id, version = "latest", withoutGrants = false } = payload;
20
20
  const {
21
21
  data: { dataStructureVersion },
22
22
  } = yield call(client.query, {
@@ -26,6 +26,7 @@ export function* legacyFetchStructureSaga({ payload }) {
26
26
  dataStructureId: id,
27
27
  version,
28
28
  note_fields,
29
+ withoutGrants,
29
30
  },
30
31
  });
31
32
 
@@ -52,17 +52,19 @@
52
52
  }
53
53
 
54
54
  .structure-lineage .dl {
55
+ height: 100%;
55
56
  padding: 0;
56
57
  margin: 0;
57
58
  }
58
59
 
59
60
  .structure-lineage .dl svg {
60
- height: clamp(340px, 52vw, 640px) !important;
61
- max-height: 640px;
61
+ width: 100%;
62
+ height: 100% !important;
63
+ min-height: 340px;
62
64
  background-color: #f7f8fa;
63
65
  padding: 0;
64
66
  margin: 0;
65
67
  display: block;
66
68
  margin-left: 0;
67
69
  margin-right: 0;
68
- }
70
+ }