@truedat/df 8.5.9 → 8.6.1
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/api/queries.js +18 -0
- package/src/components/DynamicFieldValue.js +6 -0
- package/src/components/FieldViewerValue.js +21 -3
- package/src/components/__tests__/DynamicFormViewer.spec.js +164 -3
- package/src/components/__tests__/FieldViewerValue.spec.js +129 -12
- package/src/components/widgets/GroupPreview.js +55 -0
- package/src/components/widgets/UserGroupPreview.js +97 -0
- package/src/components/widgets/__tests__/GroupPreview.spec.js +105 -0
- package/src/components/widgets/__tests__/UserGroupPreview.spec.js +98 -0
- package/src/messages/en.js +1 -0
- package/src/messages/es.js +1 -0
- package/src/templates/components/templateForm/TableValuesForm.js +237 -227
- package/src/templates/components/templateForm/__tests__/__snapshots__/FieldForm.spec.js.snap +13 -0
- package/src/templates/components/templateForm/contentValidation.js +21 -9
- package/src/templates/components/templateForm/valueDefinitions.js +1 -0
- package/src/templates/components/templateForm/widgetDefinitions.js +11 -3
- package/src/templates/utils/__tests__/filterValues.spec.js +52 -0
- package/src/templates/utils/__tests__/parseFieldOptions.spec.js +45 -0
- package/src/templates/utils/filterValues.js +33 -11
- package/src/templates/utils/parseFieldOptions.js +33 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/df",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.6.1",
|
|
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.
|
|
54
|
+
"@truedat/test": "8.6.1",
|
|
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.
|
|
61
|
+
"@truedat/core": "8.6.1",
|
|
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": "932eb0895ec71961f52a09309b99ae017977a899"
|
|
91
91
|
}
|
package/src/api/queries.js
CHANGED
|
@@ -17,3 +17,21 @@ export const DOMAIN_PREVIEW_QUERY = gql`
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
`;
|
|
20
|
+
|
|
21
|
+
export const USER_GROUP_PREVIEW_QUERY = gql`
|
|
22
|
+
query UserGroupPreviewQuery($ids: [ID!]!) {
|
|
23
|
+
userGroupDetails(ids: $ids) {
|
|
24
|
+
id
|
|
25
|
+
name
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
export const GROUP_PREVIEW_QUERY = gql`
|
|
31
|
+
query GroupPreviewQuery($ids: [ID!]!) {
|
|
32
|
+
groupDetails(ids: $ids) {
|
|
33
|
+
id
|
|
34
|
+
name
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
@@ -4,6 +4,8 @@ import { FormattedMessage, useIntl } from "react-intl";
|
|
|
4
4
|
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
|
+
import UserGroupPreview from "./widgets/UserGroupPreview";
|
|
8
|
+
import GroupPreview from "./widgets/GroupPreview";
|
|
7
9
|
import HierarchyPreview from "./widgets/HierarchyPreview";
|
|
8
10
|
import SystemPreview from "./widgets/SystemPreview";
|
|
9
11
|
import FieldViewerValue from "./FieldViewerValue";
|
|
@@ -52,6 +54,10 @@ export const DynamicFieldValue = ({
|
|
|
52
54
|
)
|
|
53
55
|
) : type == "domain" ? (
|
|
54
56
|
<DomainPreview domainIds={_.castArray(value)} />
|
|
57
|
+
) : type == "group" ? (
|
|
58
|
+
<GroupPreview groupId={value} />
|
|
59
|
+
) : type == "user_group" ? (
|
|
60
|
+
<UserGroupPreview userGroupId={value} />
|
|
55
61
|
) : type == "hierarchy" ? (
|
|
56
62
|
<HierarchyPreview hierarchyValue={_.castArray(value)} />
|
|
57
63
|
) : _.isArray(value) ? (
|
|
@@ -36,6 +36,19 @@ const DynamicTableField = (field) => {
|
|
|
36
36
|
</Table.Cell>
|
|
37
37
|
);
|
|
38
38
|
};
|
|
39
|
+
|
|
40
|
+
const groupNameOrAlias = (group) =>
|
|
41
|
+
_.isString(group) ? group : group?.alias || group?.name;
|
|
42
|
+
|
|
43
|
+
const userGroupDisplayName = (value, values) => {
|
|
44
|
+
const [_type, name] = value.split(":");
|
|
45
|
+
const group = _.find(values?.processed_groups, (group) =>
|
|
46
|
+
[groupNameOrAlias(group), _.get(group, "name")].includes(name)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return group ? groupNameOrAlias(group) : name;
|
|
50
|
+
};
|
|
51
|
+
|
|
39
52
|
export const FieldViewerValue = ({
|
|
40
53
|
label,
|
|
41
54
|
multiple,
|
|
@@ -106,19 +119,24 @@ export const FieldViewerValue = ({
|
|
|
106
119
|
return <ImagePreview value={value} />;
|
|
107
120
|
case "system":
|
|
108
121
|
return <SystemPreview value={value} />;
|
|
109
|
-
case "
|
|
122
|
+
case "group":
|
|
123
|
+
case "user_group": {
|
|
110
124
|
const [type, name] = value.split(":");
|
|
125
|
+
const displayName =
|
|
126
|
+
type === "group" ? userGroupDisplayName(value, values) : name;
|
|
127
|
+
|
|
111
128
|
return multiple ? (
|
|
112
129
|
<Label>
|
|
113
130
|
<Icon name={type} />
|
|
114
|
-
{
|
|
131
|
+
{displayName}
|
|
115
132
|
</Label>
|
|
116
133
|
) : (
|
|
117
134
|
<>
|
|
118
135
|
<Icon name={type} />
|
|
119
|
-
{
|
|
136
|
+
{displayName}
|
|
120
137
|
</>
|
|
121
138
|
);
|
|
139
|
+
}
|
|
122
140
|
case "string":
|
|
123
141
|
case "user":
|
|
124
142
|
case "number":
|
|
@@ -1,10 +1,86 @@
|
|
|
1
1
|
import { render } from "@truedat/test/render";
|
|
2
|
-
import {
|
|
2
|
+
import { useTemplate } from "@truedat/core/hooks";
|
|
3
3
|
import { markdownToHtml } from "@truedat/core/components/Markdown";
|
|
4
|
+
import DynamicFormViewerFetcher, {
|
|
5
|
+
DynamicFormViewer,
|
|
6
|
+
} from "../DynamicFormViewer";
|
|
7
|
+
|
|
8
|
+
jest.mock("@truedat/core/components/Loading", () => ({
|
|
9
|
+
__esModule: true,
|
|
10
|
+
default: () => <div data-testid="loading" />,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock("@truedat/core/hooks", () => {
|
|
14
|
+
const originalModule = jest.requireActual("@truedat/core/hooks");
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
__esModule: true,
|
|
18
|
+
...originalModule,
|
|
19
|
+
useTemplate: jest.fn(),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
jest.mock("../widgets/GroupPreview", () => ({
|
|
24
|
+
__esModule: true,
|
|
25
|
+
default: ({ groupId }) => (
|
|
26
|
+
<div data-testid="group-preview">{[].concat(groupId).join(",")}</div>
|
|
27
|
+
),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
const groupTemplate = {
|
|
31
|
+
scope: "bg",
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
name: "g1",
|
|
35
|
+
fields: [
|
|
36
|
+
{
|
|
37
|
+
name: "group-field",
|
|
38
|
+
label: "group-label",
|
|
39
|
+
type: "group",
|
|
40
|
+
widget: "dropdown",
|
|
41
|
+
cardinality: "*",
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const groupContent = {
|
|
49
|
+
"group-field": {
|
|
50
|
+
value: ["group:Group Alias"],
|
|
51
|
+
origin: "user",
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const unnamedGroupTemplate = {
|
|
56
|
+
scope: "bg",
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
fields: [
|
|
60
|
+
{
|
|
61
|
+
name: "group-field",
|
|
62
|
+
label: "group-label",
|
|
63
|
+
type: "group",
|
|
64
|
+
widget: "dropdown",
|
|
65
|
+
cardinality: "*",
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
4
71
|
|
|
5
72
|
describe("<DynamicFormViewer />", () => {
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
jest.clearAllMocks();
|
|
75
|
+
useTemplate.mockReturnValue({
|
|
76
|
+
data: {},
|
|
77
|
+
loading: false,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
6
81
|
it("renders markdown content through MarkdownReader", () => {
|
|
7
|
-
const markdown =
|
|
82
|
+
const markdown =
|
|
83
|
+
"## Title\n\n**Hello** world\n\n[link](https://example.com)";
|
|
8
84
|
|
|
9
85
|
const template = {
|
|
10
86
|
scope: "bg",
|
|
@@ -36,5 +112,90 @@ describe("<DynamicFormViewer />", () => {
|
|
|
36
112
|
expect(reader).toBeInTheDocument();
|
|
37
113
|
expect(reader.innerHTML).toBe(markdownToHtml(markdown));
|
|
38
114
|
});
|
|
39
|
-
});
|
|
40
115
|
|
|
116
|
+
it("renders group fields through GroupPreview", () => {
|
|
117
|
+
const rendered = render(
|
|
118
|
+
<DynamicFormViewer template={groupTemplate} content={groupContent} />
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
122
|
+
"group:Group Alias"
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("renders groups without heading when the group name is missing", () => {
|
|
127
|
+
const rendered = render(
|
|
128
|
+
<DynamicFormViewer
|
|
129
|
+
template={unnamedGroupTemplate}
|
|
130
|
+
content={groupContent}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
135
|
+
"group:Group Alias"
|
|
136
|
+
);
|
|
137
|
+
expect(rendered.container.querySelector("h3, h4")).not.toBeInTheDocument();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("renders a negative message when template is missing", () => {
|
|
141
|
+
const rendered = render(<DynamicFormViewer content={groupContent} />);
|
|
142
|
+
|
|
143
|
+
expect(
|
|
144
|
+
rendered.container.querySelector(".ui.negative.message")
|
|
145
|
+
).toBeInTheDocument();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("renders object templates without fetching them", () => {
|
|
149
|
+
const rendered = render(
|
|
150
|
+
<DynamicFormViewerFetcher
|
|
151
|
+
template={groupTemplate}
|
|
152
|
+
content={groupContent}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
expect(useTemplate).not.toHaveBeenCalled();
|
|
157
|
+
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
158
|
+
"group:Group Alias"
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("renders a loader while fetching string templates", () => {
|
|
163
|
+
useTemplate.mockReturnValue({
|
|
164
|
+
data: {},
|
|
165
|
+
loading: true,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const rendered = render(
|
|
169
|
+
<DynamicFormViewerFetcher template="group-template" />
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(useTemplate).toHaveBeenCalledWith({
|
|
173
|
+
name: "group-template",
|
|
174
|
+
domainIds: undefined,
|
|
175
|
+
});
|
|
176
|
+
expect(rendered.getByTestId("loading")).toBeInTheDocument();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("fetches string templates before rendering them", () => {
|
|
180
|
+
useTemplate.mockReturnValue({
|
|
181
|
+
data: { template: groupTemplate },
|
|
182
|
+
loading: false,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const rendered = render(
|
|
186
|
+
<DynamicFormViewerFetcher
|
|
187
|
+
template="group-template"
|
|
188
|
+
domainIds={[1]}
|
|
189
|
+
content={groupContent}
|
|
190
|
+
/>
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
expect(useTemplate).toHaveBeenCalledWith({
|
|
194
|
+
name: "group-template",
|
|
195
|
+
domainIds: [1],
|
|
196
|
+
});
|
|
197
|
+
expect(rendered.getByTestId("group-preview")).toHaveTextContent(
|
|
198
|
+
"group:Group Alias"
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { render } from "@truedat/test/render";
|
|
2
|
-
import { FieldViewerValue } from "../FieldViewerValue";
|
|
3
2
|
import { markdownToHtml } from "@truedat/core/components/Markdown";
|
|
3
|
+
import { FieldViewerValue } from "../FieldViewerValue";
|
|
4
4
|
|
|
5
5
|
describe("<FieldViewerValue />", () => {
|
|
6
6
|
const testTypes = [
|
|
@@ -56,18 +56,24 @@ describe("<FieldViewerValue />", () => {
|
|
|
56
56
|
type: "datetime",
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
values: {
|
|
60
|
-
|
|
59
|
+
values: {
|
|
60
|
+
table_columns: [{ name: "col1", cardinality: "?", type: "string" }],
|
|
61
|
+
},
|
|
62
|
+
value: [
|
|
63
|
+
{ col1: { value: "v2", origin: "user" } },
|
|
64
|
+
{ col1: { value: "v2", origin: "user" } },
|
|
65
|
+
],
|
|
61
66
|
type: "dynamic_table",
|
|
62
|
-
}
|
|
67
|
+
},
|
|
63
68
|
];
|
|
64
69
|
|
|
65
70
|
testTypes.forEach((props) =>
|
|
66
|
-
it(`matches the latest snapshot with type: ${props.type}${
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
it(`matches the latest snapshot with type: ${props.type}${
|
|
72
|
+
props.alternative ? " " + props.alternative : ""
|
|
73
|
+
}`, () => {
|
|
74
|
+
const { container } = render(<FieldViewerValue {...props} />);
|
|
75
|
+
expect(container).toMatchSnapshot();
|
|
76
|
+
})
|
|
71
77
|
);
|
|
72
78
|
|
|
73
79
|
it("matches the latest snapshot for multiple", () => {
|
|
@@ -80,10 +86,30 @@ describe("<FieldViewerValue />", () => {
|
|
|
80
86
|
expect(container).toMatchSnapshot();
|
|
81
87
|
});
|
|
82
88
|
|
|
89
|
+
it("shows group alias for user_group values when available", () => {
|
|
90
|
+
const { container } = render(
|
|
91
|
+
<FieldViewerValue
|
|
92
|
+
type="user_group"
|
|
93
|
+
value="group:Group alias"
|
|
94
|
+
values={{
|
|
95
|
+
processed_groups: ["Group alias"],
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(container.textContent).toContain("Group alias");
|
|
101
|
+
});
|
|
102
|
+
|
|
83
103
|
it("renders MarkdownReader for type=markdown", () => {
|
|
84
|
-
const markdown =
|
|
104
|
+
const markdown =
|
|
105
|
+
"## Title\n\n**Hello** world\n\n[link](https://example.com)";
|
|
85
106
|
const { container } = render(
|
|
86
|
-
<FieldViewerValue
|
|
107
|
+
<FieldViewerValue
|
|
108
|
+
type="markdown"
|
|
109
|
+
value={markdown}
|
|
110
|
+
label="md"
|
|
111
|
+
widget="markdown"
|
|
112
|
+
/>
|
|
87
113
|
);
|
|
88
114
|
|
|
89
115
|
const reader = container.querySelector(".markdown-reader");
|
|
@@ -93,8 +119,99 @@ describe("<FieldViewerValue />", () => {
|
|
|
93
119
|
|
|
94
120
|
it("returns null when markdown content is empty", () => {
|
|
95
121
|
const { container } = render(
|
|
96
|
-
<FieldViewerValue
|
|
122
|
+
<FieldViewerValue
|
|
123
|
+
type="markdown"
|
|
124
|
+
value=" "
|
|
125
|
+
label="md"
|
|
126
|
+
widget="markdown"
|
|
127
|
+
/>
|
|
97
128
|
);
|
|
98
129
|
expect(container.firstChild).toBeNull();
|
|
99
130
|
});
|
|
131
|
+
|
|
132
|
+
it("renders only non-empty values for dynamic table array cells", () => {
|
|
133
|
+
const rendered = render(
|
|
134
|
+
<FieldViewerValue
|
|
135
|
+
type="dynamic_table"
|
|
136
|
+
values={{
|
|
137
|
+
table_columns: [{ name: "col1", cardinality: "*", type: "string" }],
|
|
138
|
+
}}
|
|
139
|
+
value={[
|
|
140
|
+
{
|
|
141
|
+
col1: {
|
|
142
|
+
value: ["v1", "", null, "v2"],
|
|
143
|
+
origin: "user",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
]}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const tableCell = rendered.container.querySelector("tbody td");
|
|
151
|
+
|
|
152
|
+
expect(rendered.getByText("v1")).toBeInTheDocument();
|
|
153
|
+
expect(rendered.getByText("v2")).toBeInTheDocument();
|
|
154
|
+
expect(tableCell.querySelectorAll(".ui.label")).toHaveLength(2);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("renders an empty cell for dynamic table values when the cell content is missing", () => {
|
|
158
|
+
const rendered = render(
|
|
159
|
+
<FieldViewerValue
|
|
160
|
+
type="dynamic_table"
|
|
161
|
+
values={{
|
|
162
|
+
table_columns: [{ name: "col1", cardinality: "*", type: "string" }],
|
|
163
|
+
}}
|
|
164
|
+
value={[{}]}
|
|
165
|
+
/>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
expect(rendered.container.querySelector("tbody td")).toBeEmptyDOMElement();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("returns null when the field value is nil", () => {
|
|
172
|
+
const { container } = render(
|
|
173
|
+
<FieldViewerValue type="string" value={null} />
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(container.firstChild).toBeNull();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("renders group values using the processed group name when alias is missing", () => {
|
|
180
|
+
const rendered = render(
|
|
181
|
+
<FieldViewerValue
|
|
182
|
+
type="group"
|
|
183
|
+
value="group:Data Owners"
|
|
184
|
+
multiple
|
|
185
|
+
values={{
|
|
186
|
+
processed_groups: [{ name: "Data Owners" }],
|
|
187
|
+
}}
|
|
188
|
+
/>
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
expect(rendered.getByText("Data Owners")).toBeInTheDocument();
|
|
192
|
+
expect(rendered.container.querySelector(".ui.label")).toBeInTheDocument();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("renders user_group values using the raw name when they are not groups", () => {
|
|
196
|
+
const rendered = render(
|
|
197
|
+
<FieldViewerValue type="user_group" value="user:Jane Doe" multiple />
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(rendered.getByText("Jane Doe")).toBeInTheDocument();
|
|
201
|
+
expect(rendered.container.querySelector(".ui.label")).toBeInTheDocument();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("renders identifier widgets with the identifier css class", () => {
|
|
205
|
+
const rendered = render(
|
|
206
|
+
<FieldViewerValue
|
|
207
|
+
type="string"
|
|
208
|
+
value="identifier-value"
|
|
209
|
+
widget="identifier"
|
|
210
|
+
/>
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
expect(
|
|
214
|
+
rendered.container.querySelector(".identifier-value")
|
|
215
|
+
).toHaveTextContent("identifier-value");
|
|
216
|
+
});
|
|
100
217
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { useQuery } from "@apollo/client";
|
|
4
|
+
import { Label } from "semantic-ui-react";
|
|
5
|
+
import { GROUP_PREVIEW_QUERY } from "../../api/queries";
|
|
6
|
+
import { LinkedUserGroupLabel } from "./UserGroupPreview";
|
|
7
|
+
|
|
8
|
+
const groupName = (group) => (_.isString(group) ? group : group.name);
|
|
9
|
+
const groupId = (group) => (_.isString(group) ? null : group.id);
|
|
10
|
+
const isGroup = (group) => groupName(group)?.startsWith("group:");
|
|
11
|
+
|
|
12
|
+
export const GroupPreview = ({ groups }) =>
|
|
13
|
+
_.flow(
|
|
14
|
+
_.filter(isGroup),
|
|
15
|
+
_.map((group) => (
|
|
16
|
+
<LinkedUserGroupLabel
|
|
17
|
+
key={groupId(group) || groupName(group)}
|
|
18
|
+
userGroup={group}
|
|
19
|
+
/>
|
|
20
|
+
)),
|
|
21
|
+
)(groups);
|
|
22
|
+
|
|
23
|
+
GroupPreview.propTypes = {
|
|
24
|
+
groups: PropTypes.arrayOf(
|
|
25
|
+
PropTypes.oneOfType([
|
|
26
|
+
PropTypes.shape({
|
|
27
|
+
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
|
|
28
|
+
.isRequired,
|
|
29
|
+
name: PropTypes.string.isRequired,
|
|
30
|
+
}),
|
|
31
|
+
PropTypes.string,
|
|
32
|
+
]),
|
|
33
|
+
).isRequired,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const GroupPreviewLoader = ({ groupId }) => {
|
|
37
|
+
const { loading, error, data } = useQuery(GROUP_PREVIEW_QUERY, {
|
|
38
|
+
variables: { ids: _.castArray(groupId) },
|
|
39
|
+
});
|
|
40
|
+
if (error) return null;
|
|
41
|
+
return loading ? (
|
|
42
|
+
<Label>...</Label>
|
|
43
|
+
) : (
|
|
44
|
+
<GroupPreview groups={data.groupDetails} />
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
GroupPreviewLoader.propTypes = {
|
|
49
|
+
groupId: PropTypes.oneOfType([
|
|
50
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
51
|
+
PropTypes.string,
|
|
52
|
+
]).isRequired,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default GroupPreviewLoader;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { useQuery } from "@apollo/client";
|
|
4
|
+
import { Icon, Label } from "semantic-ui-react";
|
|
5
|
+
import { Link } from "react-router";
|
|
6
|
+
import { linkTo } from "@truedat/core/routes";
|
|
7
|
+
import { USER_GROUP_PREVIEW_QUERY } from "../../api/queries";
|
|
8
|
+
|
|
9
|
+
const typeAndName = (value) => {
|
|
10
|
+
const [type, ...nameParts] = value.split(":");
|
|
11
|
+
return { type, name: nameParts.join(":") };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const userGroupName = (userGroup) =>
|
|
15
|
+
_.isString(userGroup) ? userGroup : userGroup.name;
|
|
16
|
+
|
|
17
|
+
const userGroupId = (userGroup) =>
|
|
18
|
+
_.isString(userGroup) ? null : userGroup.id;
|
|
19
|
+
|
|
20
|
+
const isGroup = (userGroup) => userGroupName(userGroup)?.startsWith("group:");
|
|
21
|
+
|
|
22
|
+
export const UserGroupLabel = ({ value }) => {
|
|
23
|
+
const { type, name } = typeAndName(value);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Label>
|
|
27
|
+
<Icon name={type} />
|
|
28
|
+
{name}
|
|
29
|
+
</Label>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
UserGroupLabel.propTypes = {
|
|
34
|
+
value: PropTypes.string.isRequired,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const LinkedUserGroupLabel = ({ userGroup }) => {
|
|
38
|
+
const id = userGroupId(userGroup);
|
|
39
|
+
const label = <UserGroupLabel value={userGroupName(userGroup)} />;
|
|
40
|
+
|
|
41
|
+
return id && isGroup(userGroup) ? (
|
|
42
|
+
<Link to={linkTo.GROUP({ id })}>{label}</Link>
|
|
43
|
+
) : (
|
|
44
|
+
label
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
LinkedUserGroupLabel.propTypes = {
|
|
49
|
+
userGroup: PropTypes.oneOfType([
|
|
50
|
+
PropTypes.shape({
|
|
51
|
+
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
52
|
+
name: PropTypes.string.isRequired,
|
|
53
|
+
}),
|
|
54
|
+
PropTypes.string,
|
|
55
|
+
]).isRequired,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const UserGroupPreview = ({ userGroups }) =>
|
|
59
|
+
_.map((userGroup) => (
|
|
60
|
+
<LinkedUserGroupLabel
|
|
61
|
+
key={userGroupId(userGroup) || userGroupName(userGroup)}
|
|
62
|
+
userGroup={userGroup}
|
|
63
|
+
/>
|
|
64
|
+
))(userGroups);
|
|
65
|
+
|
|
66
|
+
UserGroupPreview.propTypes = {
|
|
67
|
+
userGroups: PropTypes.arrayOf(
|
|
68
|
+
PropTypes.oneOfType([
|
|
69
|
+
PropTypes.shape({
|
|
70
|
+
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
71
|
+
name: PropTypes.string.isRequired,
|
|
72
|
+
}),
|
|
73
|
+
PropTypes.string,
|
|
74
|
+
]),
|
|
75
|
+
).isRequired,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const UserGroupPreviewLoader = ({ userGroupId }) => {
|
|
79
|
+
const { loading, error, data } = useQuery(USER_GROUP_PREVIEW_QUERY, {
|
|
80
|
+
variables: { ids: _.castArray(userGroupId) },
|
|
81
|
+
});
|
|
82
|
+
if (error) return null;
|
|
83
|
+
return loading ? (
|
|
84
|
+
<Label>...</Label>
|
|
85
|
+
) : (
|
|
86
|
+
<UserGroupPreview userGroups={data.userGroupDetails} />
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
UserGroupPreviewLoader.propTypes = {
|
|
91
|
+
userGroupId: PropTypes.oneOfType([
|
|
92
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
93
|
+
PropTypes.string,
|
|
94
|
+
]).isRequired,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default UserGroupPreviewLoader;
|