synapse-react-client 4.0.24 → 4.0.26

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 (119) hide show
  1. package/dist/SWC.index.d.ts +1 -0
  2. package/dist/SWC.index.d.ts.map +1 -1
  3. package/dist/SWC.index.js +2 -1
  4. package/dist/SWC.index.js.map +1 -1
  5. package/dist/components/AccessRequirementList/ManagedACTAccessRequirementRequestFlow/DataAccessRequestAccessorsFilesForm/DataAccessRequestAccessorsFilesForm.js.map +1 -1
  6. package/dist/components/AclEditor/useUpdateAcl.js.map +1 -1
  7. package/dist/components/Authentication/TwoFactorBackupCodes.js.map +1 -1
  8. package/dist/components/Authentication/TwoFactorEnrollmentForm.js.map +1 -1
  9. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +3 -0
  10. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  11. package/dist/components/Breadcrumbs/Breadcrumbs.js +43 -30
  12. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  13. package/dist/components/CannedRejectionDialog/CannedRejectionDialog.js.map +1 -1
  14. package/dist/components/ChallengeSubmission/SubmissionDirectoryList.js.map +1 -1
  15. package/dist/components/CopyToClipboardString/CopyToClipboardString.d.ts +7 -1
  16. package/dist/components/CopyToClipboardString/CopyToClipboardString.d.ts.map +1 -1
  17. package/dist/components/CopyToClipboardString/CopyToClipboardString.js +22 -16
  18. package/dist/components/CopyToClipboardString/CopyToClipboardString.js.map +1 -1
  19. package/dist/components/DataExplorer/DataExplorer.css +1 -1
  20. package/dist/components/DataExplorer/DataExplorer.d.ts +16 -2
  21. package/dist/components/DataExplorer/DataExplorer.d.ts.map +1 -1
  22. package/dist/components/DataExplorer/DataExplorer.js +82 -75
  23. package/dist/components/DataExplorer/DataExplorer.js.map +1 -1
  24. package/dist/components/DataExplorer/DataExplorer.module.js +16 -16
  25. package/dist/components/DataExplorer/DataExplorer.module.js.map +1 -1
  26. package/dist/components/DataExplorer/DataExplorer.module.scss +1 -1
  27. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts.map +1 -1
  28. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js +14 -1
  29. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js.map +1 -1
  30. package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
  31. package/dist/components/DataGrid/utils/columnFactory.js +15 -19
  32. package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
  33. package/dist/components/EntityFinder/tree/EntityTree.js.map +1 -1
  34. package/dist/components/EntityFinder/tree/VirtualizedTree.js.map +1 -1
  35. package/dist/components/EntityIcon.d.ts +1 -0
  36. package/dist/components/EntityIcon.d.ts.map +1 -1
  37. package/dist/components/EntityIcon.js +37 -36
  38. package/dist/components/EntityIcon.js.map +1 -1
  39. package/dist/components/EntitySidebar/EntitySidebar.css +1 -0
  40. package/dist/components/EntitySidebar/EntitySidebar.d.ts +7 -0
  41. package/dist/components/EntitySidebar/EntitySidebar.d.ts.map +1 -0
  42. package/dist/components/EntitySidebar/EntitySidebar.js +62 -0
  43. package/dist/components/EntitySidebar/EntitySidebar.js.map +1 -0
  44. package/dist/components/EntitySidebar/EntitySidebar.module.js +17 -0
  45. package/dist/components/EntitySidebar/EntitySidebar.module.js.map +1 -0
  46. package/dist/components/EntitySidebar/EntitySidebar.module.scss +87 -0
  47. package/dist/components/Evaluation/EvaluationRoundEditorList.js.map +1 -1
  48. package/dist/components/GenericCard/BioregistryRules.js.map +1 -1
  49. package/dist/components/GenericCard/TableRowGenericCard.d.ts +2 -1
  50. package/dist/components/GenericCard/TableRowGenericCard.d.ts.map +1 -1
  51. package/dist/components/GenericCard/TableRowGenericCard.js +3 -2
  52. package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
  53. package/dist/components/HeaderCard.d.ts.map +1 -1
  54. package/dist/components/HeaderCard.js +4 -0
  55. package/dist/components/HeaderCard.js.map +1 -1
  56. package/dist/components/HexGrid/HexGrid.d.ts +2 -1
  57. package/dist/components/HexGrid/HexGrid.d.ts.map +1 -1
  58. package/dist/components/HexGrid/HexGrid.js +13 -13
  59. package/dist/components/HexGrid/HexGrid.js.map +1 -1
  60. package/dist/components/IconSvg/IconSvg.d.ts +2 -1
  61. package/dist/components/IconSvg/IconSvg.d.ts.map +1 -1
  62. package/dist/components/IconSvg/IconSvg.js +112 -89
  63. package/dist/components/IconSvg/IconSvg.js.map +1 -1
  64. package/dist/components/Plot/UpsetPlot.js.map +1 -1
  65. package/dist/components/ProvenanceGraph/ProvenanceGraph.d.ts +3 -0
  66. package/dist/components/ProvenanceGraph/ProvenanceGraph.d.ts.map +1 -1
  67. package/dist/components/ProvenanceGraph/ProvenanceGraph.js +140 -85
  68. package/dist/components/ProvenanceGraph/ProvenanceGraph.js.map +1 -1
  69. package/dist/components/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField.js.map +1 -1
  70. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts.map +1 -1
  71. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js +3 -3
  72. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
  73. package/dist/components/StorybookComponentWrapper.js.map +1 -1
  74. package/dist/components/SynapseHomepageV2/HotdropsAndNews.css +1 -1
  75. package/dist/components/SynapseHomepageV2/HotdropsAndNews.module.js +9 -8
  76. package/dist/components/SynapseHomepageV2/HotdropsAndNews.module.js.map +1 -1
  77. package/dist/components/SynapseHomepageV2/HotdropsAndNews.module.scss +4 -1
  78. package/dist/components/SynapseHomepageV2/WordPressNews.d.ts +2 -1
  79. package/dist/components/SynapseHomepageV2/WordPressNews.d.ts.map +1 -1
  80. package/dist/components/SynapseHomepageV2/WordPressNews.js +8 -7
  81. package/dist/components/SynapseHomepageV2/WordPressNews.js.map +1 -1
  82. package/dist/components/SynapseHomepageV2/WordPressNewsItem.d.ts +5 -1
  83. package/dist/components/SynapseHomepageV2/WordPressNewsItem.d.ts.map +1 -1
  84. package/dist/components/SynapseHomepageV2/WordPressNewsItem.js +19 -11
  85. package/dist/components/SynapseHomepageV2/WordPressNewsItem.js.map +1 -1
  86. package/dist/components/SynapseTable/TablePagination.js.map +1 -1
  87. package/dist/components/SynapseTable/datasets/DatasetItemsEditor.js.map +1 -1
  88. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
  89. package/dist/components/TanStackTable/StyledTanStackTable.js.map +1 -1
  90. package/dist/components/WordPress/useWordPressPosts.js +1 -1
  91. package/dist/components/WordPress/useWordPressPosts.js.map +1 -1
  92. package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.d.ts +1 -8
  93. package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.d.ts.map +1 -1
  94. package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js +17 -12
  95. package/dist/components/entity/page/breadcrumbs/EntityPageBreadcrumbs.js.map +1 -1
  96. package/dist/components/entity/page/title_bar/EntityPageTitleBar.d.ts.map +1 -1
  97. package/dist/components/entity/page/title_bar/EntityPageTitleBar.js +20 -16
  98. package/dist/components/entity/page/title_bar/EntityPageTitleBar.js.map +1 -1
  99. package/dist/components/entity/page/title_bar/TitleBarProperties.d.ts +0 -1
  100. package/dist/components/entity/page/title_bar/TitleBarProperties.d.ts.map +1 -1
  101. package/dist/components/entity/page/title_bar/TitleBarProperties.js +17 -82
  102. package/dist/components/entity/page/title_bar/TitleBarProperties.js.map +1 -1
  103. package/dist/components/entity/page/title_bar/useGetEntityTitleBarProperties.d.ts.map +1 -1
  104. package/dist/components/entity/page/title_bar/useGetEntityTitleBarProperties.js +3 -4
  105. package/dist/components/entity/page/title_bar/useGetEntityTitleBarProperties.js.map +1 -1
  106. package/dist/components/menu/ComplexMenu.d.ts.map +1 -1
  107. package/dist/components/menu/ComplexMenu.js +5 -3
  108. package/dist/components/menu/ComplexMenu.js.map +1 -1
  109. package/dist/style/components/_data-grid-extra.css +1 -1
  110. package/dist/style/components/_data-grid-extra.scss +0 -6
  111. package/dist/testutils/ReactQueryMockUtils.js.map +1 -1
  112. package/dist/tsconfig.build.tsbuildinfo +1 -1
  113. package/dist/types/ThemeTypes.d.ts +2 -2
  114. package/dist/utils/functions/IsEqualTreatUndefinedAsMissing.js.map +1 -1
  115. package/dist/utils/hooks/useDebouncedEffect.js.map +1 -1
  116. package/dist/utils/hooks/useDetectSSOCode.js.map +1 -1
  117. package/dist/utils/hooks/useImmutableTableQuery/useImmutableTableQuery.js.map +1 -1
  118. package/dist/utils/hooks/useLogin.js.map +1 -1
  119. package/package.json +6 -6
@@ -1,96 +1,102 @@
1
1
  import { displayToast as e } from "../ToastMessage/ToastMessage.js";
2
2
  import t from "../../synapse-client/index.js";
3
- import { SynapseErrorBoundary as n } from "../error/ErrorBanner.js";
4
- import { useSynapseContext as r } from "../../utils/context/SynapseContext.js";
5
- import { useGetEntityHeaders as i } from "../../synapse-queries/entity/useGetEntityHeaders.js";
3
+ import { entityTypeToFriendlyName as n, getEntityTypeFromHeader as r } from "../../utils/functions/EntityTypeUtils.js";
4
+ import { SynapseErrorBoundary as i } from "../error/ErrorBanner.js";
5
+ import { useSynapseContext as a } from "../../utils/context/SynapseContext.js";
6
+ import { useGetEntityHeaders as o } from "../../synapse-queries/entity/useGetEntityHeaders.js";
6
7
  import "../../synapse-queries/index.js";
7
- import { NodeType as a, getLayoutedElements as o, isArrayEqual as s } from "./ProvenanceUtils.js";
8
- import { addActivityNode as ee, addEntityNode as te, addEntityPlaceholderNode as c, addExpandNode as l, addExternalNode as u, addUndefinedNode as d, findEntityNode as f, isRootEntity as p } from "./ProvenanceGraphUtils.js";
9
- import { useCallback as m, useEffect as h, useState as g } from "react";
10
- import { CircularProgress as ne } from "@mui/material";
11
- import { jsx as _ } from "react/jsx-runtime";
12
- import { USED_ENTITY_CONCRETE_TYPE_VALUE as v } from "@sage-bionetworks/synapse-types";
13
- import { useErrorHandler as y } from "react-error-boundary";
14
- import b, { Controls as x, ReactFlowProvider as S, getConnectedEdges as C, useEdgesState as w, useNodesState as T, useReactFlow as E } from "reactflow";
8
+ import { NodeType as s, getLayoutedElements as ee, isArrayEqual as c } from "./ProvenanceUtils.js";
9
+ import { addActivityNode as te, addEntityNode as ne, addEntityPlaceholderNode as re, addExpandNode as l, addExternalNode as u, addUndefinedNode as ie, findEntityNode as ae, isRootEntity as d } from "./ProvenanceGraphUtils.js";
10
+ import { useCallback as f, useEffect as p, useState as m } from "react";
11
+ import { Button as h, CircularProgress as g, Stack as _, Typography as v } from "@mui/material";
12
+ import { jsx as y, jsxs as b } from "react/jsx-runtime";
13
+ import { USED_ENTITY_CONCRETE_TYPE_VALUE as x } from "@sage-bionetworks/synapse-types";
14
+ import { useErrorHandler as S } from "react-error-boundary";
15
+ import C, { Controls as oe, ReactFlowProvider as w, getConnectedEdges as se, useEdgesState as ce, useNodesState as le, useReactFlow as ue } from "reactflow";
15
16
  import "reactflow/dist/style.css";
16
17
  //#region src/components/ProvenanceGraph/ProvenanceGraph.tsx
17
- var D = 400, O = .85, k = (n) => {
18
- let { entityRefs: S, containerHeight: k = "200px", initialNodes: A = [], initialEdges: j = [], onNodesChangedListener: M, onEdgesChangedListener: N } = n, { accessToken: P } = r(), [F, I] = g(A), [L, R] = g(j), [z, B] = T([]), [V, H] = w([]), [U, W] = g(), G = y(), { data: K, isSuccess: q } = i(S, { throwOnError: !0 });
19
- q && K && K.totalNumberOfResults == 0 && G(`Unable to load provenance for the given Synapse IDs: ${S.map((e) => e.targetId).join(",")}`);
20
- let J = K?.results, [Y, X] = g(!1), Z = E(), re = m((e, t) => {
21
- W(t);
22
- }, []), Q = m(async (e) => {
18
+ var T = 400, E = .85, D = "Edit Provenance", O = "No provenance data", de = (e) => `We don’t have any provenance information for this ${e} yet.`, k = "#3B4046", fe = "#F9F9FA", pe = "#4D535A", me = "#9EAAB7", he = "rgba(255, 255, 255, 0.60)", A = (i) => {
19
+ let { entityRefs: w, containerHeight: D = "200px", initialNodes: A = [], initialEdges: j = [], onNodesChangedListener: M, onEdgesChangedListener: N, onEditProvenanceClicked: P } = i, { accessToken: F } = a(), [I, L] = m(A), [R, z] = m(j), [B, V] = le([]), [H, U] = ce([]), [W, G] = m(), [ge, _e] = m(!1), K = S(), { data: q, isSuccess: ve } = o(w, { throwOnError: !0 }), J = [
20
+ s.ENTITY_PLACEHOLDER,
21
+ s.EXTERNAL,
22
+ s.ACTIVITY,
23
+ s.EXPAND
24
+ ], ye = B.some((e) => J.includes(e.data.type)), be = ge && !ye;
25
+ ve && q && q.totalNumberOfResults == 0 && K(`Unable to load provenance for the given Synapse IDs: ${w.map((e) => e.targetId).join(",")}`);
26
+ let Y = q?.results, xe = Y?.[0] ? n(r(Y[0])).toLowerCase() : "entity", [X, Se] = m(!1), Z = ue(), Ce = f((e, t) => {
27
+ G(t);
28
+ }, []), Q = f(async (e) => {
23
29
  let { entityHeader: n, nodesCopy: r, edgesCopy: i, usedInActivity: a } = e;
24
- te({
30
+ ne({
25
31
  entityHeader: n,
26
32
  activity: a,
27
33
  nodesCopy: r,
28
34
  edgesCopy: i
29
35
  });
30
36
  try {
31
- let e = await t.getActivityForEntity(n.id, n.versionNumber, P);
32
- (!p({
37
+ let e = await t.getActivityForEntity(n.id, n.versionNumber, F);
38
+ (!d({
33
39
  entityHeader: n,
34
- rootEntityHeaders: J
35
- }) || e.used && e.used.length >= D) && l({
40
+ rootEntityHeaders: Y
41
+ }) || e.used && e.used.length >= T) && l({
36
42
  entityHeader: n,
37
43
  itemCount: e.used?.length,
38
44
  nodesCopy: r,
39
45
  edgesCopy: i
40
46
  });
41
47
  } catch (e) {
42
- console.error(e), p({
48
+ console.error(e), d({
43
49
  entityHeader: n,
44
- rootEntityHeaders: J
45
- }) && d({
50
+ rootEntityHeaders: Y
51
+ }) && ie({
46
52
  entityHeader: n,
47
53
  nodesCopy: r,
48
54
  edgesCopy: i
49
55
  });
50
56
  }
51
- }, [P, J]);
52
- h(() => {
53
- !Y && z.length > 0 && setTimeout(() => {
54
- if (J) {
55
- let e = f(J[0], z);
57
+ }, [F, Y]);
58
+ p(() => {
59
+ !X && B.length > 0 && setTimeout(() => {
60
+ if (Y) {
61
+ let e = ae(Y[0], B);
56
62
  if (e) {
57
- let t = Z.getZoom(), n = t > O ? O : t;
63
+ let t = Z.getZoom(), n = t > E ? E : t;
58
64
  Z?.setCenter(e.position.x + 150, e.position.y - 30, {
59
65
  zoom: n,
60
66
  duration: 0
61
67
  });
62
68
  }
63
- X(!0);
69
+ Se(!0);
64
70
  }
65
71
  });
66
72
  }, [
67
- Y,
68
- z,
73
+ X,
74
+ B,
69
75
  Z,
70
- J
76
+ Y
71
77
  ]);
72
- let $ = m(async (e) => {
78
+ let $ = f(async (e) => {
73
79
  let { entityHeader: n, nodesCopy: r, edgesCopy: i } = e;
74
80
  try {
75
- let e = await t.getActivityForEntity(n.id, n.versionNumber, P);
76
- if (ee({
81
+ let e = await t.getActivityForEntity(n.id, n.versionNumber, F);
82
+ if (te({
77
83
  activity: e,
78
84
  entityHeader: n,
79
85
  nodesCopy: r,
80
86
  edgesCopy: i
81
- }), e.used && e.used.length < D) {
87
+ }), e.used && e.used.length < T) {
82
88
  let n = [];
83
89
  e.used.forEach((t) => {
84
- t.concreteType == v ? n.push(t.reference) : u({
90
+ t.concreteType == x ? n.push(t.reference) : u({
85
91
  usedURL: t,
86
92
  activity: e,
87
93
  nodesCopy: r,
88
94
  edgesCopy: i
89
95
  });
90
96
  });
91
- let { results: a } = await t.getEntityHeaders(n, P);
97
+ let { results: a } = await t.getEntityHeaders(n, F);
92
98
  n.filter((e) => a.find((t) => t.id == e.targetId) == null).forEach((t) => {
93
- c({
99
+ re({
94
100
  ref: t,
95
101
  activity: e,
96
102
  nodesCopy: r,
@@ -110,11 +116,11 @@ var D = 400, O = .85, k = (n) => {
110
116
  } catch (e) {
111
117
  console.error(e);
112
118
  }
113
- }, [P, Q]);
114
- h(() => {
115
- if (J && F.length == 0) {
116
- let e = [...F], t = [...L], n = [];
117
- J.forEach((r) => {
119
+ }, [F, Q]);
120
+ p(() => {
121
+ if (Y && I.length == 0) {
122
+ let e = [...I], t = [...R], n = [];
123
+ Y.forEach((r) => {
118
124
  let i = Q({
119
125
  entityHeader: r,
120
126
  nodesCopy: e,
@@ -128,86 +134,135 @@ var D = 400, O = .85, k = (n) => {
128
134
  });
129
135
  n.push(a);
130
136
  }), Promise.allSettled(n).finally(() => {
131
- I(e), R(t);
137
+ L(e), z(t), _e(!0);
132
138
  });
133
139
  }
134
140
  }, [
135
141
  Q,
136
- G,
142
+ K,
137
143
  $,
138
- J,
139
- S,
140
- L,
141
- F
142
- ]), h(() => {
143
- let t = U?.data;
144
- if (U && t?.type == a.EXPAND) {
144
+ Y,
145
+ w,
146
+ R,
147
+ I
148
+ ]), p(() => {
149
+ let t = W?.data;
150
+ if (W && t?.type == s.EXPAND) {
145
151
  let n = t.props;
146
- if (n.itemCount > D) {
152
+ if (n.itemCount > T) {
147
153
  e("Web visualization does not support expanding this many items at this time.", "danger");
148
154
  return;
149
155
  } else {
150
- t.label = /* @__PURE__ */ _(ne, { size: 30 });
151
- let e = F.filter((e) => e.id != U.id), r = C([U], L)[0], i = L.filter((e) => e != r);
156
+ t.label = /* @__PURE__ */ y(g, { size: 30 });
157
+ let e = I.filter((e) => e.id != W.id), r = se([W], R)[0], i = R.filter((e) => e != r);
152
158
  $({
153
159
  entityHeader: n.entityHeader,
154
160
  nodesCopy: e,
155
161
  edgesCopy: i
156
162
  }).finally(() => {
157
- I(e), R(i);
163
+ L(e), z(i);
158
164
  });
159
165
  }
160
- W(void 0);
166
+ G(void 0);
161
167
  }
162
168
  }, [
163
- U,
164
- F,
165
- L,
169
+ W,
170
+ I,
171
+ R,
166
172
  $
167
- ]), h(() => {
168
- let { nodes: e, edges: t } = o(F, L, "TB");
169
- s(e, z) || (B(e), M && M(e)), s(t, V) || (H(t), N && N(t));
173
+ ]), p(() => {
174
+ let { nodes: e, edges: t } = ee(I, R, "TB");
175
+ c(e, B) || (V(e), M && M(e)), c(t, H) || (U(t), N && N(t));
170
176
  }, [
171
- F,
172
- L,
173
- z,
174
- V,
177
+ I,
178
+ R,
175
179
  B,
176
180
  H,
177
- Y,
181
+ V,
182
+ U,
183
+ X,
178
184
  Z,
179
- S,
185
+ w,
180
186
  M,
181
187
  N
182
188
  ]);
183
- let ie = m((e) => {
189
+ let we = f((e) => {
184
190
  e && e.deltaX !== void 0 && e.deltaY !== void 0 && window.scrollTo(window.scrollX + e.deltaX, window.scrollY + e.deltaY);
185
191
  }, []);
186
- return /* @__PURE__ */ _("div", {
192
+ return /* @__PURE__ */ y("div", {
187
193
  className: "ProvenanceWidget",
188
194
  role: "graphics-doc",
189
195
  style: {
190
196
  width: "100%",
191
- height: k
197
+ height: D,
198
+ backgroundColor: fe,
199
+ padding: "15px"
192
200
  },
193
- children: /* @__PURE__ */ _(b, {
201
+ children: be ? /* @__PURE__ */ b(_, {
202
+ sx: {
203
+ display: "flex",
204
+ height: "100%",
205
+ alignItems: "center",
206
+ justifyContent: "center",
207
+ textAlign: "center"
208
+ },
209
+ children: [
210
+ /* @__PURE__ */ y(v, {
211
+ sx: {
212
+ color: k,
213
+ fontSize: "16px",
214
+ lineHeight: "24px",
215
+ fontWeight: 540,
216
+ marginBottom: "12px"
217
+ },
218
+ children: O
219
+ }),
220
+ /* @__PURE__ */ y(v, {
221
+ sx: {
222
+ color: k,
223
+ fontSize: "14px",
224
+ lineHeight: "20px",
225
+ fontWeight: 440
226
+ },
227
+ children: de(xe)
228
+ }),
229
+ P && /* @__PURE__ */ y(h, {
230
+ variant: "outlined",
231
+ sx: {
232
+ borderRadius: "6px",
233
+ border: "1px solid",
234
+ borderColor: me,
235
+ background: he,
236
+ color: pe,
237
+ fontWeight: 540,
238
+ lineHeight: "12px",
239
+ letterSpacing: "-0.24px",
240
+ marginTop: "20px",
241
+ height: "28px",
242
+ padding: "8px"
243
+ },
244
+ onClick: P,
245
+ children: "Edit Provenance"
246
+ })
247
+ ]
248
+ }) : /* @__PURE__ */ y(C, {
194
249
  defaultViewport: {
195
250
  x: 0,
196
251
  y: 0,
197
- zoom: O
252
+ zoom: E
198
253
  },
199
- nodes: z,
200
- edges: V,
201
- onNodeClick: re,
254
+ nodes: B,
255
+ edges: H,
256
+ onNodeClick: Ce,
202
257
  attributionPosition: "bottom-right",
203
258
  onConnect: void 0,
204
259
  zoomOnScroll: !1,
205
- onPaneScroll: ie,
206
- children: /* @__PURE__ */ _(x, {})
260
+ onPaneScroll: we,
261
+ children: /* @__PURE__ */ y(oe, {})
207
262
  })
208
263
  });
209
- }, A = (e) => /* @__PURE__ */ _(n, { children: /* @__PURE__ */ _(S, { children: /* @__PURE__ */ _(k, { ...e }) }) });
264
+ }, j = (e) => /* @__PURE__ */ y(i, { children: /* @__PURE__ */ y(w, { children: /* @__PURE__ */ y(A, { ...e }) }) });
210
265
  //#endregion
211
- export { A as default };
266
+ export { D as EDIT_PROVENANCE_TEXT, O as NO_PROVENANCE_TITLE, j as default };
212
267
 
213
268
  //# sourceMappingURL=ProvenanceGraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProvenanceGraph.js","names":[],"sources":["../../../src/components/ProvenanceGraph/ProvenanceGraph.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { useGetEntityHeaders } from '@/synapse-queries'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { CircularProgress } from '@mui/material'\nimport {\n Activity,\n EntityHeader,\n ReferenceList,\n Used,\n USED_ENTITY_CONCRETE_TYPE_VALUE,\n UsedEntity,\n UsedURL,\n} from '@sage-bionetworks/synapse-types'\nimport { MouseEvent, useCallback, useEffect, useState, WheelEvent } from 'react'\nimport { useErrorHandler } from 'react-error-boundary'\nimport ReactFlow, {\n Controls,\n Edge,\n getConnectedEdges,\n Node,\n ReactFlowProvider,\n useEdgesState,\n useNodesState,\n useReactFlow,\n} from 'reactflow'\nimport { SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { ExpandGraphNodeDataProps } from './ExpandGraphNodeLabel'\nimport {\n addActivityNode,\n addEntityNode,\n addEntityPlaceholderNode,\n addExpandNode,\n addExternalNode,\n addUndefinedNode,\n findEntityNode,\n isRootEntity,\n} from './ProvenanceGraphUtils'\nimport {\n getLayoutedElements,\n isArrayEqual,\n NodeType,\n ProvenanceNodeData,\n} from './ProvenanceUtils'\nimport 'reactflow/dist/style.css'\n\nexport type ProvenanceProps = {\n // what entity nodes should we start with?\n entityRefs: ReferenceList\n containerHeight?: string\n initialNodes?: Node[]\n initialEdges?: Edge[]\n onNodesChangedListener?: (nodes: Node[]) => void\n onEdgesChangedListener?: (edges: Edge[]) => void\n}\n\nconst MAX_ACTIVITY_EXPAND_NODES = 400\nconst DEFAULT_ZOOM = 0.85\n\n/**\n * Renders a Provenance Graph for a set of entities.\n * New Nodes are added to tempNodes, and new Edges are added to tempEdges.\n * On change, these are fed into the dagre js graph library to figure out the node positions,\n * and the output stored in 'nodes' and 'edges'. The 'nodes' and 'edges' arrays are used by the\n * ReactFlow component.\n */\nconst ProvenanceReactFlow = (props: ProvenanceProps): React.ReactNode => {\n const {\n entityRefs: rootEntityRefs,\n containerHeight = '200px',\n initialNodes = [],\n initialEdges = [],\n onNodesChangedListener,\n onEdgesChangedListener,\n } = props\n const { accessToken } = useSynapseContext()\n const [tempNodes, setTempNodes] = useState<Node[]>(initialNodes)\n const [tempEdges, setTempEdges] = useState<Edge[]>(initialEdges)\n const [nodes, setNodes] = useNodesState([])\n const [edges, setEdges] = useEdgesState([])\n const [clickedNode, setClickedNode] = useState<Node>()\n const handleError = useErrorHandler()\n\n const { data: rootEntityHeadersPage, isSuccess } = useGetEntityHeaders(\n rootEntityRefs,\n { throwOnError: true },\n )\n if (\n isSuccess &&\n rootEntityHeadersPage &&\n rootEntityHeadersPage.totalNumberOfResults == 0\n ) {\n const synapseIds = rootEntityRefs.map(ref => ref.targetId).join(',')\n handleError(\n `Unable to load provenance for the given Synapse IDs: ${synapseIds}`,\n )\n }\n const rootEntityHeaders = rootEntityHeadersPage?.results\n const [initializedPosition, setInitializedPosition] = useState<boolean>(false)\n\n // Get the react flow instance so we attempt to properly center the view.\n const reactFlowInstance = useReactFlow()\n\n const onClickNode = useCallback((_event: MouseEvent, node: Node) => {\n setClickedNode(node)\n }, [])\n\n /**\n * Called when we have a new entity to add to the graph. This will result in adding\n * a new Entity Node to the nodesCopy, a link from the usedInActivity to the new Entity Node,\n * AND it will look for an Activity associated with the new entity. If an Activity is found,\n * it will add an Expand Node for the user to click (to expand to see this Activity!).\n * If this is a root node (starting entity node), then we automatically add the Activity Node\n * and process it.\n */\n const addEntity = useCallback(\n async (params: {\n entityHeader: EntityHeader\n usedInActivity?: Activity\n nodesCopy: Node[]\n edgesCopy: Edge[]\n }) => {\n const { entityHeader, nodesCopy, edgesCopy, usedInActivity } = params\n addEntityNode({\n entityHeader,\n activity: usedInActivity,\n nodesCopy,\n edgesCopy,\n })\n //look for Activity\n try {\n const activity = await SynapseClient.getActivityForEntity(\n entityHeader.id,\n entityHeader.versionNumber,\n accessToken,\n )\n // if this is not a root node (or there are too many items to show), add an expand node\n if (\n !isRootEntity({ entityHeader, rootEntityHeaders }) ||\n (activity.used && activity.used.length >= MAX_ACTIVITY_EXPAND_NODES)\n ) {\n addExpandNode({\n entityHeader,\n itemCount: activity.used?.length,\n nodesCopy,\n edgesCopy,\n })\n }\n } catch (e) {\n // Activity is not accessible\n console.error(e)\n if (\n isRootEntity({\n entityHeader,\n rootEntityHeaders,\n })\n ) {\n // add provenance undefined node\n addUndefinedNode({\n entityHeader,\n nodesCopy,\n edgesCopy,\n })\n }\n }\n },\n [accessToken, rootEntityHeaders],\n )\n\n /**\n * This effect attempts to center the graph on one of the root nodes.\n * Only initializes after after a root node has been added to the graph.\n */\n useEffect(() => {\n if (!initializedPosition && nodes.length > 0) {\n setTimeout(() => {\n if (rootEntityHeaders) {\n const rootEntityNode = findEntityNode(rootEntityHeaders[0], nodes)\n if (rootEntityNode) {\n const currentZoom = reactFlowInstance.getZoom()\n const zoom = currentZoom > DEFAULT_ZOOM ? DEFAULT_ZOOM : currentZoom\n reactFlowInstance?.setCenter(\n rootEntityNode.position.x + 150,\n rootEntityNode.position.y - 30,\n { zoom, duration: 0 },\n )\n }\n setInitializedPosition(true)\n }\n })\n }\n }, [initializedPosition, nodes, reactFlowInstance, rootEntityHeaders])\n\n /**\n * This is called when the user clicks on an Expand Node. It will add the associated Activity\n * and all \"used\" items (entities and urls) to the graph by adding items to the nodesCopy and edgesCopy arrays.\n */\n const onExpandEntity = useCallback(\n async (params: {\n entityHeader: EntityHeader\n nodesCopy: Node[]\n edgesCopy: Edge[]\n }) => {\n const { entityHeader, nodesCopy, edgesCopy } = params\n try {\n const activity = await SynapseClient.getActivityForEntity(\n entityHeader.id,\n entityHeader.versionNumber,\n accessToken,\n )\n addActivityNode({\n activity,\n entityHeader,\n nodesCopy,\n edgesCopy,\n })\n // go through Activity.used array to add these nodes/edges\n if (activity.used && activity.used.length < MAX_ACTIVITY_EXPAND_NODES) {\n const usedEntityReferences: ReferenceList = []\n activity.used.forEach((usedItem: Used) => {\n if (usedItem.concreteType == USED_ENTITY_CONCRETE_TYPE_VALUE) {\n usedEntityReferences.push((usedItem as UsedEntity).reference)\n } else {\n // UsedURL\n const usedURL = usedItem as UsedURL\n addExternalNode({ usedURL, activity, nodesCopy, edgesCopy })\n }\n })\n const usedEntityHeadersPage = await SynapseClient.getEntityHeaders(\n usedEntityReferences,\n accessToken,\n )\n const { results: usedEntityHeaderPageResults } = usedEntityHeadersPage\n // find refs that were not returned by the entity header call\n const refsMissingEntityHeaders = usedEntityReferences.filter(ref => {\n return (\n usedEntityHeaderPageResults.find(header => {\n return header.id == ref.targetId\n }) == undefined\n )\n })\n refsMissingEntityHeaders.forEach(ref => {\n addEntityPlaceholderNode({ ref, activity, nodesCopy, edgesCopy })\n })\n const addEntityPromises: Promise<void>[] = []\n usedEntityHeaderPageResults.forEach(header => {\n addEntityPromises.push(\n addEntity({\n entityHeader: header,\n nodesCopy,\n edgesCopy,\n usedInActivity: activity,\n }),\n )\n })\n await Promise.allSettled(addEntityPromises)\n }\n } catch (e) {\n // Activity is not accessible\n console.error(e)\n }\n },\n [accessToken, addEntity],\n )\n\n /**\n * This effect code executes when no nodes have been added.\n * It will add the root nodes, and attempt to expand the root nodes.\n */\n useEffect(() => {\n if (rootEntityHeaders && tempNodes.length == 0) {\n const nodesCopy = [...tempNodes]\n const edgesCopy = [...tempEdges]\n const addAndExpandPromises: Promise<void>[] = []\n rootEntityHeaders.forEach(header => {\n const addEntityPromise = addEntity({\n entityHeader: header,\n nodesCopy,\n edgesCopy,\n })\n addAndExpandPromises.push(addEntityPromise)\n\n const expandEntityPromise = onExpandEntity({\n entityHeader: header,\n nodesCopy,\n edgesCopy,\n })\n addAndExpandPromises.push(expandEntityPromise)\n })\n Promise.allSettled(addAndExpandPromises).finally(() => {\n setTempNodes(nodesCopy)\n setTempEdges(edgesCopy)\n })\n }\n }, [\n addEntity,\n handleError,\n onExpandEntity,\n rootEntityHeaders,\n rootEntityRefs,\n tempEdges,\n tempNodes,\n ])\n\n /**\n * This effect code executes when a node is clicked.\n * We check to see if it is an expand node. If it is, then we remove the expand node (and associated edge)\n * and ask for the Activity and associated \"used\" nodes (entities and URLs)\n */\n useEffect(() => {\n const nodeData: ProvenanceNodeData = clickedNode?.data as ProvenanceNodeData\n if (clickedNode && nodeData?.type == NodeType.EXPAND) {\n const expandNodeDataProps = nodeData.props as ExpandGraphNodeDataProps\n if (expandNodeDataProps.itemCount > MAX_ACTIVITY_EXPAND_NODES) {\n displayToast(\n 'Web visualization does not support expanding this many items at this time.',\n 'danger',\n )\n return\n } else {\n // graph will be used outside of synapse, so show a non-branded spinner\n nodeData.label = <CircularProgress size={30} />\n // remove clicked node\n const nodesWithoutExpandNode = tempNodes.filter(\n node => node.id != clickedNode.id,\n )\n const edgeToRemove = getConnectedEdges([clickedNode], tempEdges)[0]\n const edgesWithoutExpandEdge = tempEdges.filter(\n edge => edge != edgeToRemove,\n )\n onExpandEntity({\n entityHeader: expandNodeDataProps.entityHeader,\n nodesCopy: nodesWithoutExpandNode,\n edgesCopy: edgesWithoutExpandEdge,\n }).finally(() => {\n setTempNodes(nodesWithoutExpandNode)\n setTempEdges(edgesWithoutExpandEdge)\n })\n }\n setClickedNode(undefined)\n }\n }, [clickedNode, tempNodes, tempEdges, onExpandEntity])\n\n /**\n * This effect code is run when the graph nodes or edges change.\n * It feeds the nodes and edges into our layout library to figure out where they should be positioned.\n * The result is saved in the state variable \"nodes\" and \"edges\".\n */\n useEffect(() => {\n const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(\n tempNodes,\n tempEdges,\n 'TB',\n )\n // hack: ProvenanceUtils.getProvenanceNode() returns a new object every time, so check to see if\n // there were any real changes\n if (!isArrayEqual(layoutedNodes, nodes)) {\n setNodes(layoutedNodes)\n if (onNodesChangedListener) {\n onNodesChangedListener(layoutedNodes)\n }\n }\n if (!isArrayEqual(layoutedEdges, edges)) {\n setEdges(layoutedEdges)\n if (onEdgesChangedListener) {\n onEdgesChangedListener(layoutedEdges)\n }\n }\n }, [\n tempNodes,\n tempEdges,\n nodes,\n edges,\n setNodes,\n setEdges,\n initializedPosition,\n reactFlowInstance,\n rootEntityRefs,\n onNodesChangedListener,\n onEdgesChangedListener,\n ])\n\n const onPaneScrollFunction: (event?: WheelEvent) => void = useCallback(\n event => {\n // Cannot simply check the truthy value of event.deltaX (or Y) because the value might be 0 (or -0), which is falsy\n if (\n event &&\n typeof event.deltaX !== 'undefined' &&\n typeof event.deltaY !== 'undefined'\n ) {\n window.scrollTo(\n window.scrollX + event.deltaX,\n window.scrollY + event.deltaY,\n )\n }\n },\n [],\n )\n return (\n <div\n className=\"ProvenanceWidget\"\n role=\"graphics-doc\" //https://www.w3.org/wiki/SVG_Accessibility/ARIA_roles_for_charts#Document_Roles\n style={{ width: '100%', height: containerHeight }}\n >\n <ReactFlow\n defaultViewport={{ x: 0, y: 0, zoom: DEFAULT_ZOOM }}\n nodes={nodes}\n edges={edges}\n onNodeClick={onClickNode}\n // onNodesChange={onNodesChange} // SWC-6804: When the nodes/edges are updated (expanded) the graph is already re-rendered.\n // onEdgesChange={onEdgesChange} // Specifying these callbacks causes an infinite re-rendering loop.\n attributionPosition=\"bottom-right\"\n onConnect={undefined}\n zoomOnScroll={false}\n onPaneScroll={onPaneScrollFunction}\n >\n <Controls />\n </ReactFlow>\n </div>\n )\n}\n\nconst ProvenanceGraph = (props: ProvenanceProps): React.ReactNode => {\n return (\n <SynapseErrorBoundary>\n <ReactFlowProvider>\n <ProvenanceReactFlow {...props} />\n </ReactFlowProvider>\n </SynapseErrorBoundary>\n )\n}\n\nexport default ProvenanceGraph\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProvenanceGraph.js","names":[],"sources":["../../../src/components/ProvenanceGraph/ProvenanceGraph.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport { useGetEntityHeaders } from '@/synapse-queries'\nimport {\n entityTypeToFriendlyName,\n getEntityTypeFromHeader,\n} from '@/utils/functions/EntityTypeUtils'\nimport { useSynapseContext } from '@/utils/context/SynapseContext'\nimport { CircularProgress, Typography, Button, Stack } from '@mui/material'\nimport {\n Activity,\n EntityHeader,\n ReferenceList,\n Used,\n USED_ENTITY_CONCRETE_TYPE_VALUE,\n UsedEntity,\n UsedURL,\n} from '@sage-bionetworks/synapse-types'\nimport { MouseEvent, useCallback, useEffect, useState, WheelEvent } from 'react'\nimport { useErrorHandler } from 'react-error-boundary'\nimport ReactFlow, {\n Controls,\n Edge,\n getConnectedEdges,\n Node,\n ReactFlowProvider,\n useEdgesState,\n useNodesState,\n useReactFlow,\n} from 'reactflow'\nimport { SynapseErrorBoundary } from '../error/ErrorBanner'\nimport { displayToast } from '../ToastMessage/ToastMessage'\nimport { ExpandGraphNodeDataProps } from './ExpandGraphNodeLabel'\nimport {\n addActivityNode,\n addEntityNode,\n addEntityPlaceholderNode,\n addExpandNode,\n addExternalNode,\n addUndefinedNode,\n findEntityNode,\n isRootEntity,\n} from './ProvenanceGraphUtils'\nimport {\n getLayoutedElements,\n isArrayEqual,\n NodeType,\n ProvenanceNodeData,\n} from './ProvenanceUtils'\nimport 'reactflow/dist/style.css'\n\nexport type ProvenanceProps = {\n // what entity nodes should we start with?\n entityRefs: ReferenceList\n containerHeight?: string\n initialNodes?: Node[]\n initialEdges?: Edge[]\n onNodesChangedListener?: (nodes: Node[]) => void\n onEdgesChangedListener?: (edges: Edge[]) => void\n onEditProvenanceClicked?: () => void\n}\n\nconst MAX_ACTIVITY_EXPAND_NODES = 400\nconst DEFAULT_ZOOM = 0.85\nexport const EDIT_PROVENANCE_TEXT = 'Edit Provenance'\nexport const NO_PROVENANCE_TITLE = 'No provenance data'\nconst NO_PROVENANCE_MESSAGE = (entityTypeName: string) =>\n `We don’t have any provenance information for this ${entityTypeName} yet.`\nconst NO_PROVENANCE_TEXT_COLOR = '#3B4046'\nconst PROVENANCE_BACKGROUND_COLOR = '#F9F9FA'\nconst EDIT_PROVENANCE_BUTTON_TEXT_COLOR = '#4D535A'\nconst EDIT_PROVENANCE_BUTTON_BORDER_COLOR = '#9EAAB7'\nconst EDIT_PROVENANCE_BUTTON_BACKGROUND_COLOR = 'rgba(255, 255, 255, 0.60)'\n\n/**\n * Renders a Provenance Graph for a set of entities.\n * New Nodes are added to tempNodes, and new Edges are added to tempEdges.\n * On change, these are fed into the dagre js graph library to figure out the node positions,\n * and the output stored in 'nodes' and 'edges'. The 'nodes' and 'edges' arrays are used by the\n * ReactFlow component.\n */\nconst ProvenanceReactFlow = (props: ProvenanceProps): React.ReactNode => {\n const {\n entityRefs: rootEntityRefs,\n containerHeight = '200px',\n initialNodes = [],\n initialEdges = [],\n onNodesChangedListener,\n onEdgesChangedListener,\n onEditProvenanceClicked,\n } = props\n const { accessToken } = useSynapseContext()\n const [tempNodes, setTempNodes] = useState<Node[]>(initialNodes)\n const [tempEdges, setTempEdges] = useState<Edge[]>(initialEdges)\n const [nodes, setNodes] = useNodesState([])\n const [edges, setEdges] = useEdgesState([])\n const [clickedNode, setClickedNode] = useState<Node>()\n const [initialBuildComplete, setInitialBuildComplete] =\n useState<boolean>(false)\n const handleError = useErrorHandler()\n\n const { data: rootEntityHeadersPage, isSuccess } = useGetEntityHeaders(\n rootEntityRefs,\n { throwOnError: true },\n )\n\n const PROVENANCE_NODE_TYPES = [\n NodeType.ENTITY_PLACEHOLDER,\n NodeType.EXTERNAL,\n NodeType.ACTIVITY,\n NodeType.EXPAND,\n ]\n const hasProvenanceNodes = nodes.some(node =>\n PROVENANCE_NODE_TYPES.includes((node.data as ProvenanceNodeData).type),\n )\n\n const showNoProvenance = initialBuildComplete && !hasProvenanceNodes\n\n if (\n isSuccess &&\n rootEntityHeadersPage &&\n rootEntityHeadersPage.totalNumberOfResults == 0\n ) {\n const synapseIds = rootEntityRefs.map(ref => ref.targetId).join(',')\n handleError(\n `Unable to load provenance for the given Synapse IDs: ${synapseIds}`,\n )\n }\n const rootEntityHeaders = rootEntityHeadersPage?.results\n const entityTypeName = rootEntityHeaders?.[0]\n ? entityTypeToFriendlyName(\n getEntityTypeFromHeader(rootEntityHeaders[0]),\n ).toLowerCase()\n : 'entity'\n const [initializedPosition, setInitializedPosition] = useState<boolean>(false)\n\n // Get the react flow instance so we attempt to properly center the view.\n const reactFlowInstance = useReactFlow()\n\n const onClickNode = useCallback((_event: MouseEvent, node: Node) => {\n setClickedNode(node)\n }, [])\n\n /**\n * Called when we have a new entity to add to the graph. This will result in adding\n * a new Entity Node to the nodesCopy, a link from the usedInActivity to the new Entity Node,\n * AND it will look for an Activity associated with the new entity. If an Activity is found,\n * it will add an Expand Node for the user to click (to expand to see this Activity!).\n * If this is a root node (starting entity node), then we automatically add the Activity Node\n * and process it.\n */\n const addEntity = useCallback(\n async (params: {\n entityHeader: EntityHeader\n usedInActivity?: Activity\n nodesCopy: Node[]\n edgesCopy: Edge[]\n }) => {\n const { entityHeader, nodesCopy, edgesCopy, usedInActivity } = params\n addEntityNode({\n entityHeader,\n activity: usedInActivity,\n nodesCopy,\n edgesCopy,\n })\n //look for Activity\n try {\n const activity = await SynapseClient.getActivityForEntity(\n entityHeader.id,\n entityHeader.versionNumber,\n accessToken,\n )\n // if this is not a root node (or there are too many items to show), add an expand node\n if (\n !isRootEntity({ entityHeader, rootEntityHeaders }) ||\n (activity.used && activity.used.length >= MAX_ACTIVITY_EXPAND_NODES)\n ) {\n addExpandNode({\n entityHeader,\n itemCount: activity.used?.length,\n nodesCopy,\n edgesCopy,\n })\n }\n } catch (e) {\n // Activity is not accessible\n console.error(e)\n if (\n isRootEntity({\n entityHeader,\n rootEntityHeaders,\n })\n ) {\n // add provenance undefined node\n addUndefinedNode({\n entityHeader,\n nodesCopy,\n edgesCopy,\n })\n }\n }\n },\n [accessToken, rootEntityHeaders],\n )\n\n /**\n * This effect attempts to center the graph on one of the root nodes.\n * Only initializes after after a root node has been added to the graph.\n */\n useEffect(() => {\n if (!initializedPosition && nodes.length > 0) {\n setTimeout(() => {\n if (rootEntityHeaders) {\n const rootEntityNode = findEntityNode(rootEntityHeaders[0], nodes)\n if (rootEntityNode) {\n const currentZoom = reactFlowInstance.getZoom()\n const zoom = currentZoom > DEFAULT_ZOOM ? DEFAULT_ZOOM : currentZoom\n reactFlowInstance?.setCenter(\n rootEntityNode.position.x + 150,\n rootEntityNode.position.y - 30,\n { zoom, duration: 0 },\n )\n }\n setInitializedPosition(true)\n }\n })\n }\n }, [initializedPosition, nodes, reactFlowInstance, rootEntityHeaders])\n\n /**\n * This is called when the user clicks on an Expand Node. It will add the associated Activity\n * and all \"used\" items (entities and urls) to the graph by adding items to the nodesCopy and edgesCopy arrays.\n */\n const onExpandEntity = useCallback(\n async (params: {\n entityHeader: EntityHeader\n nodesCopy: Node[]\n edgesCopy: Edge[]\n }) => {\n const { entityHeader, nodesCopy, edgesCopy } = params\n try {\n const activity = await SynapseClient.getActivityForEntity(\n entityHeader.id,\n entityHeader.versionNumber,\n accessToken,\n )\n addActivityNode({\n activity,\n entityHeader,\n nodesCopy,\n edgesCopy,\n })\n // go through Activity.used array to add these nodes/edges\n if (activity.used && activity.used.length < MAX_ACTIVITY_EXPAND_NODES) {\n const usedEntityReferences: ReferenceList = []\n activity.used.forEach((usedItem: Used) => {\n if (usedItem.concreteType == USED_ENTITY_CONCRETE_TYPE_VALUE) {\n usedEntityReferences.push((usedItem as UsedEntity).reference)\n } else {\n // UsedURL\n const usedURL = usedItem as UsedURL\n addExternalNode({ usedURL, activity, nodesCopy, edgesCopy })\n }\n })\n const usedEntityHeadersPage = await SynapseClient.getEntityHeaders(\n usedEntityReferences,\n accessToken,\n )\n const { results: usedEntityHeaderPageResults } = usedEntityHeadersPage\n // find refs that were not returned by the entity header call\n const refsMissingEntityHeaders = usedEntityReferences.filter(ref => {\n return (\n usedEntityHeaderPageResults.find(header => {\n return header.id == ref.targetId\n }) == undefined\n )\n })\n refsMissingEntityHeaders.forEach(ref => {\n addEntityPlaceholderNode({ ref, activity, nodesCopy, edgesCopy })\n })\n const addEntityPromises: Promise<void>[] = []\n usedEntityHeaderPageResults.forEach(header => {\n addEntityPromises.push(\n addEntity({\n entityHeader: header,\n nodesCopy,\n edgesCopy,\n usedInActivity: activity,\n }),\n )\n })\n await Promise.allSettled(addEntityPromises)\n }\n } catch (e) {\n // Activity is not accessible\n console.error(e)\n }\n },\n [accessToken, addEntity],\n )\n\n /**\n * This effect code executes when no nodes have been added.\n * It will add the root nodes, and attempt to expand the root nodes.\n */\n useEffect(() => {\n if (rootEntityHeaders && tempNodes.length == 0) {\n const nodesCopy = [...tempNodes]\n const edgesCopy = [...tempEdges]\n const addAndExpandPromises: Promise<void>[] = []\n rootEntityHeaders.forEach(header => {\n const addEntityPromise = addEntity({\n entityHeader: header,\n nodesCopy,\n edgesCopy,\n })\n addAndExpandPromises.push(addEntityPromise)\n\n const expandEntityPromise = onExpandEntity({\n entityHeader: header,\n nodesCopy,\n edgesCopy,\n })\n addAndExpandPromises.push(expandEntityPromise)\n })\n Promise.allSettled(addAndExpandPromises).finally(() => {\n setTempNodes(nodesCopy)\n setTempEdges(edgesCopy)\n setInitialBuildComplete(true)\n })\n }\n }, [\n addEntity,\n handleError,\n onExpandEntity,\n rootEntityHeaders,\n rootEntityRefs,\n tempEdges,\n tempNodes,\n ])\n\n /**\n * This effect code executes when a node is clicked.\n * We check to see if it is an expand node. If it is, then we remove the expand node (and associated edge)\n * and ask for the Activity and associated \"used\" nodes (entities and URLs)\n */\n useEffect(() => {\n const nodeData: ProvenanceNodeData = clickedNode?.data as ProvenanceNodeData\n if (clickedNode && nodeData?.type == NodeType.EXPAND) {\n const expandNodeDataProps = nodeData.props as ExpandGraphNodeDataProps\n if (expandNodeDataProps.itemCount > MAX_ACTIVITY_EXPAND_NODES) {\n displayToast(\n 'Web visualization does not support expanding this many items at this time.',\n 'danger',\n )\n return\n } else {\n // graph will be used outside of synapse, so show a non-branded spinner\n nodeData.label = <CircularProgress size={30} />\n // remove clicked node\n const nodesWithoutExpandNode = tempNodes.filter(\n node => node.id != clickedNode.id,\n )\n const edgeToRemove = getConnectedEdges([clickedNode], tempEdges)[0]\n const edgesWithoutExpandEdge = tempEdges.filter(\n edge => edge != edgeToRemove,\n )\n onExpandEntity({\n entityHeader: expandNodeDataProps.entityHeader,\n nodesCopy: nodesWithoutExpandNode,\n edgesCopy: edgesWithoutExpandEdge,\n }).finally(() => {\n setTempNodes(nodesWithoutExpandNode)\n setTempEdges(edgesWithoutExpandEdge)\n })\n }\n setClickedNode(undefined)\n }\n }, [clickedNode, tempNodes, tempEdges, onExpandEntity])\n\n /**\n * This effect code is run when the graph nodes or edges change.\n * It feeds the nodes and edges into our layout library to figure out where they should be positioned.\n * The result is saved in the state variable \"nodes\" and \"edges\".\n */\n useEffect(() => {\n const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(\n tempNodes,\n tempEdges,\n 'TB',\n )\n // hack: ProvenanceUtils.getProvenanceNode() returns a new object every time, so check to see if\n // there were any real changes\n if (!isArrayEqual(layoutedNodes, nodes)) {\n setNodes(layoutedNodes)\n if (onNodesChangedListener) {\n onNodesChangedListener(layoutedNodes)\n }\n }\n if (!isArrayEqual(layoutedEdges, edges)) {\n setEdges(layoutedEdges)\n if (onEdgesChangedListener) {\n onEdgesChangedListener(layoutedEdges)\n }\n }\n }, [\n tempNodes,\n tempEdges,\n nodes,\n edges,\n setNodes,\n setEdges,\n initializedPosition,\n reactFlowInstance,\n rootEntityRefs,\n onNodesChangedListener,\n onEdgesChangedListener,\n ])\n\n const onPaneScrollFunction: (event?: WheelEvent) => void = useCallback(\n event => {\n // Cannot simply check the truthy value of event.deltaX (or Y) because the value might be 0 (or -0), which is falsy\n if (\n event &&\n typeof event.deltaX !== 'undefined' &&\n typeof event.deltaY !== 'undefined'\n ) {\n window.scrollTo(\n window.scrollX + event.deltaX,\n window.scrollY + event.deltaY,\n )\n }\n },\n [],\n )\n return (\n <div\n className=\"ProvenanceWidget\"\n role=\"graphics-doc\" //https://www.w3.org/wiki/SVG_Accessibility/ARIA_roles_for_charts#Document_Roles\n style={{\n width: '100%',\n height: containerHeight,\n backgroundColor: PROVENANCE_BACKGROUND_COLOR,\n padding: '15px',\n }}\n >\n {showNoProvenance ? (\n <Stack\n sx={{\n display: 'flex',\n height: '100%',\n alignItems: 'center',\n justifyContent: 'center',\n textAlign: 'center',\n }}\n >\n <Typography\n sx={{\n color: NO_PROVENANCE_TEXT_COLOR,\n fontSize: '16px',\n lineHeight: '24px',\n fontWeight: 540,\n marginBottom: '12px',\n }}\n >\n {NO_PROVENANCE_TITLE}\n </Typography>\n <Typography\n sx={{\n color: NO_PROVENANCE_TEXT_COLOR,\n fontSize: '14px',\n lineHeight: '20px',\n fontWeight: 440,\n }}\n >\n {NO_PROVENANCE_MESSAGE(entityTypeName)}\n </Typography>\n {onEditProvenanceClicked && (\n <Button\n variant=\"outlined\"\n sx={{\n borderRadius: '6px',\n border: '1px solid',\n borderColor: EDIT_PROVENANCE_BUTTON_BORDER_COLOR,\n background: EDIT_PROVENANCE_BUTTON_BACKGROUND_COLOR,\n color: EDIT_PROVENANCE_BUTTON_TEXT_COLOR,\n fontWeight: 540,\n lineHeight: '12px' /* 100% */,\n letterSpacing: '-0.24px',\n marginTop: '20px',\n height: '28px',\n padding: '8px',\n }}\n onClick={onEditProvenanceClicked}\n >\n {EDIT_PROVENANCE_TEXT}\n </Button>\n )}\n </Stack>\n ) : (\n <ReactFlow\n defaultViewport={{ x: 0, y: 0, zoom: DEFAULT_ZOOM }}\n nodes={nodes}\n edges={edges}\n onNodeClick={onClickNode}\n // onNodesChange={onNodesChange} // SWC-6804: When the nodes/edges are updated (expanded) the graph is already re-rendered.\n // onEdgesChange={onEdgesChange} // Specifying these callbacks causes an infinite re-rendering loop.\n attributionPosition=\"bottom-right\"\n onConnect={undefined}\n zoomOnScroll={false}\n onPaneScroll={onPaneScrollFunction}\n >\n <Controls />\n </ReactFlow>\n )}\n </div>\n )\n}\n\nconst ProvenanceGraph = (props: ProvenanceProps): React.ReactNode => {\n return (\n <SynapseErrorBoundary>\n <ReactFlowProvider>\n <ProvenanceReactFlow {...props} />\n </ReactFlowProvider>\n </SynapseErrorBoundary>\n )\n}\n\nexport default ProvenanceGraph\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AdditionalPropertiesSchemaField.js","names":[],"sources":["../../../../src/components/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField.tsx"],"sourcesContent":["import {\n FieldProps,\n FormContextType,\n RJSFSchema,\n StrictRJSFSchema,\n} from '@rjsf/utils'\nimport { isEqual } from 'lodash-es'\nimport { useEffect, useState } from 'react'\nimport FullWidthAlert from '../../FullWidthAlert/FullWidthAlert'\nimport { convertToArray } from '../AnnotationEditorUtils'\nimport { GridLegacy as Grid, InputLabel } from '@mui/material'\nimport { AdditionalPropertyContextProvider } from '../template/AdditionalPropertyContext'\n\n// Matches ####-##-##T##:##:##.###Z, e.g. 1970-01-01T12:00:000Z\nconst ISO_TIMESTAMP_REGEX = /\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z/\n\n// Types that correspond to the different input fields that the annotation editor supports\nconst propertyTypeArray = [\n 'String',\n 'Integer',\n 'Float',\n 'Boolean',\n 'Datetime',\n] as const\n\nexport type PropertyType = (typeof propertyTypeArray)[number]\n\nexport function guessPropertyType(list: Array<unknown>): PropertyType {\n if (list.length === 0) {\n // The field was just added, so default to string\n return 'String'\n } else if (\n list.every(\n item => typeof item === 'number' || item === 'NaN', // \"NaN\" is technically a float value\n )\n ) {\n if (list.every(item => Number.isInteger(item))) {\n return 'Integer'\n } else {\n return 'Float'\n }\n } else if (list.every(item => typeof item === 'boolean')) {\n return 'Boolean'\n } else if (\n list.every(item => typeof item === 'string') &&\n list.every((item: string) => !!ISO_TIMESTAMP_REGEX.exec(item))\n ) {\n return 'Datetime'\n }\n // otherwise, default type is 'string'\n return 'String'\n}\n\nexport function transformDataFromPropertyType(\n list: Array<any>,\n propertyType: PropertyType,\n) {\n switch (propertyType) {\n case 'Integer':\n return list.map(item =>\n Number.isNaN(Number(item)) ? 0 : Math.floor(Number(item)),\n )\n\n case 'Float':\n return list.map(item => {\n const asFloat = parseFloat(item as string)\n if (Number.isNaN(asFloat)) {\n return 'NaN'\n } else if (Number.isInteger(asFloat)) {\n return asFloat.toFixed(1)\n } else {\n return asFloat\n }\n })\n case 'Datetime':\n return list.map(item => {\n if (typeof item === 'string' && ISO_TIMESTAMP_REGEX.exec(item)) {\n return item\n } else {\n return new Date().toISOString()\n }\n })\n case 'Boolean':\n return list.map(item => !!item)\n case 'String':\n default:\n return list.map(item => String(item))\n }\n}\n\n/**\n * Maps a Synapse Annotation PropertyType to a JSON Schema that captures the type and format.\n * @param propertyType\n */\nexport function getSchemaForPropertyType(propertyType: PropertyType) {\n switch (propertyType) {\n case 'Datetime':\n return { type: 'string', format: 'datetime' }\n case 'Boolean':\n return { type: 'boolean' }\n case 'Float':\n return { type: 'number' }\n case 'Integer':\n return { type: 'integer' }\n case 'String':\n default:\n return { type: 'string' }\n }\n}\n\n/**\n * react-jsonschema-form SchemaField override for \"additionalProperties\" only. In Synapse these are \"custom annotations\".\n * Modifies the data to provide full compatibility with Synapse annotations features.\n *\n * This component provides these enhancements to the SchemaField:\n * - Supports selecting a type, and changing the input widget appropriately\n * - Identifying the type on mount\n * - Treat all field values as arrays\n * - When the last array value is removed, remove the entire key from the form.\n * @param props\n * @returns\n */\nexport function AdditionalPropertiesSchemaField<\n T extends Array<unknown> = Array<unknown>,\n S extends StrictRJSFSchema = RJSFSchema,\n F extends FormContextType = any,\n>(\n props: FieldProps<T, S, F> & {\n onDropPropertyClick: (key: string) => (event: any) => void\n },\n) {\n const {\n formData,\n onChange,\n registry,\n schema,\n name,\n onDropPropertyClick,\n idSchema,\n } = props\n const id = idSchema.$id\n const { ArrayField } = registry.fields\n const { SelectWidget } = registry.widgets\n\n // The type determines which widget we show.\n const [propertyType, setPropertyType] = useState(\n guessPropertyType(convertToArray(formData)),\n )\n\n // If the property type is updated, store it in a new variable where we'll show a warning if data may be lost on coersion\n const [nextPropertyType, setNextPropertyType] = useState(propertyType)\n\n /**\n * This effect is invoked whenever the user attempts to change the datatype of a custom annotation.\n */\n useEffect(() => {\n function onNextPropertyTypeUpdate() {\n if (Array.isArray(formData)) {\n const dataIsEmpty =\n formData.length === 0 ||\n formData.every(item => item == null || item == '')\n const coercedList = transformDataFromPropertyType(\n formData,\n nextPropertyType,\n )\n // if the data is empty or identical after conversion, then just update the property type\n if (dataIsEmpty || nextPropertyType !== propertyType) {\n if (isEqual(formData, coercedList)) {\n setPropertyType(nextPropertyType)\n }\n }\n }\n }\n\n onNextPropertyTypeUpdate()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [nextPropertyType])\n\n /**\n * This effect is invoked whenever the propertyType changes.\n */\n useEffect(() => {\n function coerceDataAndUpdateWidget() {\n if (Array.isArray(formData)) {\n if (formData.every(item => item == null)) {\n onDropPropertyClick(name)(new CustomEvent('dropEmptyProperty'))\n } else {\n const coercedList = transformDataFromPropertyType(\n formData,\n nextPropertyType,\n ) as unknown as T\n\n // Data conversion is non-destructive or has been confirmed by the user\n setPropertyType(nextPropertyType)\n // Coerce the data to match the new type\n onChange(coercedList)\n }\n }\n }\n\n coerceDataAndUpdateWidget()\n // Don't add other properties to dependency array because we don't want to automatically coerce input\n // i.e. Only coerce data when the type changes, which should only be on mount or when the user explicitly chooses a new type.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [propertyType])\n\n const itemsSchema = getSchemaForPropertyType(propertyType)\n\n useEffect(() => {\n // If the additional property has not yet been coerced to an array, trigger an update to coerce and render nothing.\n // We must do this because RJSF does not currently batch these kinds of updates\n // See https://github.com/rjsf-team/react-jsonschema-form/issues/3367\n if (!Array.isArray(formData)) {\n onChange(convertToArray(formData) as unknown as T)\n }\n }, [formData, onChange])\n\n if (!Array.isArray(formData)) {\n return <></>\n }\n\n return (\n <AdditionalPropertyContextProvider\n value={{\n dropProperty: e => {\n onDropPropertyClick(name)(e)\n },\n }}\n >\n <Grid item xs={2}>\n <InputLabel htmlFor={`${id}-type`}>Type</InputLabel>\n <SelectWidget\n name={'Type'}\n id={`${id}-type`}\n schema={{} as S}\n options={{\n enumOptions: propertyTypeArray.map(type => ({\n label: type,\n value: type,\n })),\n }}\n value={propertyType}\n onChange={value => {\n setNextPropertyType(value as PropertyType)\n }}\n disabled={props.disabled}\n readOnly={props.readonly}\n required={true}\n isClearable={false}\n onBlur={() => {}}\n onFocus={() => {}}\n registry={registry}\n label={'Type'}\n />\n </Grid>\n <Grid item xs={7}>\n <ArrayField\n {...props}\n uiSchema={{\n ...props.uiSchema,\n 'ui:title': 'Value(s)',\n items: {\n ...props.uiSchema?.items,\n 'ui:placeholder': 'New Value',\n },\n }}\n schema={{\n ...schema,\n items: {\n ...itemsSchema,\n },\n }}\n />\n </Grid>\n {propertyType !== nextPropertyType && (\n <FullWidthAlert\n variant=\"warning\"\n title=\"Data may be lost when converting types\"\n description={`Are you sure you want to convert ${name} from ${propertyType} to ${nextPropertyType}? Current values may be lost on conversion.`}\n primaryButtonConfig={{\n text: 'Convert',\n onClick: () => {\n setPropertyType(nextPropertyType)\n },\n }}\n secondaryButtonConfig={{\n text: 'Cancel',\n onClick: () => {\n setNextPropertyType(propertyType)\n },\n }}\n isGlobal={false}\n />\n )}\n </AdditionalPropertyContextProvider>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdditionalPropertiesSchemaField.js","names":[],"sources":["../../../../src/components/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField.tsx"],"sourcesContent":["import {\n FieldProps,\n FormContextType,\n RJSFSchema,\n StrictRJSFSchema,\n} from '@rjsf/utils'\nimport { isEqual } from 'lodash-es'\nimport { useEffect, useState } from 'react'\nimport FullWidthAlert from '../../FullWidthAlert/FullWidthAlert'\nimport { convertToArray } from '../AnnotationEditorUtils'\nimport { GridLegacy as Grid, InputLabel } from '@mui/material'\nimport { AdditionalPropertyContextProvider } from '../template/AdditionalPropertyContext'\n\n// Matches ####-##-##T##:##:##.###Z, e.g. 1970-01-01T12:00:000Z\nconst ISO_TIMESTAMP_REGEX = /\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z/\n\n// Types that correspond to the different input fields that the annotation editor supports\nconst propertyTypeArray = [\n 'String',\n 'Integer',\n 'Float',\n 'Boolean',\n 'Datetime',\n] as const\n\nexport type PropertyType = (typeof propertyTypeArray)[number]\n\nexport function guessPropertyType(list: Array<unknown>): PropertyType {\n if (list.length === 0) {\n // The field was just added, so default to string\n return 'String'\n } else if (\n list.every(\n item => typeof item === 'number' || item === 'NaN', // \"NaN\" is technically a float value\n )\n ) {\n if (list.every(item => Number.isInteger(item))) {\n return 'Integer'\n } else {\n return 'Float'\n }\n } else if (list.every(item => typeof item === 'boolean')) {\n return 'Boolean'\n } else if (\n list.every(item => typeof item === 'string') &&\n list.every((item: string) => !!ISO_TIMESTAMP_REGEX.exec(item))\n ) {\n return 'Datetime'\n }\n // otherwise, default type is 'string'\n return 'String'\n}\n\nexport function transformDataFromPropertyType(\n list: Array<any>,\n propertyType: PropertyType,\n) {\n switch (propertyType) {\n case 'Integer':\n return list.map(item =>\n Number.isNaN(Number(item)) ? 0 : Math.floor(Number(item)),\n )\n\n case 'Float':\n return list.map(item => {\n const asFloat = parseFloat(item as string)\n if (Number.isNaN(asFloat)) {\n return 'NaN'\n } else if (Number.isInteger(asFloat)) {\n return asFloat.toFixed(1)\n } else {\n return asFloat\n }\n })\n case 'Datetime':\n return list.map(item => {\n if (typeof item === 'string' && ISO_TIMESTAMP_REGEX.exec(item)) {\n return item\n } else {\n return new Date().toISOString()\n }\n })\n case 'Boolean':\n return list.map(item => !!item)\n case 'String':\n default:\n return list.map(item => String(item))\n }\n}\n\n/**\n * Maps a Synapse Annotation PropertyType to a JSON Schema that captures the type and format.\n * @param propertyType\n */\nexport function getSchemaForPropertyType(propertyType: PropertyType) {\n switch (propertyType) {\n case 'Datetime':\n return { type: 'string', format: 'datetime' }\n case 'Boolean':\n return { type: 'boolean' }\n case 'Float':\n return { type: 'number' }\n case 'Integer':\n return { type: 'integer' }\n case 'String':\n default:\n return { type: 'string' }\n }\n}\n\n/**\n * react-jsonschema-form SchemaField override for \"additionalProperties\" only. In Synapse these are \"custom annotations\".\n * Modifies the data to provide full compatibility with Synapse annotations features.\n *\n * This component provides these enhancements to the SchemaField:\n * - Supports selecting a type, and changing the input widget appropriately\n * - Identifying the type on mount\n * - Treat all field values as arrays\n * - When the last array value is removed, remove the entire key from the form.\n * @param props\n * @returns\n */\nexport function AdditionalPropertiesSchemaField<\n T extends Array<unknown> = Array<unknown>,\n S extends StrictRJSFSchema = RJSFSchema,\n F extends FormContextType = any,\n>(\n props: FieldProps<T, S, F> & {\n onDropPropertyClick: (key: string) => (event: any) => void\n },\n) {\n const {\n formData,\n onChange,\n registry,\n schema,\n name,\n onDropPropertyClick,\n idSchema,\n } = props\n const id = idSchema.$id\n const { ArrayField } = registry.fields\n const { SelectWidget } = registry.widgets\n\n // The type determines which widget we show.\n const [propertyType, setPropertyType] = useState(\n guessPropertyType(convertToArray(formData)),\n )\n\n // If the property type is updated, store it in a new variable where we'll show a warning if data may be lost on coersion\n const [nextPropertyType, setNextPropertyType] = useState(propertyType)\n\n /**\n * This effect is invoked whenever the user attempts to change the datatype of a custom annotation.\n */\n useEffect(() => {\n function onNextPropertyTypeUpdate() {\n if (Array.isArray(formData)) {\n const dataIsEmpty =\n formData.length === 0 ||\n formData.every(item => item == null || item == '')\n const coercedList = transformDataFromPropertyType(\n formData,\n nextPropertyType,\n )\n // if the data is empty or identical after conversion, then just update the property type\n if (dataIsEmpty || nextPropertyType !== propertyType) {\n if (isEqual(formData, coercedList)) {\n setPropertyType(nextPropertyType)\n }\n }\n }\n }\n\n onNextPropertyTypeUpdate()\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [nextPropertyType])\n\n /**\n * This effect is invoked whenever the propertyType changes.\n */\n useEffect(() => {\n function coerceDataAndUpdateWidget() {\n if (Array.isArray(formData)) {\n if (formData.every(item => item == null)) {\n onDropPropertyClick(name)(new CustomEvent('dropEmptyProperty'))\n } else {\n const coercedList = transformDataFromPropertyType(\n formData,\n nextPropertyType,\n ) as unknown as T\n\n // Data conversion is non-destructive or has been confirmed by the user\n setPropertyType(nextPropertyType)\n // Coerce the data to match the new type\n onChange(coercedList)\n }\n }\n }\n\n coerceDataAndUpdateWidget()\n // Don't add other properties to dependency array because we don't want to automatically coerce input\n // i.e. Only coerce data when the type changes, which should only be on mount or when the user explicitly chooses a new type.\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [propertyType])\n\n const itemsSchema = getSchemaForPropertyType(propertyType)\n\n useEffect(() => {\n // If the additional property has not yet been coerced to an array, trigger an update to coerce and render nothing.\n // We must do this because RJSF does not currently batch these kinds of updates\n // See https://github.com/rjsf-team/react-jsonschema-form/issues/3367\n if (!Array.isArray(formData)) {\n onChange(convertToArray(formData) as unknown as T)\n }\n }, [formData, onChange])\n\n if (!Array.isArray(formData)) {\n return <></>\n }\n\n return (\n <AdditionalPropertyContextProvider\n value={{\n dropProperty: e => {\n onDropPropertyClick(name)(e)\n },\n }}\n >\n <Grid item xs={2}>\n <InputLabel htmlFor={`${id}-type`}>Type</InputLabel>\n <SelectWidget\n name={'Type'}\n id={`${id}-type`}\n schema={{} as S}\n options={{\n enumOptions: propertyTypeArray.map(type => ({\n label: type,\n value: type,\n })),\n }}\n value={propertyType}\n onChange={value => {\n setNextPropertyType(value as PropertyType)\n }}\n disabled={props.disabled}\n readOnly={props.readonly}\n required={true}\n isClearable={false}\n onBlur={() => {}}\n onFocus={() => {}}\n registry={registry}\n label={'Type'}\n />\n </Grid>\n <Grid item xs={7}>\n <ArrayField\n {...props}\n uiSchema={{\n ...props.uiSchema,\n 'ui:title': 'Value(s)',\n items: {\n ...props.uiSchema?.items,\n 'ui:placeholder': 'New Value',\n },\n }}\n schema={{\n ...schema,\n items: {\n ...itemsSchema,\n },\n }}\n />\n </Grid>\n {propertyType !== nextPropertyType && (\n <FullWidthAlert\n variant=\"warning\"\n title=\"Data may be lost when converting types\"\n description={`Are you sure you want to convert ${name} from ${propertyType} to ${nextPropertyType}? Current values may be lost on conversion.`}\n primaryButtonConfig={{\n text: 'Convert',\n onClick: () => {\n setPropertyType(nextPropertyType)\n },\n }}\n secondaryButtonConfig={{\n text: 'Cancel',\n onClick: () => {\n setNextPropertyType(propertyType)\n },\n }}\n isGlobal={false}\n />\n )}\n </AdditionalPropertyContextProvider>\n )\n}\n"],"mappings":";;;;;;;;AAcA,IAAM,IAAsB,+CAGtB,IAAoB;CACxB;CACA;CACA;CACA;CACA;AACF;AAIA,SAAgB,EAAkB,GAAoC;CAuBpE,OAtBI,EAAK,WAAW,IAEX,WAEP,EAAK,OACH,MAAQ,OAAO,KAAS,YAAY,MAAS,KAC/C,IAEI,EAAK,OAAM,MAAQ,OAAO,UAAU,CAAI,CAAC,IACpC,YAEA,UAEA,EAAK,OAAM,MAAQ,OAAO,KAAS,SAAS,IAC9C,YAEP,EAAK,OAAM,MAAQ,OAAO,KAAS,QAAQ,KAC3C,EAAK,OAAO,MAAiB,CAAC,CAAC,EAAoB,KAAK,CAAI,CAAC,IAEtD,aAGF;AACT;AAEA,SAAgB,EACd,GACA,GACA;CACA,QAAQ,GAAR;EACE,KAAK,WACH,OAAO,EAAK,KAAI,MACd,OAAO,MAAM,OAAO,CAAI,CAAC,IAAI,IAAI,KAAK,MAAM,OAAO,CAAI,CAAC,CAC1D;EAEF,KAAK,SACH,OAAO,EAAK,KAAI,MAAQ;GACtB,IAAM,IAAU,WAAW,CAAc;GAMvC,OALE,OAAO,MAAM,CAAO,IACf,QACE,OAAO,UAAU,CAAO,IAC1B,EAAQ,QAAQ,CAAC,IAEjB;EAEX,CAAC;EACH,KAAK,YACH,OAAO,EAAK,KAAI,MACV,OAAO,KAAS,YAAY,EAAoB,KAAK,CAAI,IACpD,qBAEA,IAAI,KAAK,GAAE,YAAY,CAEjC;EACH,KAAK,WACH,OAAO,EAAK,KAAI,MAAQ,CAAC,CAAC,CAAI;EAEhC,SACE,OAAO,EAAK,KAAI,MAAQ,OAAO,CAAI,CAAC;CACxC;AACF;AAMA,SAAgB,EAAyB,GAA4B;CACnE,QAAQ,GAAR;EACE,KAAK,YACH,OAAO;GAAE,MAAM;GAAU,QAAQ;EAAW;EAC9C,KAAK,WACH,OAAO,EAAE,MAAM,UAAU;EAC3B,KAAK,SACH,OAAO,EAAE,MAAM,SAAS;EAC1B,KAAK,WACH,OAAO,EAAE,MAAM,UAAU;EAE3B,SACE,OAAO,EAAE,MAAM,SAAS;CAC5B;AACF;AAcA,SAAgB,EAKd,GAGA;CACA,IAAM,EACJ,aACA,aACA,aACA,WACA,SACA,wBACA,gBACE,GACE,IAAK,EAAS,KACd,EAAE,kBAAe,EAAS,QAC1B,EAAE,oBAAiB,EAAS,SAG5B,CAAC,GAAc,KAAmB,EACtC,EAAkB,EAAe,CAAQ,CAAC,CAC5C,GAGM,CAAC,GAAkB,KAAuB,EAAS,CAAY;CA+BrE,AA1BA,QAAgB;EACd,SAAS,IAA2B;GAClC,IAAI,MAAM,QAAQ,CAAQ,GAAG;IAC3B,IAAM,IACJ,EAAS,WAAW,KACpB,EAAS,OAAM,MAAQ,KAAQ,QAAQ,KAAQ,EAAE,GAC7C,IAAc,EAClB,GACA,CACF;IAEA,CAAI,KAAe,MAAqB,MAClC,EAAQ,GAAU,CAAW,KAC/B,EAAgB,CAAgB;GAGtC;EACF;EAEA,EAAyB;CAE3B,GAAG,CAAC,CAAgB,CAAC,GAKrB,QAAgB;EACd,SAAS,IAA4B;GACnC,IAAI,MAAM,QAAQ,CAAQ,GACxB,IAAI,EAAS,OAAM,MAAQ,KAAQ,IAAI,GACrC,EAAoB,CAAI,EAAE,IAAI,YAAY,mBAAmB,CAAC;QACzD;IACL,IAAM,IAAc,EAClB,GACA,CACF;IAKA,AAFA,EAAgB,CAAgB,GAEhC,EAAS,CAAW;GACtB;EAEJ;EAEA,EAA0B;CAI5B,GAAG,CAAC,CAAY,CAAC;CAEjB,IAAM,IAAc,EAAyB,CAAY;CAezD,OAbA,QAAgB;EAId,AAAK,MAAM,QAAQ,CAAQ,KACzB,EAAS,EAAe,CAAQ,CAAiB;CAErD,GAAG,CAAC,GAAU,CAAQ,CAAC,GAElB,MAAM,QAAQ,CAAQ,IAKzB,kBAAC,GAAD;EACE,OAAO,EACL,eAAc,MAAK;GACjB,EAAoB,CAAI,EAAE,CAAC;EAC7B,EACF;YALF;GAOE,kBAAC,GAAD;IAAM,MAAA;IAAK,IAAI;cAAf,CACE,kBAAC,GAAD;KAAY,SAAS,GAAG,EAAG;eAAQ;IAAgB,CAAA,GACnD,kBAAC,GAAD;KACE,MAAM;KACN,IAAI,GAAG,EAAG;KACV,QAAQ,CAAC;KACT,SAAS,EACP,aAAa,EAAkB,KAAI,OAAS;MAC1C,OAAO;MACP,OAAO;KACT,EAAE,EACJ;KACA,OAAO;KACP,WAAU,MAAS;MACjB,EAAoB,CAAqB;KAC3C;KACA,UAAU,EAAM;KAChB,UAAU,EAAM;KAChB,UAAU;KACV,aAAa;KACb,cAAc,CAAC;KACf,eAAe,CAAC;KACN;KACV,OAAO;IACR,CAAA,CACG;;GACN,kBAAC,GAAD;IAAM,MAAA;IAAK,IAAI;cACb,kBAAC,GAAD;KACE,GAAI;KACJ,UAAU;MACR,GAAG,EAAM;MACT,YAAY;MACZ,OAAO;OACL,GAAG,EAAM,UAAU;OACnB,kBAAkB;MACpB;KACF;KACA,QAAQ;MACN,GAAG;MACH,OAAO,EACL,GAAG,EACL;KACF;IACD,CAAA;GACG,CAAA;GACL,MAAiB,KAChB,kBAAC,GAAD;IACE,SAAQ;IACR,OAAM;IACN,aAAa,oCAAoC,EAAK,QAAQ,EAAa,MAAM,EAAiB;IAClG,qBAAqB;KACnB,MAAM;KACN,eAAe;MACb,EAAgB,CAAgB;KAClC;IACF;IACA,uBAAuB;KACrB,MAAM;KACN,eAAe;MACb,EAAoB,CAAY;KAClC;IACF;IACA,UAAU;GACX,CAAA;EAE8B;MA5E5B,kBAAA,GAAA,CAAI,CAAA;AA8Ef"}
@@ -1 +1 @@
1
- {"version":3,"file":"SearchQueryUseQueryOptions.d.ts","sourceRoot":"","sources":["../../../src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SearchQueryUseQueryOptions.d.ts","sourceRoot":"","sources":["../../../src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts"],"names":[],"mappings":"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"}
@@ -110,15 +110,15 @@ function h(e, t, n, r) {
110
110
  rows: o
111
111
  }
112
112
  } : void 0, u = e.aggregationResults, d = Object.entries(u ?? {}).map(([e, t]) => {
113
- let n = t, i = n[`sterms#${e}`] ?? n[e], a = i?.buckets === void 0 ? t : i, o = r?.filter((t) => t.concreteType === c && t.columnName === e).flatMap((e) => e.facetValues ?? []) ?? [];
113
+ let n = t, i = Object.keys(n).find((t) => t.endsWith(`#${e}`)), a = (i === void 0 ? void 0 : n[i]) ?? n[e], o = a?.buckets === void 0 ? t : a, s = r?.filter((t) => t.concreteType === c && t.columnName === e).flatMap((e) => e.facetValues ?? []) ?? [];
114
114
  return {
115
115
  concreteType: "org.sagebionetworks.repo.model.table.FacetColumnResultValues",
116
116
  facetType: "enumeration",
117
117
  columnName: e,
118
- facetValues: (a.buckets ?? []).map((e) => ({
118
+ facetValues: (o.buckets ?? []).map((e) => ({
119
119
  value: String(e.key),
120
120
  count: e.doc_count,
121
- isSelected: o.includes(String(e.key))
121
+ isSelected: s.includes(String(e.key))
122
122
  }))
123
123
  };
124
124
  }), f = (n ?? []).filter((e) => e.facetType === "range" && (e.columnType === "DATE" || e.columnType === "DOUBLE" || e.columnType === "INTEGER") && !d.some((t) => t.columnName === e.name)).map((e) => {