@truedat/df 8.6.3 → 8.6.6
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 +4 -4
- package/src/components/DynamicFieldValue.js +2 -2
- package/src/components/FieldViewerValue.js +27 -3
- package/src/components/__tests__/DynamicFieldValue.spec.js +29 -0
- package/src/components/__tests__/DynamicFormViewer.spec.js +8 -5
- package/src/components/__tests__/FieldViewerValue.spec.js +18 -1
- package/src/components/widgets/GroupPreview.js +45 -9
- package/src/components/widgets/__tests__/GroupPreview.spec.js +16 -4
- package/src/templates/utils/__tests__/filterValues.spec.js +10 -2
- package/src/templates/utils/__tests__/parseFieldOptions.spec.js +4 -4
- package/src/templates/utils/filterValues.js +1 -4
- package/src/templates/utils/parseFieldOptions.js +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/df",
|
|
3
|
-
"version": "8.6.
|
|
3
|
+
"version": "8.6.6",
|
|
4
4
|
"description": "Truedat Web Data Quality Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -51,14 +51,14 @@
|
|
|
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.6.
|
|
54
|
+
"@truedat/test": "8.6.6",
|
|
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
|
-
"@truedat/core": "8.6.
|
|
61
|
+
"@truedat/core": "8.6.6",
|
|
62
62
|
"axios": "^1.15.0",
|
|
63
63
|
"graphql": "^16.11.0",
|
|
64
64
|
"is-hotkey": "^0.2.0",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"semantic-ui-react": "^3.0.0-beta.2",
|
|
88
88
|
"swr": "^2.3.3"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "8a7cc3d7598dde1a52abbb9933118f4a90155d42"
|
|
91
91
|
}
|
|
@@ -5,7 +5,7 @@ import { Icon, List, Container } from "semantic-ui-react";
|
|
|
5
5
|
import OriginLabel from "@truedat/core/components/OriginLabel";
|
|
6
6
|
import DomainPreview from "./widgets/DomainPreview";
|
|
7
7
|
import UserGroupPreview from "./widgets/UserGroupPreview";
|
|
8
|
-
import GroupPreview from "./widgets/GroupPreview";
|
|
8
|
+
import { GroupPreview } from "./widgets/GroupPreview";
|
|
9
9
|
import HierarchyPreview from "./widgets/HierarchyPreview";
|
|
10
10
|
import SystemPreview from "./widgets/SystemPreview";
|
|
11
11
|
import FieldViewerValue from "./FieldViewerValue";
|
|
@@ -55,7 +55,7 @@ export const DynamicFieldValue = ({
|
|
|
55
55
|
) : type == "domain" ? (
|
|
56
56
|
<DomainPreview domainIds={_.castArray(value)} />
|
|
57
57
|
) : type == "group" ? (
|
|
58
|
-
<GroupPreview
|
|
58
|
+
<GroupPreview groups={_.castArray(value)} />
|
|
59
59
|
) : type == "user_group" ? (
|
|
60
60
|
<UserGroupPreview userGroupId={value} />
|
|
61
61
|
) : type == "hierarchy" ? (
|
|
@@ -40,8 +40,13 @@ const DynamicTableField = (field) => {
|
|
|
40
40
|
const groupNameOrAlias = (group) =>
|
|
41
41
|
_.isString(group) ? group : group?.alias || group?.name;
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
|
|
43
|
+
const stripGroupPrefix = (value) =>
|
|
44
|
+
_.isString(value) && value.startsWith("group:")
|
|
45
|
+
? value.slice("group:".length)
|
|
46
|
+
: value;
|
|
47
|
+
|
|
48
|
+
const groupDisplayName = (rawName, values) => {
|
|
49
|
+
const name = stripGroupPrefix(rawName);
|
|
45
50
|
const group = _.find(values?.processed_groups, (group) =>
|
|
46
51
|
[groupNameOrAlias(group), _.get(group, "name")].includes(name)
|
|
47
52
|
);
|
|
@@ -49,6 +54,11 @@ const userGroupDisplayName = (value, values) => {
|
|
|
49
54
|
return group ? groupNameOrAlias(group) : name;
|
|
50
55
|
};
|
|
51
56
|
|
|
57
|
+
const userGroupDisplayName = (value, values) => {
|
|
58
|
+
const [_type, name] = value.split(":");
|
|
59
|
+
return groupDisplayName(name, values);
|
|
60
|
+
};
|
|
61
|
+
|
|
52
62
|
export const FieldViewerValue = ({
|
|
53
63
|
label,
|
|
54
64
|
multiple,
|
|
@@ -119,7 +129,21 @@ export const FieldViewerValue = ({
|
|
|
119
129
|
return <ImagePreview value={value} />;
|
|
120
130
|
case "system":
|
|
121
131
|
return <SystemPreview value={value} />;
|
|
122
|
-
case "group":
|
|
132
|
+
case "group": {
|
|
133
|
+
const displayName = groupDisplayName(value, values);
|
|
134
|
+
|
|
135
|
+
return multiple ? (
|
|
136
|
+
<Label>
|
|
137
|
+
<Icon name="group" />
|
|
138
|
+
{displayName}
|
|
139
|
+
</Label>
|
|
140
|
+
) : (
|
|
141
|
+
<>
|
|
142
|
+
<Icon name="group" />
|
|
143
|
+
{displayName}
|
|
144
|
+
</>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
123
147
|
case "user_group": {
|
|
124
148
|
const [type, name] = value.split(":");
|
|
125
149
|
const displayName =
|
|
@@ -26,4 +26,33 @@ describe("<DynamicFieldValue />", () => {
|
|
|
26
26
|
const wrapper = render(<DynamicFieldValue {...props} />);
|
|
27
27
|
expect(wrapper).toMatchSnapshot();
|
|
28
28
|
});
|
|
29
|
+
|
|
30
|
+
it("renders a single group value with a group icon", () => {
|
|
31
|
+
const rendered = render(
|
|
32
|
+
<DynamicFieldValue
|
|
33
|
+
label="label"
|
|
34
|
+
value={{ value: "Data Owners", origin: "user" }}
|
|
35
|
+
type="group"
|
|
36
|
+
widget="dropdown"
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(rendered.getByText(/data owners/i)).toBeInTheDocument();
|
|
41
|
+
expect(rendered.container.querySelector(".group.icon")).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("renders multiple group values with a group icon each", () => {
|
|
45
|
+
const rendered = render(
|
|
46
|
+
<DynamicFieldValue
|
|
47
|
+
label="label"
|
|
48
|
+
value={{ value: ["Data Owners", "Quality"], origin: "user" }}
|
|
49
|
+
type="group"
|
|
50
|
+
widget="checkbox"
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(rendered.getByText(/data owners/i)).toBeInTheDocument();
|
|
55
|
+
expect(rendered.getByText(/quality/i)).toBeInTheDocument();
|
|
56
|
+
expect(rendered.container.querySelectorAll(".group.icon")).toHaveLength(2);
|
|
57
|
+
});
|
|
29
58
|
});
|
|
@@ -22,6 +22,9 @@ jest.mock("@truedat/core/hooks", () => {
|
|
|
22
22
|
|
|
23
23
|
jest.mock("../widgets/GroupPreview", () => ({
|
|
24
24
|
__esModule: true,
|
|
25
|
+
GroupPreview: ({ groups }) => (
|
|
26
|
+
<div data-testid="group-preview">{[].concat(groups).join(",")}</div>
|
|
27
|
+
),
|
|
25
28
|
default: ({ groupId }) => (
|
|
26
29
|
<div data-testid="group-preview">{[].concat(groupId).join(",")}</div>
|
|
27
30
|
),
|
|
@@ -47,7 +50,7 @@ const groupTemplate = {
|
|
|
47
50
|
|
|
48
51
|
const groupContent = {
|
|
49
52
|
"group-field": {
|
|
50
|
-
value: ["
|
|
53
|
+
value: ["Group Alias"],
|
|
51
54
|
origin: "user",
|
|
52
55
|
},
|
|
53
56
|
};
|
|
@@ -119,7 +122,7 @@ describe("<DynamicFormViewer />", () => {
|
|
|
119
122
|
);
|
|
120
123
|
|
|
121
124
|
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
122
|
-
"
|
|
125
|
+
"Group Alias"
|
|
123
126
|
);
|
|
124
127
|
});
|
|
125
128
|
|
|
@@ -132,7 +135,7 @@ describe("<DynamicFormViewer />", () => {
|
|
|
132
135
|
);
|
|
133
136
|
|
|
134
137
|
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
135
|
-
"
|
|
138
|
+
"Group Alias"
|
|
136
139
|
);
|
|
137
140
|
expect(rendered.container.querySelector("h3, h4")).not.toBeInTheDocument();
|
|
138
141
|
});
|
|
@@ -155,7 +158,7 @@ describe("<DynamicFormViewer />", () => {
|
|
|
155
158
|
|
|
156
159
|
expect(useTemplate).not.toHaveBeenCalled();
|
|
157
160
|
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
158
|
-
"
|
|
161
|
+
"Group Alias"
|
|
159
162
|
);
|
|
160
163
|
});
|
|
161
164
|
|
|
@@ -195,7 +198,7 @@ describe("<DynamicFormViewer />", () => {
|
|
|
195
198
|
domainIds: [1],
|
|
196
199
|
});
|
|
197
200
|
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
198
|
-
"
|
|
201
|
+
"Group Alias"
|
|
199
202
|
);
|
|
200
203
|
});
|
|
201
204
|
});
|
|
@@ -180,7 +180,7 @@ describe("<FieldViewerValue />", () => {
|
|
|
180
180
|
const rendered = render(
|
|
181
181
|
<FieldViewerValue
|
|
182
182
|
type="group"
|
|
183
|
-
value="
|
|
183
|
+
value="Data Owners"
|
|
184
184
|
multiple
|
|
185
185
|
values={{
|
|
186
186
|
processed_groups: [{ name: "Data Owners" }],
|
|
@@ -190,6 +190,23 @@ describe("<FieldViewerValue />", () => {
|
|
|
190
190
|
|
|
191
191
|
expect(rendered.getByText("Data Owners")).toBeInTheDocument();
|
|
192
192
|
expect(rendered.container.querySelector(".ui.label")).toBeInTheDocument();
|
|
193
|
+
expect(rendered.container.querySelector(".group.icon")).toBeInTheDocument();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("strips legacy group: prefix when rendering group values", () => {
|
|
197
|
+
const rendered = render(
|
|
198
|
+
<FieldViewerValue
|
|
199
|
+
type="group"
|
|
200
|
+
value="group:Data Owners"
|
|
201
|
+
multiple
|
|
202
|
+
values={{
|
|
203
|
+
processed_groups: [{ name: "Data Owners" }],
|
|
204
|
+
}}
|
|
205
|
+
/>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(rendered.getByText("Data Owners")).toBeInTheDocument();
|
|
209
|
+
expect(rendered.container.querySelector(".group.icon")).toBeInTheDocument();
|
|
193
210
|
});
|
|
194
211
|
|
|
195
212
|
it("renders user_group values using the raw name when they are not groups", () => {
|
|
@@ -1,21 +1,57 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import { useQuery } from "@apollo/client";
|
|
4
|
-
import { Label } from "semantic-ui-react";
|
|
4
|
+
import { Icon, Label } from "semantic-ui-react";
|
|
5
|
+
import { Link } from "react-router";
|
|
6
|
+
import { linkTo } from "@truedat/core/routes";
|
|
5
7
|
import { GROUP_PREVIEW_QUERY } from "../../api/queries";
|
|
6
|
-
import { LinkedUserGroupLabel } from "./UserGroupPreview";
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const stripGroupPrefix = (value) =>
|
|
10
|
+
_.isString(value) && value.startsWith("group:")
|
|
11
|
+
? value.slice("group:".length)
|
|
12
|
+
: value;
|
|
13
|
+
|
|
14
|
+
const groupName = (group) => (_.isString(group) ? group : group?.name);
|
|
15
|
+
const groupId = (group) => (_.isString(group) ? null : group?.id);
|
|
16
|
+
const groupDisplayName = (group) => stripGroupPrefix(groupName(group));
|
|
17
|
+
const isUserValue = (group) =>
|
|
18
|
+
_.isString(groupName(group)) && groupName(group).startsWith("user:");
|
|
19
|
+
|
|
20
|
+
export const GroupLabel = ({ value }) => (
|
|
21
|
+
<Label>
|
|
22
|
+
<Icon name="group" />
|
|
23
|
+
{stripGroupPrefix(value)}
|
|
24
|
+
</Label>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
GroupLabel.propTypes = {
|
|
28
|
+
value: PropTypes.string.isRequired,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const LinkedGroupLabel = ({ group }) => {
|
|
32
|
+
const id = groupId(group);
|
|
33
|
+
const label = <GroupLabel value={groupName(group)} />;
|
|
34
|
+
|
|
35
|
+
return id ? <Link to={linkTo.GROUP({ id })}>{label}</Link> : label;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
LinkedGroupLabel.propTypes = {
|
|
39
|
+
group: PropTypes.oneOfType([
|
|
40
|
+
PropTypes.shape({
|
|
41
|
+
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
42
|
+
name: PropTypes.string.isRequired,
|
|
43
|
+
}),
|
|
44
|
+
PropTypes.string,
|
|
45
|
+
]).isRequired,
|
|
46
|
+
};
|
|
11
47
|
|
|
12
48
|
export const GroupPreview = ({ groups }) =>
|
|
13
49
|
_.flow(
|
|
14
|
-
_.
|
|
50
|
+
_.reject(isUserValue),
|
|
15
51
|
_.map((group) => (
|
|
16
|
-
<
|
|
17
|
-
key={groupId(group) ||
|
|
18
|
-
|
|
52
|
+
<LinkedGroupLabel
|
|
53
|
+
key={groupId(group) || groupDisplayName(group)}
|
|
54
|
+
group={group}
|
|
19
55
|
/>
|
|
20
56
|
)),
|
|
21
57
|
)(groups);
|
|
@@ -18,7 +18,19 @@ describe("<GroupPreview />", () => {
|
|
|
18
18
|
jest.clearAllMocks();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it("renders group values with
|
|
21
|
+
it("renders group values with a group icon", () => {
|
|
22
|
+
const rendered = render(
|
|
23
|
+
<GroupPreview groups={[{ id: 123, name: "Group Alias" }]} />
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
expect(rendered.container.textContent).toBe("Group Alias");
|
|
27
|
+
expect(rendered.container.querySelector(".group.icon")).toBeInTheDocument();
|
|
28
|
+
expect(
|
|
29
|
+
rendered.getByRole("link", { name: /group alias/i })
|
|
30
|
+
).toHaveAttribute("href", "/groups/123");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("strips the legacy group: prefix when rendering names", () => {
|
|
22
34
|
const rendered = render(
|
|
23
35
|
<GroupPreview groups={[{ id: 123, name: "group:Group Alias" }]} />
|
|
24
36
|
);
|
|
@@ -33,7 +45,7 @@ describe("<GroupPreview />", () => {
|
|
|
33
45
|
it("does not render user values", () => {
|
|
34
46
|
const rendered = render(
|
|
35
47
|
<GroupPreview
|
|
36
|
-
groups={["user:John Doe", { id: 123, name: "
|
|
48
|
+
groups={["user:John Doe", { id: 123, name: "Group Alias" }]}
|
|
37
49
|
/>
|
|
38
50
|
);
|
|
39
51
|
|
|
@@ -46,7 +58,7 @@ describe("<GroupPreview />", () => {
|
|
|
46
58
|
|
|
47
59
|
it("renders string groups without a link when there is no group id", () => {
|
|
48
60
|
const rendered = render(
|
|
49
|
-
<GroupPreview groups={["
|
|
61
|
+
<GroupPreview groups={["Standalone Group"]} />
|
|
50
62
|
);
|
|
51
63
|
|
|
52
64
|
expect(rendered.container.textContent).toBe("Standalone Group");
|
|
@@ -91,7 +103,7 @@ describe("<GroupPreview />", () => {
|
|
|
91
103
|
loading: false,
|
|
92
104
|
error: undefined,
|
|
93
105
|
data: {
|
|
94
|
-
groupDetails: [{ id: 123, name: "
|
|
106
|
+
groupDetails: [{ id: 123, name: "Group Alias" }],
|
|
95
107
|
},
|
|
96
108
|
});
|
|
97
109
|
|
|
@@ -81,10 +81,10 @@ describe("utils: validValues", () => {
|
|
|
81
81
|
|
|
82
82
|
expect(
|
|
83
83
|
filterValues(template)({
|
|
84
|
-
role: { value: "
|
|
84
|
+
role: { value: "alias1", origin: "default" },
|
|
85
85
|
}),
|
|
86
86
|
).toEqual({
|
|
87
|
-
role: { value: "
|
|
87
|
+
role: { value: "alias1", origin: "default" },
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
expect(
|
|
@@ -94,6 +94,14 @@ describe("utils: validValues", () => {
|
|
|
94
94
|
).toEqual({
|
|
95
95
|
role: { value: null, origin: "default" },
|
|
96
96
|
});
|
|
97
|
+
|
|
98
|
+
expect(
|
|
99
|
+
filterValues(template)({
|
|
100
|
+
role: { value: "group:alias1", origin: "default" },
|
|
101
|
+
}),
|
|
102
|
+
).toEqual({
|
|
103
|
+
role: { value: null, origin: "default" },
|
|
104
|
+
});
|
|
97
105
|
});
|
|
98
106
|
|
|
99
107
|
it("should nullify unlisted fixed values", () => {
|
|
@@ -138,14 +138,14 @@ describe("utils: parseFieldOptions", () => {
|
|
|
138
138
|
processed_groups: ["alias1", "group2"],
|
|
139
139
|
},
|
|
140
140
|
};
|
|
141
|
-
const content = { field: { value: "
|
|
141
|
+
const content = { field: { value: "alias1", origin: "default" } };
|
|
142
142
|
const result = parseFormatFieldOptions(content)(field);
|
|
143
143
|
expect(result).toEqual({
|
|
144
144
|
...field,
|
|
145
|
-
value: { value: "
|
|
145
|
+
value: { value: "alias1", origin: "default" },
|
|
146
146
|
parsedValues: [
|
|
147
|
-
{ value: "
|
|
148
|
-
{ value: "
|
|
147
|
+
{ value: "alias1", text: "alias1", icon: "group" },
|
|
148
|
+
{ value: "group2", text: "group2", icon: "group" },
|
|
149
149
|
],
|
|
150
150
|
});
|
|
151
151
|
});
|
|
@@ -20,10 +20,7 @@ const userGroupValues = (field) =>
|
|
|
20
20
|
|
|
21
21
|
const groupValues = _.flow(
|
|
22
22
|
_.get("processed_groups"),
|
|
23
|
-
_.map(
|
|
24
|
-
const name = groupNameOrAlias(group);
|
|
25
|
-
return `group:${name}`;
|
|
26
|
-
}),
|
|
23
|
+
_.map(groupNameOrAlias),
|
|
27
24
|
);
|
|
28
25
|
|
|
29
26
|
export const validValues = _.flow(
|
|
@@ -47,19 +47,20 @@ const doParseFieldOptions = (formatMessage, content, selectedDomain, field) => {
|
|
|
47
47
|
const groupNameOrAlias = (group) =>
|
|
48
48
|
typeof group === "string" ? group : group.alias || group.name;
|
|
49
49
|
const parseRoleGroups = (values) => {
|
|
50
|
+
const isGroupOnly = field?.type === "group";
|
|
50
51
|
const groups = _.flow(
|
|
51
52
|
_.get("processed_groups"),
|
|
52
53
|
_.map((group) => {
|
|
53
54
|
const name = groupNameOrAlias(group);
|
|
54
55
|
return {
|
|
55
|
-
value: `group:${name}`,
|
|
56
|
+
value: isGroupOnly ? name : `group:${name}`,
|
|
56
57
|
text: name,
|
|
57
58
|
icon: "group",
|
|
58
59
|
};
|
|
59
60
|
}),
|
|
60
61
|
)(values);
|
|
61
62
|
|
|
62
|
-
if (
|
|
63
|
+
if (isGroupOnly) return groups;
|
|
63
64
|
|
|
64
65
|
const users = _.flow(
|
|
65
66
|
_.get("processed_users"),
|