@webiny/app-security-access-management 6.3.0 → 6.4.0-beta.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/Extension.js +74 -73
- package/Extension.js.map +1 -1
- package/SecurityPermissions.js +49 -41
- package/SecurityPermissions.js.map +1 -1
- package/constants.js +6 -5
- package/constants.js.map +1 -1
- package/domain/permissionsSchema.js +30 -19
- package/domain/permissionsSchema.js.map +1 -1
- package/features/permissions/abstractions.js +2 -1
- package/features/permissions/abstractions.js.map +1 -1
- package/features/permissions/feature.js +2 -1
- package/features/permissions/feature.js.map +1 -1
- package/index.js +0 -2
- package/package.json +9 -11
- package/routes.js +32 -37
- package/routes.js.map +1 -1
- package/types.js +0 -3
- package/ui/views/ApiKeys/ApiKeyForm.js +203 -220
- package/ui/views/ApiKeys/ApiKeyForm.js.map +1 -1
- package/ui/views/ApiKeys/ApiKeys.js +11 -12
- package/ui/views/ApiKeys/ApiKeys.js.map +1 -1
- package/ui/views/ApiKeys/ApiKeysDataList.js +129 -143
- package/ui/views/ApiKeys/ApiKeysDataList.js.map +1 -1
- package/ui/views/ApiKeys/graphql.js +7 -6
- package/ui/views/ApiKeys/graphql.js.map +1 -1
- package/ui/views/ApiKeys/index.js +0 -2
- package/ui/views/ApiKeys/utils.js +12 -6
- package/ui/views/ApiKeys/utils.js.map +1 -1
- package/ui/views/Roles/Roles.js +11 -12
- package/ui/views/Roles/Roles.js.map +1 -1
- package/ui/views/Roles/RolesDataList.js +130 -144
- package/ui/views/Roles/RolesDataList.js.map +1 -1
- package/ui/views/Roles/RolesForm.js +198 -223
- package/ui/views/Roles/RolesForm.js.map +1 -1
- package/ui/views/Roles/graphql.js +7 -6
- package/ui/views/Roles/graphql.js.map +1 -1
- package/ui/views/Roles/index.js +0 -2
- package/ui/views/Teams/Teams.js +11 -12
- package/ui/views/Teams/Teams.js.map +1 -1
- package/ui/views/Teams/TeamsDataList.js +130 -146
- package/ui/views/Teams/TeamsDataList.js.map +1 -1
- package/ui/views/Teams/TeamsForm.js +174 -182
- package/ui/views/Teams/TeamsForm.js.map +1 -1
- package/ui/views/Teams/graphql.js +7 -6
- package/ui/views/Teams/graphql.js.map +1 -1
- package/ui/views/Teams/index.js +0 -2
- package/ui/views/utils.js +9 -7
- package/ui/views/utils.js.map +1 -1
- package/index.js.map +0 -1
- package/types.js.map +0 -1
- package/ui/views/ApiKeys/index.js.map +0 -1
- package/ui/views/Roles/index.js.map +0 -1
- package/ui/views/Teams/index.js.map +0 -1
|
@@ -1,237 +1,220 @@
|
|
|
1
|
-
import
|
|
1
|
+
import react, { useCallback } from "react";
|
|
2
2
|
import { useMutation, useQuery } from "@apollo/react-hooks";
|
|
3
3
|
import get from "lodash/get.js";
|
|
4
4
|
import isEmpty from "lodash/isEmpty.js";
|
|
5
5
|
import { i18n } from "@webiny/app/i18n/index.js";
|
|
6
|
-
import { Bind, Form, useForm, useGenerateSlug } from "@webiny/form";
|
|
7
|
-
import {
|
|
6
|
+
import { Bind as form_Bind, Form, useForm, useGenerateSlug } from "@webiny/form";
|
|
7
|
+
import { EmptyView, Permissions, SimpleForm, SimpleFormContent, SimpleFormFooter, SimpleFormHeader, useRouter } from "@webiny/app-admin";
|
|
8
8
|
import { validation } from "@webiny/validation";
|
|
9
|
-
import { ReactComponent
|
|
10
|
-
import { ReactComponent as
|
|
11
|
-
import { ReactComponent as
|
|
12
|
-
import { ReactComponent as
|
|
9
|
+
import { ReactComponent } from "@webiny/icons/add.svg";
|
|
10
|
+
import { ReactComponent as content_copy_svg_ReactComponent } from "@webiny/icons/content_copy.svg";
|
|
11
|
+
import { ReactComponent as content_paste_svg_ReactComponent } from "@webiny/icons/content_paste.svg";
|
|
12
|
+
import { ReactComponent as settings_svg_ReactComponent } from "@webiny/icons/settings.svg";
|
|
13
13
|
import { pickDataForCreate, pickDataForUpdate } from "./utils.js";
|
|
14
|
-
import * as GQL from "./graphql.js";
|
|
15
14
|
import { Alert, Button, CopyButton, Grid, Icon, IconButton, Input, Label, OverlayLoader, Textarea, Tooltip, useToast } from "@webiny/admin-ui";
|
|
16
15
|
import { Routes } from "../../../routes.js";
|
|
16
|
+
import * as __rspack_external__graphql_js_d64db012 from "./graphql.js";
|
|
17
17
|
const t = i18n.ns("app-security-admin-users/admin/api-keys/form");
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
18
|
+
const ApiKeyForm = ({ id, newEntry })=>{
|
|
19
|
+
const { goToRoute } = useRouter();
|
|
20
|
+
const toast = useToast();
|
|
21
|
+
const getQuery = useQuery(__rspack_external__graphql_js_d64db012.READ_API_KEY, {
|
|
22
|
+
variables: {
|
|
23
|
+
id
|
|
24
|
+
},
|
|
25
|
+
skip: !id,
|
|
26
|
+
onCompleted: (data)=>{
|
|
27
|
+
if (!data) return;
|
|
28
|
+
const { error } = data.security.apiKey;
|
|
29
|
+
if (error) {
|
|
30
|
+
goToRoute(Routes.ApiKeys.List);
|
|
31
|
+
toast.showWarningToast({
|
|
32
|
+
title: error.message
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const [create, createMutation] = useMutation(__rspack_external__graphql_js_d64db012.CREATE_API_KEY, {
|
|
38
|
+
refetchQueries: [
|
|
39
|
+
{
|
|
40
|
+
query: __rspack_external__graphql_js_d64db012.LIST_API_KEYS
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
});
|
|
44
|
+
const [update, updateMutation] = useMutation(__rspack_external__graphql_js_d64db012.UPDATE_API_KEY, {
|
|
45
|
+
refetchQueries: [
|
|
46
|
+
{
|
|
47
|
+
query: __rspack_external__graphql_js_d64db012.LIST_API_KEYS
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
const loading = [
|
|
52
|
+
getQuery,
|
|
53
|
+
createMutation,
|
|
54
|
+
updateMutation
|
|
55
|
+
].find((item)=>item.loading);
|
|
56
|
+
const onSubmit = useCallback(async (formData)=>{
|
|
57
|
+
if (!formData.permissions || !formData.permissions.length) return void toast.showWarningToast({
|
|
58
|
+
title: t`You must configure permissions before saving!`,
|
|
59
|
+
duration: 1 / 0
|
|
60
|
+
});
|
|
61
|
+
const isUpdate = formData.createdOn;
|
|
62
|
+
const [operation, args] = isUpdate ? [
|
|
63
|
+
update,
|
|
64
|
+
{
|
|
65
|
+
variables: {
|
|
66
|
+
id: formData.id,
|
|
67
|
+
data: pickDataForUpdate(formData)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
] : [
|
|
71
|
+
create,
|
|
72
|
+
{
|
|
73
|
+
variables: {
|
|
74
|
+
data: pickDataForCreate(formData)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
const response = await operation(args);
|
|
79
|
+
const { error } = response.data.security.apiKey;
|
|
80
|
+
if (error) return void toast.showWarningToast({
|
|
81
|
+
title: error.message
|
|
82
|
+
});
|
|
83
|
+
const { id } = response.data.security.apiKey.data;
|
|
84
|
+
if (!isUpdate) goToRoute(Routes.ApiKeys.List, {
|
|
85
|
+
id
|
|
42
86
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
refetchQueries: [{
|
|
48
|
-
query: GQL.LIST_API_KEYS
|
|
49
|
-
}]
|
|
50
|
-
});
|
|
51
|
-
const [update, updateMutation] = useMutation(GQL.UPDATE_API_KEY, {
|
|
52
|
-
refetchQueries: [{
|
|
53
|
-
query: GQL.LIST_API_KEYS
|
|
54
|
-
}]
|
|
55
|
-
});
|
|
56
|
-
const loading = [getQuery, createMutation, updateMutation].find(item => item.loading);
|
|
57
|
-
const onSubmit = useCallback(async formData => {
|
|
58
|
-
if (!formData.permissions || !formData.permissions.length) {
|
|
59
|
-
toast.showWarningToast({
|
|
60
|
-
title: t`You must configure permissions before saving!`,
|
|
61
|
-
duration: Infinity
|
|
62
|
-
});
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const isUpdate = formData.createdOn;
|
|
66
|
-
const [operation, args] = isUpdate ? [update, {
|
|
67
|
-
variables: {
|
|
68
|
-
id: formData.id,
|
|
69
|
-
data: pickDataForUpdate(formData)
|
|
70
|
-
}
|
|
71
|
-
}] : [create, {
|
|
72
|
-
variables: {
|
|
73
|
-
data: pickDataForCreate(formData)
|
|
74
|
-
}
|
|
75
|
-
}];
|
|
76
|
-
const response = await operation(args);
|
|
77
|
-
const {
|
|
78
|
-
error
|
|
79
|
-
} = response.data.security.apiKey;
|
|
80
|
-
if (error) {
|
|
81
|
-
toast.showWarningToast({
|
|
82
|
-
title: error.message
|
|
83
|
-
});
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const {
|
|
87
|
-
id
|
|
88
|
-
} = response.data.security.apiKey.data;
|
|
89
|
-
if (!isUpdate) {
|
|
90
|
-
goToRoute(Routes.ApiKeys.List, {
|
|
87
|
+
toast.showSuccessToast({
|
|
88
|
+
title: t`API key saved successfully.`
|
|
89
|
+
});
|
|
90
|
+
}, [
|
|
91
91
|
id
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
onClick: () => {
|
|
109
|
-
goToRoute(Routes.ApiKeys.List, {
|
|
110
|
-
new: true
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
})
|
|
92
|
+
]);
|
|
93
|
+
const data = get(getQuery, "data.security.apiKey.data", {});
|
|
94
|
+
const showEmptyView = !newEntry && !loading && isEmpty(data);
|
|
95
|
+
if (showEmptyView) return /*#__PURE__*/ react.createElement(EmptyView, {
|
|
96
|
+
icon: /*#__PURE__*/ react.createElement(settings_svg_ReactComponent, null),
|
|
97
|
+
title: t`Click on the left side list to display API key details or create a...`,
|
|
98
|
+
action: /*#__PURE__*/ react.createElement(Button, {
|
|
99
|
+
icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
|
|
100
|
+
text: t`New API Key`,
|
|
101
|
+
"data-testid": "new-record-button",
|
|
102
|
+
onClick: ()=>{
|
|
103
|
+
goToRoute(Routes.ApiKeys.List, {
|
|
104
|
+
new: true
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
})
|
|
114
108
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}), /*#__PURE__*/React.createElement(Button, {
|
|
152
|
-
text: t`Save`,
|
|
153
|
-
"data-testid": "sam.key.new.form.button.save",
|
|
154
|
-
onClick: form.submit
|
|
155
|
-
})));
|
|
156
|
-
});
|
|
109
|
+
return /*#__PURE__*/ react.createElement(Form, {
|
|
110
|
+
data: data,
|
|
111
|
+
onSubmit: onSubmit
|
|
112
|
+
}, ({ data, form, Bind })=>/*#__PURE__*/ react.createElement(SimpleForm, {
|
|
113
|
+
size: "lg"
|
|
114
|
+
}, loading && /*#__PURE__*/ react.createElement(OverlayLoader, null), /*#__PURE__*/ react.createElement(SimpleFormHeader, {
|
|
115
|
+
title: data.name ? data.name : "Untitled"
|
|
116
|
+
}), /*#__PURE__*/ react.createElement(SimpleFormContent, null, /*#__PURE__*/ react.createElement(FormContent, {
|
|
117
|
+
newEntry: newEntry
|
|
118
|
+
})), /*#__PURE__*/ react.createElement(SimpleFormHeader, {
|
|
119
|
+
title: "Permissions",
|
|
120
|
+
rounded: false
|
|
121
|
+
}, /*#__PURE__*/ react.createElement("div", {
|
|
122
|
+
className: "flex justify-end"
|
|
123
|
+
}, /*#__PURE__*/ react.createElement(CopyPermissionsToJson, {
|
|
124
|
+
permissions: data.permissions
|
|
125
|
+
}))), /*#__PURE__*/ react.createElement(SimpleFormContent, null, /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
126
|
+
span: 12
|
|
127
|
+
}, /*#__PURE__*/ react.createElement(Bind, {
|
|
128
|
+
name: "permissions",
|
|
129
|
+
defaultValue: []
|
|
130
|
+
}, (bind)=>/*#__PURE__*/ react.createElement(Permissions, {
|
|
131
|
+
id: data.id || "new",
|
|
132
|
+
...bind
|
|
133
|
+
}))))), /*#__PURE__*/ react.createElement(SimpleFormFooter, null, /*#__PURE__*/ react.createElement(Button, {
|
|
134
|
+
variant: "secondary",
|
|
135
|
+
text: t`Cancel`,
|
|
136
|
+
onClick: ()=>{
|
|
137
|
+
goToRoute(Routes.ApiKeys.List);
|
|
138
|
+
},
|
|
139
|
+
"data-testid": "sam.key.new.form.button.cancel"
|
|
140
|
+
}), /*#__PURE__*/ react.createElement(Button, {
|
|
141
|
+
text: t`Save`,
|
|
142
|
+
"data-testid": "sam.key.new.form.button.save",
|
|
143
|
+
onClick: form.submit
|
|
144
|
+
}))));
|
|
157
145
|
};
|
|
158
|
-
const FormContent = props
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
})) : /*#__PURE__*/React.createElement(Alert, {
|
|
211
|
-
className: "mt-xs"
|
|
212
|
-
}, "Your token will be shown once you submit the form."))));
|
|
146
|
+
const FormContent = (props)=>{
|
|
147
|
+
const { newEntry } = props;
|
|
148
|
+
const form = useForm();
|
|
149
|
+
const toast = useToast();
|
|
150
|
+
const { generateSlug } = useGenerateSlug(form, "name", "slug");
|
|
151
|
+
const data = form.data;
|
|
152
|
+
return /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
153
|
+
span: 6
|
|
154
|
+
}, /*#__PURE__*/ react.createElement(form_Bind, {
|
|
155
|
+
name: "name",
|
|
156
|
+
validators: validation.create("required")
|
|
157
|
+
}, /*#__PURE__*/ react.createElement(Input, {
|
|
158
|
+
label: t`Name`,
|
|
159
|
+
"data-testid": "sam.key.new.form.name",
|
|
160
|
+
onBlur: generateSlug
|
|
161
|
+
}))), /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
162
|
+
span: 6
|
|
163
|
+
}, /*#__PURE__*/ react.createElement(form_Bind, {
|
|
164
|
+
name: "slug",
|
|
165
|
+
validators: validation.create("required")
|
|
166
|
+
}, /*#__PURE__*/ react.createElement(Input, {
|
|
167
|
+
label: t`Slug`,
|
|
168
|
+
"data-testid": "sam.key.new.form.name",
|
|
169
|
+
disabled: !newEntry
|
|
170
|
+
}))), /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
171
|
+
span: 12
|
|
172
|
+
}, /*#__PURE__*/ react.createElement(form_Bind, {
|
|
173
|
+
name: "description",
|
|
174
|
+
validators: validation.create("required")
|
|
175
|
+
}, /*#__PURE__*/ react.createElement(Textarea, {
|
|
176
|
+
size: "lg",
|
|
177
|
+
label: t`Description`,
|
|
178
|
+
rows: 4,
|
|
179
|
+
"data-testid": "sam.key.new.form.description"
|
|
180
|
+
}))), /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
181
|
+
span: 12
|
|
182
|
+
}, /*#__PURE__*/ react.createElement("div", null, /*#__PURE__*/ react.createElement(Label, {
|
|
183
|
+
text: t`Token`
|
|
184
|
+
}), data.token ? /*#__PURE__*/ react.createElement("div", {
|
|
185
|
+
className: "py-sm pl-sm-extra pr-xs rounded-md mt-xs bg-neutral-disabled flex justify-between items-center"
|
|
186
|
+
}, /*#__PURE__*/ react.createElement("div", null, data.token), /*#__PURE__*/ react.createElement(CopyButton, {
|
|
187
|
+
variant: "ghost",
|
|
188
|
+
value: data.token,
|
|
189
|
+
onCopy: ()=>{
|
|
190
|
+
toast.showSuccessToast({
|
|
191
|
+
title: "Successfully copied!"
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
})) : /*#__PURE__*/ react.createElement(Alert, {
|
|
195
|
+
className: "mt-xs"
|
|
196
|
+
}, "Your token will be shown once you submit the form."))));
|
|
213
197
|
};
|
|
214
|
-
const CopyPermissionsToJson = ({
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
})
|
|
234
|
-
});
|
|
198
|
+
const CopyPermissionsToJson = ({ permissions })=>{
|
|
199
|
+
const toast = useToast();
|
|
200
|
+
return /*#__PURE__*/ react.createElement(Tooltip, {
|
|
201
|
+
content: "Copy permissions as JSON",
|
|
202
|
+
trigger: /*#__PURE__*/ react.createElement(IconButton, {
|
|
203
|
+
variant: "ghost",
|
|
204
|
+
icon: /*#__PURE__*/ react.createElement(content_copy_svg_ReactComponent, null),
|
|
205
|
+
onClick: ()=>{
|
|
206
|
+
navigator.clipboard.writeText(JSON.stringify(permissions, null, 2));
|
|
207
|
+
toast.showToast({
|
|
208
|
+
title: "JSON data copied to clipboard.",
|
|
209
|
+
icon: /*#__PURE__*/ react.createElement(Icon, {
|
|
210
|
+
icon: /*#__PURE__*/ react.createElement(content_paste_svg_ReactComponent, null),
|
|
211
|
+
label: "Paste"
|
|
212
|
+
})
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
});
|
|
235
217
|
};
|
|
218
|
+
export { ApiKeyForm };
|
|
236
219
|
|
|
237
220
|
//# sourceMappingURL=ApiKeyForm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useCallback","useMutation","useQuery","get","isEmpty","i18n","Bind","Form","useForm","useGenerateSlug","useRouter","Permissions","EmptyView","SimpleForm","SimpleFormFooter","SimpleFormContent","SimpleFormHeader","validation","ReactComponent","AddIcon","CopyIcon","PasteIcon","SettingsIcon","pickDataForCreate","pickDataForUpdate","GQL","Alert","Button","CopyButton","Grid","Icon","IconButton","Input","Label","OverlayLoader","Textarea","Tooltip","useToast","Routes","t","ns","ApiKeyForm","id","newEntry","goToRoute","toast","getQuery","READ_API_KEY","variables","skip","onCompleted","data","error","security","apiKey","ApiKeys","List","showWarningToast","title","message","create","createMutation","CREATE_API_KEY","refetchQueries","query","LIST_API_KEYS","update","updateMutation","UPDATE_API_KEY","loading","find","item","onSubmit","formData","permissions","length","duration","Infinity","isUpdate","createdOn","operation","args","response","showSuccessToast","showEmptyView","createElement","icon","action","text","onClick","new","form","size","name","FormContent","rounded","className","CopyPermissionsToJson","Column","span","defaultValue","bind","Object","assign","variant","submit","props","generateSlug","validators","label","onBlur","disabled","rows","token","value","onCopy","content","trigger","navigator","clipboard","writeText","JSON","stringify","showToast"],"sources":["ApiKeyForm.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { useMutation, useQuery } from \"@apollo/react-hooks\";\nimport get from \"lodash/get.js\";\nimport isEmpty from \"lodash/isEmpty.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { Bind, Form, useForm, useGenerateSlug } from \"@webiny/form\";\nimport {\n useRouter,\n Permissions,\n EmptyView,\n SimpleForm,\n SimpleFormFooter,\n SimpleFormContent,\n SimpleFormHeader\n} from \"@webiny/app-admin\";\nimport { validation } from \"@webiny/validation\";\nimport { ReactComponent as AddIcon } from \"@webiny/icons/add.svg\";\nimport { ReactComponent as CopyIcon } from \"@webiny/icons/content_copy.svg\";\nimport { ReactComponent as PasteIcon } from \"@webiny/icons/content_paste.svg\";\nimport { ReactComponent as SettingsIcon } from \"@webiny/icons/settings.svg\";\nimport { pickDataForCreate, pickDataForUpdate } from \"./utils.js\";\nimport * as GQL from \"./graphql.js\";\nimport type { ApiKey } from \"~/types.js\";\nimport {\n Alert,\n Button,\n CopyButton,\n Grid,\n Icon,\n IconButton,\n Input,\n Label,\n OverlayLoader,\n Textarea,\n Tooltip,\n useToast\n} from \"@webiny/admin-ui\";\nimport { Routes } from \"~/routes.js\";\nimport type { GenericRecord } from \"@webiny/app/types.js\";\n\nconst t = i18n.ns(\"app-security-admin-users/admin/api-keys/form\");\n\ninterface ApiKeyFormProps {\n newEntry: boolean;\n id: string | undefined;\n}\n\nexport const ApiKeyForm = ({ id, newEntry }: ApiKeyFormProps) => {\n const { goToRoute } = useRouter();\n const toast = useToast();\n\n const getQuery = useQuery(GQL.READ_API_KEY, {\n variables: { id },\n skip: !id,\n onCompleted: data => {\n if (!data) {\n return;\n }\n\n const { error } = data.security.apiKey;\n if (error) {\n goToRoute(Routes.ApiKeys.List);\n toast.showWarningToast({ title: error.message });\n }\n }\n });\n\n const [create, createMutation] = useMutation(GQL.CREATE_API_KEY, {\n refetchQueries: [{ query: GQL.LIST_API_KEYS }]\n });\n\n const [update, updateMutation] = useMutation(GQL.UPDATE_API_KEY, {\n refetchQueries: [{ query: GQL.LIST_API_KEYS }]\n });\n\n const loading = [getQuery, createMutation, updateMutation].find(item => item.loading);\n\n const onSubmit = useCallback(\n async (formData: ApiKey) => {\n if (!formData.permissions || !formData.permissions.length) {\n toast.showWarningToast({\n title: t`You must configure permissions before saving!`,\n duration: Infinity\n });\n return;\n }\n\n const isUpdate = formData.createdOn;\n const [operation, args] = isUpdate\n ? [update, { variables: { id: formData.id, data: pickDataForUpdate(formData) } }]\n : [create, { variables: { data: pickDataForCreate(formData) } }];\n\n const response = await operation(args);\n\n const { error } = response.data.security.apiKey;\n if (error) {\n toast.showWarningToast({ title: error.message });\n return;\n }\n\n const { id } = response.data.security.apiKey.data;\n\n if (!isUpdate) {\n goToRoute(Routes.ApiKeys.List, { id });\n }\n\n toast.showSuccessToast({ title: t`API key saved successfully.` });\n },\n [id]\n );\n\n const data: ApiKey = get(getQuery, \"data.security.apiKey.data\", {});\n\n const showEmptyView = !newEntry && !loading && isEmpty(data);\n\n if (showEmptyView) {\n return (\n <EmptyView\n icon={<SettingsIcon />}\n title={t`Click on the left side list to display API key details or create a...`}\n action={\n <Button\n icon={<AddIcon />}\n text={t`New API Key`}\n data-testid=\"new-record-button\"\n onClick={() => {\n goToRoute(Routes.ApiKeys.List, { new: true });\n }}\n />\n }\n />\n );\n }\n\n return (\n <Form data={data} onSubmit={onSubmit}>\n {({ data, form, Bind }) => {\n return (\n <SimpleForm size={\"lg\"}>\n {loading && <OverlayLoader />}\n <SimpleFormHeader title={data.name ? data.name : \"Untitled\"} />\n <SimpleFormContent>\n <FormContent newEntry={newEntry} />\n </SimpleFormContent>\n <SimpleFormHeader title={\"Permissions\"} rounded={false}>\n <div className={\"flex justify-end\"}>\n <CopyPermissionsToJson permissions={data.permissions} />\n </div>\n </SimpleFormHeader>\n <SimpleFormContent>\n <Grid>\n <Grid.Column span={12}>\n <Bind name={\"permissions\"} defaultValue={[]}>\n {bind => <Permissions id={data.id || \"new\"} {...bind} />}\n </Bind>\n </Grid.Column>\n </Grid>\n </SimpleFormContent>\n <SimpleFormFooter>\n <Button\n variant={\"secondary\"}\n text={t`Cancel`}\n onClick={() => {\n goToRoute(Routes.ApiKeys.List);\n }}\n data-testid=\"sam.key.new.form.button.cancel\"\n />\n <Button\n text={t`Save`}\n data-testid=\"sam.key.new.form.button.save\"\n onClick={form.submit}\n />\n </SimpleFormFooter>\n </SimpleForm>\n );\n }}\n </Form>\n );\n};\n\ninterface FormContentProps {\n newEntry: boolean;\n}\n\nconst FormContent = (props: FormContentProps) => {\n const { newEntry } = props;\n const form = useForm();\n const toast = useToast();\n const { generateSlug } = useGenerateSlug(form, \"name\", \"slug\");\n const data = form.data;\n\n return (\n <Grid>\n <Grid.Column span={6}>\n <Bind name=\"name\" validators={validation.create(\"required\")}>\n <Input\n label={t`Name`}\n data-testid=\"sam.key.new.form.name\"\n onBlur={generateSlug}\n />\n </Bind>\n </Grid.Column>\n <Grid.Column span={6}>\n <Bind name=\"slug\" validators={validation.create(\"required\")}>\n <Input\n label={t`Slug`}\n data-testid=\"sam.key.new.form.name\"\n disabled={!newEntry}\n />\n </Bind>\n </Grid.Column>\n <Grid.Column span={12}>\n <Bind name=\"description\" validators={validation.create(\"required\")}>\n <Textarea\n size={\"lg\"}\n label={t`Description`}\n rows={4}\n data-testid=\"sam.key.new.form.description\"\n />\n </Bind>\n </Grid.Column>\n <Grid.Column span={12}>\n <div>\n <Label text={t`Token`} />\n {data.token ? (\n <div\n className={\n \"py-sm pl-sm-extra pr-xs rounded-md mt-xs bg-neutral-disabled flex justify-between items-center\"\n }\n >\n <div>{data.token}</div>\n <CopyButton\n variant={\"ghost\"}\n value={data.token}\n onCopy={() => {\n toast.showSuccessToast({ title: \"Successfully copied!\" });\n }}\n />\n </div>\n ) : (\n <Alert className={\"mt-xs\"}>\n {\"Your token will be shown once you submit the form.\"}\n </Alert>\n )}\n </div>\n </Grid.Column>\n </Grid>\n );\n};\n\ninterface CopyPermissionsToJsonProps {\n permissions: GenericRecord[];\n}\n\nconst CopyPermissionsToJson = ({ permissions }: CopyPermissionsToJsonProps) => {\n const toast = useToast();\n\n return (\n <Tooltip\n content=\"Copy permissions as JSON\"\n trigger={\n <IconButton\n variant={\"ghost\"}\n icon={<CopyIcon />}\n onClick={() => {\n navigator.clipboard.writeText(JSON.stringify(permissions, null, 2));\n toast.showToast({\n title: \"JSON data copied to clipboard.\",\n icon: <Icon icon={<PasteIcon />} label={\"Paste\"} />\n });\n }}\n />\n }\n />\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ui/views/ApiKeys/ApiKeyForm.js","sources":["../../../../src/ui/views/ApiKeys/ApiKeyForm.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { useMutation, useQuery } from \"@apollo/react-hooks\";\nimport get from \"lodash/get.js\";\nimport isEmpty from \"lodash/isEmpty.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { Bind, Form, useForm, useGenerateSlug } from \"@webiny/form\";\nimport {\n useRouter,\n Permissions,\n EmptyView,\n SimpleForm,\n SimpleFormFooter,\n SimpleFormContent,\n SimpleFormHeader\n} from \"@webiny/app-admin\";\nimport { validation } from \"@webiny/validation\";\nimport { ReactComponent as AddIcon } from \"@webiny/icons/add.svg\";\nimport { ReactComponent as CopyIcon } from \"@webiny/icons/content_copy.svg\";\nimport { ReactComponent as PasteIcon } from \"@webiny/icons/content_paste.svg\";\nimport { ReactComponent as SettingsIcon } from \"@webiny/icons/settings.svg\";\nimport { pickDataForCreate, pickDataForUpdate } from \"./utils.js\";\nimport * as GQL from \"./graphql.js\";\nimport type { ApiKey } from \"~/types.js\";\nimport {\n Alert,\n Button,\n CopyButton,\n Grid,\n Icon,\n IconButton,\n Input,\n Label,\n OverlayLoader,\n Textarea,\n Tooltip,\n useToast\n} from \"@webiny/admin-ui\";\nimport { Routes } from \"~/routes.js\";\nimport type { GenericRecord } from \"@webiny/app/types.js\";\n\nconst t = i18n.ns(\"app-security-admin-users/admin/api-keys/form\");\n\ninterface ApiKeyFormProps {\n newEntry: boolean;\n id: string | undefined;\n}\n\nexport const ApiKeyForm = ({ id, newEntry }: ApiKeyFormProps) => {\n const { goToRoute } = useRouter();\n const toast = useToast();\n\n const getQuery = useQuery(GQL.READ_API_KEY, {\n variables: { id },\n skip: !id,\n onCompleted: data => {\n if (!data) {\n return;\n }\n\n const { error } = data.security.apiKey;\n if (error) {\n goToRoute(Routes.ApiKeys.List);\n toast.showWarningToast({ title: error.message });\n }\n }\n });\n\n const [create, createMutation] = useMutation(GQL.CREATE_API_KEY, {\n refetchQueries: [{ query: GQL.LIST_API_KEYS }]\n });\n\n const [update, updateMutation] = useMutation(GQL.UPDATE_API_KEY, {\n refetchQueries: [{ query: GQL.LIST_API_KEYS }]\n });\n\n const loading = [getQuery, createMutation, updateMutation].find(item => item.loading);\n\n const onSubmit = useCallback(\n async (formData: ApiKey) => {\n if (!formData.permissions || !formData.permissions.length) {\n toast.showWarningToast({\n title: t`You must configure permissions before saving!`,\n duration: Infinity\n });\n return;\n }\n\n const isUpdate = formData.createdOn;\n const [operation, args] = isUpdate\n ? [update, { variables: { id: formData.id, data: pickDataForUpdate(formData) } }]\n : [create, { variables: { data: pickDataForCreate(formData) } }];\n\n const response = await operation(args);\n\n const { error } = response.data.security.apiKey;\n if (error) {\n toast.showWarningToast({ title: error.message });\n return;\n }\n\n const { id } = response.data.security.apiKey.data;\n\n if (!isUpdate) {\n goToRoute(Routes.ApiKeys.List, { id });\n }\n\n toast.showSuccessToast({ title: t`API key saved successfully.` });\n },\n [id]\n );\n\n const data: ApiKey = get(getQuery, \"data.security.apiKey.data\", {});\n\n const showEmptyView = !newEntry && !loading && isEmpty(data);\n\n if (showEmptyView) {\n return (\n <EmptyView\n icon={<SettingsIcon />}\n title={t`Click on the left side list to display API key details or create a...`}\n action={\n <Button\n icon={<AddIcon />}\n text={t`New API Key`}\n data-testid=\"new-record-button\"\n onClick={() => {\n goToRoute(Routes.ApiKeys.List, { new: true });\n }}\n />\n }\n />\n );\n }\n\n return (\n <Form data={data} onSubmit={onSubmit}>\n {({ data, form, Bind }) => {\n return (\n <SimpleForm size={\"lg\"}>\n {loading && <OverlayLoader />}\n <SimpleFormHeader title={data.name ? data.name : \"Untitled\"} />\n <SimpleFormContent>\n <FormContent newEntry={newEntry} />\n </SimpleFormContent>\n <SimpleFormHeader title={\"Permissions\"} rounded={false}>\n <div className={\"flex justify-end\"}>\n <CopyPermissionsToJson permissions={data.permissions} />\n </div>\n </SimpleFormHeader>\n <SimpleFormContent>\n <Grid>\n <Grid.Column span={12}>\n <Bind name={\"permissions\"} defaultValue={[]}>\n {bind => <Permissions id={data.id || \"new\"} {...bind} />}\n </Bind>\n </Grid.Column>\n </Grid>\n </SimpleFormContent>\n <SimpleFormFooter>\n <Button\n variant={\"secondary\"}\n text={t`Cancel`}\n onClick={() => {\n goToRoute(Routes.ApiKeys.List);\n }}\n data-testid=\"sam.key.new.form.button.cancel\"\n />\n <Button\n text={t`Save`}\n data-testid=\"sam.key.new.form.button.save\"\n onClick={form.submit}\n />\n </SimpleFormFooter>\n </SimpleForm>\n );\n }}\n </Form>\n );\n};\n\ninterface FormContentProps {\n newEntry: boolean;\n}\n\nconst FormContent = (props: FormContentProps) => {\n const { newEntry } = props;\n const form = useForm();\n const toast = useToast();\n const { generateSlug } = useGenerateSlug(form, \"name\", \"slug\");\n const data = form.data;\n\n return (\n <Grid>\n <Grid.Column span={6}>\n <Bind name=\"name\" validators={validation.create(\"required\")}>\n <Input\n label={t`Name`}\n data-testid=\"sam.key.new.form.name\"\n onBlur={generateSlug}\n />\n </Bind>\n </Grid.Column>\n <Grid.Column span={6}>\n <Bind name=\"slug\" validators={validation.create(\"required\")}>\n <Input\n label={t`Slug`}\n data-testid=\"sam.key.new.form.name\"\n disabled={!newEntry}\n />\n </Bind>\n </Grid.Column>\n <Grid.Column span={12}>\n <Bind name=\"description\" validators={validation.create(\"required\")}>\n <Textarea\n size={\"lg\"}\n label={t`Description`}\n rows={4}\n data-testid=\"sam.key.new.form.description\"\n />\n </Bind>\n </Grid.Column>\n <Grid.Column span={12}>\n <div>\n <Label text={t`Token`} />\n {data.token ? (\n <div\n className={\n \"py-sm pl-sm-extra pr-xs rounded-md mt-xs bg-neutral-disabled flex justify-between items-center\"\n }\n >\n <div>{data.token}</div>\n <CopyButton\n variant={\"ghost\"}\n value={data.token}\n onCopy={() => {\n toast.showSuccessToast({ title: \"Successfully copied!\" });\n }}\n />\n </div>\n ) : (\n <Alert className={\"mt-xs\"}>\n {\"Your token will be shown once you submit the form.\"}\n </Alert>\n )}\n </div>\n </Grid.Column>\n </Grid>\n );\n};\n\ninterface CopyPermissionsToJsonProps {\n permissions: GenericRecord[];\n}\n\nconst CopyPermissionsToJson = ({ permissions }: CopyPermissionsToJsonProps) => {\n const toast = useToast();\n\n return (\n <Tooltip\n content=\"Copy permissions as JSON\"\n trigger={\n <IconButton\n variant={\"ghost\"}\n icon={<CopyIcon />}\n onClick={() => {\n navigator.clipboard.writeText(JSON.stringify(permissions, null, 2));\n toast.showToast({\n title: \"JSON data copied to clipboard.\",\n icon: <Icon icon={<PasteIcon />} label={\"Paste\"} />\n });\n }}\n />\n }\n />\n );\n};\n"],"names":["t","i18n","ApiKeyForm","id","newEntry","goToRoute","useRouter","toast","useToast","getQuery","useQuery","GQL","data","error","Routes","create","createMutation","useMutation","update","updateMutation","loading","item","onSubmit","useCallback","formData","Infinity","isUpdate","operation","args","pickDataForUpdate","pickDataForCreate","response","get","showEmptyView","isEmpty","EmptyView","SettingsIcon","Button","AddIcon","Form","form","Bind","SimpleForm","OverlayLoader","SimpleFormHeader","SimpleFormContent","FormContent","CopyPermissionsToJson","Grid","bind","Permissions","SimpleFormFooter","props","useForm","generateSlug","useGenerateSlug","validation","Input","Textarea","Label","CopyButton","Alert","permissions","Tooltip","IconButton","CopyIcon","navigator","JSON","Icon","PasteIcon"],"mappings":"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"}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { useRoute, SplitView, LeftPanel, RightPanel } from "@webiny/app-admin";
|
|
1
|
+
import { LeftPanel, RightPanel, SplitView, useRoute } from "@webiny/app-admin";
|
|
3
2
|
import { ApiKeysDataList } from "./ApiKeysDataList.js";
|
|
4
3
|
import { ApiKeyForm } from "./ApiKeyForm.js";
|
|
5
4
|
import { Routes } from "../../../routes.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
route
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
})));
|
|
5
|
+
import * as __rspack_external_react from "react";
|
|
6
|
+
const ApiKeys = ()=>{
|
|
7
|
+
const { route } = useRoute(Routes.ApiKeys.List);
|
|
8
|
+
return /*#__PURE__*/ __rspack_external_react.createElement(SplitView, null, /*#__PURE__*/ __rspack_external_react.createElement(LeftPanel, null, /*#__PURE__*/ __rspack_external_react.createElement(ApiKeysDataList, {
|
|
9
|
+
activeId: route.params.id
|
|
10
|
+
})), /*#__PURE__*/ __rspack_external_react.createElement(RightPanel, null, /*#__PURE__*/ __rspack_external_react.createElement(ApiKeyForm, {
|
|
11
|
+
newEntry: true === route.params.new,
|
|
12
|
+
id: route.params.id
|
|
13
|
+
})));
|
|
16
14
|
};
|
|
15
|
+
export { ApiKeys };
|
|
17
16
|
|
|
18
17
|
//# sourceMappingURL=ApiKeys.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"ui/views/ApiKeys/ApiKeys.js","sources":["../../../../src/ui/views/ApiKeys/ApiKeys.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useRoute, SplitView, LeftPanel, RightPanel } from \"@webiny/app-admin\";\nimport { ApiKeysDataList } from \"./ApiKeysDataList.js\";\nimport { ApiKeyForm } from \"./ApiKeyForm.js\";\nimport { Routes } from \"~/routes.js\";\n\nexport const ApiKeys = () => {\n const { route } = useRoute(Routes.ApiKeys.List);\n\n return (\n <SplitView>\n <LeftPanel>\n <ApiKeysDataList activeId={route.params.id} />\n </LeftPanel>\n <RightPanel>\n <ApiKeyForm newEntry={route.params.new === true} id={route.params.id} />\n </RightPanel>\n </SplitView>\n );\n};\n"],"names":["ApiKeys","route","useRoute","Routes","SplitView","LeftPanel","ApiKeysDataList","RightPanel","ApiKeyForm"],"mappings":";;;;;AAMO,MAAMA,UAAU;IACnB,MAAM,EAAEC,KAAK,EAAE,GAAGC,SAASC,OAAO,OAAO,CAAC,IAAI;IAE9C,OAAO,WAAP,GACI,sCAACC,WAASA,MAAAA,WAAAA,GACN,sCAACC,WAASA,MAAAA,WAAAA,GACN,sCAACC,iBAAeA;QAAC,UAAUL,MAAM,MAAM,CAAC,EAAE;uBAE9C,sCAACM,YAAUA,MAAAA,WAAAA,GACP,sCAACC,YAAUA;QAAC,UAAUP,AAAqB,SAArBA,MAAM,MAAM,CAAC,GAAG;QAAW,IAAIA,MAAM,MAAM,CAAC,EAAE;;AAIpF"}
|