@blocklet/ui-react 3.1.44 → 3.1.45

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.
@@ -0,0 +1,295 @@
1
+ import { jsxs as i, jsx as t, Fragment as Y } from "react/jsx-runtime";
2
+ import A from "prop-types";
3
+ import { useState as v, useRef as ee, useMemo as E, useEffect as te } from "react";
4
+ import { useMemoizedFn as k, useRequest as re, useDebounce as oe, useInfiniteScroll as ne } from "ahooks";
5
+ import { useNavigate as ie } from "react-router-dom";
6
+ import { WELLKNOWN_SERVICE_PATH_PREFIX as se } from "@abtnode/constant";
7
+ import { Box as r, Button as P, Avatar as S, Typography as s, Menu as ae, TextField as le, InputAdornment as ce, Divider as W, MenuItem as L, ListItemAvatar as R, ListItemText as D } from "@mui/material";
8
+ import { KeyboardArrowDown as de, Search as pe, Add as he, OpenInNew as me } from "@mui/icons-material";
9
+ import ue from "lodash/noop";
10
+ import { translate as ge } from "@arcblock/ux/lib/Locale/util";
11
+ import xe from "./use-org.js";
12
+ import fe from "./create.js";
13
+ import ye from "./locales.js";
14
+ const H = 20;
15
+ function be({ session: a, locale: h = "en" }) {
16
+ const [w, C] = v(null), [m, I] = v(""), [N, u] = v(!1), F = ee(null), j = ie(), l = k((e, o = {}) => ge(ye, e, h, "en", o)), { getOrgs: _, getCurrentOrg: B } = xe(a), n = E(() => a?.user?.role || "", [a?.user?.role]), { data: g = {} } = re(
17
+ () => B(n),
18
+ {
19
+ ready: !!n,
20
+ refreshDeps: [n],
21
+ onError: (e) => {
22
+ console.error("Failed to get organization role", e);
23
+ }
24
+ }
25
+ ), d = E(() => g || {
26
+ name: a?.user?.passports?.find((o) => o.name === n)?.title || n || "-"
27
+ }, [g, n, a?.user?.passports]), K = oe(m, { wait: 500 }), { data: V, loadMore: $, loadingMore: z, reload: O } = ne(
28
+ async (e) => {
29
+ const c = { page: e ? Math.ceil(e.list.length / H) + 1 : 1, pageSize: H, search: m }, y = await _(c), { orgs: b = [], paging: U } = y || {};
30
+ return { list: b, total: U?.total || 0 };
31
+ },
32
+ {
33
+ ready: !!n,
34
+ reloadDeps: [K],
35
+ isNoMore: (e) => e?.list.length ? e.list.length >= e?.total : !0,
36
+ onError: (e) => {
37
+ console.error("Failed to fetch organizations list", e);
38
+ }
39
+ }
40
+ ), { list: p = [], total: q = 0 } = V || {}, T = p.length < q, G = k((e) => {
41
+ const o = e.target, { scrollTop: c, scrollHeight: y, clientHeight: b } = o;
42
+ y - c - b < 50 && !z && T && $();
43
+ }), x = !!w;
44
+ te(() => {
45
+ x && O();
46
+ }, [x, O]);
47
+ const J = (e) => {
48
+ C(e.currentTarget);
49
+ }, f = () => {
50
+ C(null), u(!1), I("");
51
+ }, X = (e) => {
52
+ a.switchPassport(ue, { orgId: e.id }), f();
53
+ }, Z = () => {
54
+ u(!0);
55
+ }, M = () => {
56
+ j(`${se}/user/orgs?locale=${h}`), f();
57
+ }, Q = (e) => /* @__PURE__ */ i(
58
+ L,
59
+ {
60
+ onClick: () => X(e),
61
+ selected: e.id === d.id,
62
+ sx: {
63
+ py: 1.5,
64
+ px: 2,
65
+ "&.Mui-selected": {
66
+ backgroundColor: "action.selected",
67
+ "&:hover": {
68
+ backgroundColor: "action.hover"
69
+ }
70
+ }
71
+ },
72
+ children: [
73
+ /* @__PURE__ */ t(R, { sx: { minWidth: 40 }, children: /* @__PURE__ */ t(
74
+ S,
75
+ {
76
+ sx: {
77
+ width: 28,
78
+ height: 28,
79
+ fontSize: 14,
80
+ bgcolor: e.isOwner ? "primary.main" : "grey.400"
81
+ },
82
+ children: e.name?.[0]
83
+ }
84
+ ) }),
85
+ /* @__PURE__ */ i(r, { sx: { display: "flex", alignItems: "center", flex: 1 }, children: [
86
+ /* @__PURE__ */ t(
87
+ D,
88
+ {
89
+ sx: {
90
+ "& .MuiListItemText-primary": {
91
+ mb: 0
92
+ },
93
+ "& .MuiListItemText-secondary": {
94
+ mt: "-2px"
95
+ }
96
+ },
97
+ primary: /* @__PURE__ */ t(s, { variant: "body2", sx: { fontWeight: 500, lineHeight: 1.2 }, children: e.name }),
98
+ secondary: /* @__PURE__ */ t(s, { variant: "caption", color: "text.secondary", sx: { lineHeight: 1.1 }, children: e.passports?.[0]?.title })
99
+ }
100
+ ),
101
+ e.id === d.id && /* @__PURE__ */ t(r, { sx: { display: "flex", alignItems: "center", justifyContent: "center", ml: 1 }, children: /* @__PURE__ */ t(s, { variant: "caption", color: "primary", sx: { fontSize: 10 }, children: "✓" }) })
102
+ ] })
103
+ ]
104
+ },
105
+ e.id
106
+ );
107
+ return /* @__PURE__ */ i(r, { children: [
108
+ /* @__PURE__ */ i(
109
+ P,
110
+ {
111
+ ref: F,
112
+ onClick: J,
113
+ endIcon: /* @__PURE__ */ t(de, {}),
114
+ sx: {
115
+ display: "flex",
116
+ alignItems: "center",
117
+ gap: 1,
118
+ px: 2,
119
+ py: 1,
120
+ borderRadius: 1,
121
+ textTransform: "none",
122
+ color: "text.primary",
123
+ "&:hover": {
124
+ backgroundColor: "action.hover"
125
+ }
126
+ },
127
+ "data-testid": "org-switch-button",
128
+ children: [
129
+ /* @__PURE__ */ t(
130
+ S,
131
+ {
132
+ sx: {
133
+ width: 24,
134
+ height: 24,
135
+ fontSize: 12,
136
+ bgcolor: "primary.main"
137
+ },
138
+ children: d.name?.[0]
139
+ }
140
+ ),
141
+ /* @__PURE__ */ t(s, { variant: "body2", sx: { fontWeight: 500 }, children: d.name })
142
+ ]
143
+ }
144
+ ),
145
+ /* @__PURE__ */ i(
146
+ ae,
147
+ {
148
+ anchorEl: w,
149
+ open: x,
150
+ onClose: f,
151
+ anchorOrigin: {
152
+ vertical: "bottom",
153
+ horizontal: "left"
154
+ },
155
+ transformOrigin: {
156
+ vertical: "top",
157
+ horizontal: "left"
158
+ },
159
+ PaperProps: {
160
+ sx: {
161
+ width: 340,
162
+ maxHeight: 480,
163
+ overflow: "visible",
164
+ mt: 0.5,
165
+ borderRadius: 2,
166
+ boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.08)",
167
+ border: (e) => `1px solid ${e.palette.divider}`
168
+ }
169
+ },
170
+ MenuListProps: {
171
+ sx: { py: 0 }
172
+ },
173
+ children: [
174
+ /* @__PURE__ */ t(r, { sx: { p: 1.5, pb: 1 }, children: /* @__PURE__ */ t(
175
+ le,
176
+ {
177
+ fullWidth: !0,
178
+ size: "small",
179
+ placeholder: l("search"),
180
+ value: m,
181
+ onChange: (e) => I(e.target.value),
182
+ InputProps: {
183
+ startAdornment: /* @__PURE__ */ t(ce, { position: "start", children: /* @__PURE__ */ t(pe, { fontSize: "small", color: "action" }) })
184
+ },
185
+ onClick: (e) => e.stopPropagation(),
186
+ onKeyDown: (e) => e.stopPropagation(),
187
+ sx: {
188
+ "& .MuiOutlinedInput-root": {
189
+ borderRadius: 1
190
+ }
191
+ }
192
+ }
193
+ ) }),
194
+ /* @__PURE__ */ t(r, { sx: { px: 2, pb: 1 }, children: /* @__PURE__ */ t(
195
+ s,
196
+ {
197
+ variant: "subtitle2",
198
+ color: "text.secondary",
199
+ sx: {
200
+ fontSize: 11,
201
+ fontWeight: 600,
202
+ textTransform: "uppercase",
203
+ letterSpacing: 0.5
204
+ },
205
+ children: l("orgs")
206
+ }
207
+ ) }),
208
+ /* @__PURE__ */ t(r, { sx: { maxHeight: 240, overflow: "auto" }, onScroll: G, children: p.length > 0 ? /* @__PURE__ */ t(Y, { children: p.map((e, o) => {
209
+ const c = o === p.length - 1;
210
+ return /* @__PURE__ */ i(r, { children: [
211
+ Q(e),
212
+ c && T && /* @__PURE__ */ t(
213
+ r,
214
+ {
215
+ sx: {
216
+ display: "flex",
217
+ justifyContent: "center",
218
+ py: 1,
219
+ color: "text.secondary",
220
+ fontSize: "0.875rem"
221
+ },
222
+ children: z ? l("loadingMore") : ""
223
+ }
224
+ )
225
+ ] }, e.id);
226
+ }) }) : /* @__PURE__ */ t(r, { sx: { px: 2, py: 3, textAlign: "center" }, children: /* @__PURE__ */ t(s, { variant: "body2", color: "text.secondary", children: l("myJoinedEmpty") }) }) }),
227
+ /* @__PURE__ */ t(W, {}),
228
+ /* @__PURE__ */ i(
229
+ L,
230
+ {
231
+ onClick: Z,
232
+ sx: {
233
+ py: 1.5,
234
+ px: 2,
235
+ "&:hover": {
236
+ backgroundColor: "action.hover"
237
+ }
238
+ },
239
+ children: [
240
+ /* @__PURE__ */ t(R, { sx: { minWidth: 40 }, children: /* @__PURE__ */ t(
241
+ S,
242
+ {
243
+ sx: {
244
+ width: 28,
245
+ height: 28,
246
+ bgcolor: "success.main",
247
+ color: "success.contrastText"
248
+ },
249
+ children: /* @__PURE__ */ t(he, { fontSize: "small" })
250
+ }
251
+ ) }),
252
+ /* @__PURE__ */ t(
253
+ D,
254
+ {
255
+ primary: /* @__PURE__ */ t(s, { variant: "body2", sx: { fontWeight: 500 }, children: l("createNew") })
256
+ }
257
+ )
258
+ ]
259
+ }
260
+ ),
261
+ /* @__PURE__ */ t(W, {}),
262
+ /* @__PURE__ */ t(r, { sx: { p: 1.5 }, children: /* @__PURE__ */ t(
263
+ P,
264
+ {
265
+ onClick: M,
266
+ variant: "text",
267
+ size: "small",
268
+ endIcon: /* @__PURE__ */ t(me, { fontSize: "small" }),
269
+ sx: {
270
+ color: "primary.main",
271
+ fontWeight: 500,
272
+ p: 0,
273
+ fontSize: 14,
274
+ minWidth: "auto",
275
+ "&:hover": {
276
+ backgroundColor: "transparent",
277
+ textDecoration: "underline"
278
+ }
279
+ },
280
+ children: l("viewAll")
281
+ }
282
+ ) })
283
+ ]
284
+ }
285
+ ),
286
+ N && /* @__PURE__ */ t(fe, { onSuccess: M, onCancel: () => u(!1), locale: h })
287
+ ] });
288
+ }
289
+ be.propTypes = {
290
+ session: A.object.isRequired,
291
+ locale: A.string
292
+ };
293
+ export {
294
+ be as default
295
+ };
@@ -0,0 +1,54 @@
1
+ export default translations;
2
+ declare namespace translations {
3
+ namespace en {
4
+ let search: string;
5
+ let orgs: string;
6
+ let loadingMore: string;
7
+ let myJoinedEmpty: string;
8
+ let createNew: string;
9
+ let viewAll: string;
10
+ let nameEmpty: string;
11
+ let nameTooLong: string;
12
+ let descriptionTooLong: string;
13
+ let cancel: string;
14
+ let create: string;
15
+ namespace mutate {
16
+ let title: string;
17
+ let name: string;
18
+ let description: string;
19
+ }
20
+ }
21
+ namespace zh {
22
+ let search_1: string;
23
+ export { search_1 as search };
24
+ let orgs_1: string;
25
+ export { orgs_1 as orgs };
26
+ let loadingMore_1: string;
27
+ export { loadingMore_1 as loadingMore };
28
+ let myJoinedEmpty_1: string;
29
+ export { myJoinedEmpty_1 as myJoinedEmpty };
30
+ let createNew_1: string;
31
+ export { createNew_1 as createNew };
32
+ let viewAll_1: string;
33
+ export { viewAll_1 as viewAll };
34
+ let nameEmpty_1: string;
35
+ export { nameEmpty_1 as nameEmpty };
36
+ let nameTooLong_1: string;
37
+ export { nameTooLong_1 as nameTooLong };
38
+ let descriptionTooLong_1: string;
39
+ export { descriptionTooLong_1 as descriptionTooLong };
40
+ let cancel_1: string;
41
+ export { cancel_1 as cancel };
42
+ let create_1: string;
43
+ export { create_1 as create };
44
+ export namespace mutate_1 {
45
+ let title_1: string;
46
+ export { title_1 as title };
47
+ let name_1: string;
48
+ export { name_1 as name };
49
+ let description_1: string;
50
+ export { description_1 as description };
51
+ }
52
+ export { mutate_1 as mutate };
53
+ }
54
+ }
@@ -0,0 +1,41 @@
1
+ const e = {
2
+ en: {
3
+ search: "Search",
4
+ orgs: "Organizations",
5
+ loadingMore: "Loading more",
6
+ myJoinedEmpty: "You have not joined any organizations yet",
7
+ createNew: "Create New Organization",
8
+ viewAll: "View All Organizations",
9
+ nameEmpty: "Name cannot be empty",
10
+ nameTooLong: "Name must be less than {length} characters",
11
+ descriptionTooLong: "Description must be less than {length} characters",
12
+ cancel: "Cancel",
13
+ create: "Create",
14
+ mutate: {
15
+ title: "{mode} Organization",
16
+ name: "Name",
17
+ description: "Description"
18
+ }
19
+ },
20
+ zh: {
21
+ search: "搜索",
22
+ orgs: "组织",
23
+ loadingMore: "加载更多",
24
+ myJoinedEmpty: "您还没有加入任何组织",
25
+ createNew: "创建新组织",
26
+ viewAll: "查看所有组织",
27
+ nameEmpty: "名称不能为空",
28
+ nameTooLong: "名称不能超过{length}个字符",
29
+ descriptionTooLong: "描述不能超过{length}个字符",
30
+ cancel: "取消",
31
+ create: "创建",
32
+ mutate: {
33
+ title: "{mode}组织",
34
+ name: "组织名称",
35
+ description: "组织描述"
36
+ }
37
+ }
38
+ };
39
+ export {
40
+ e as default
41
+ };
@@ -0,0 +1,5 @@
1
+ export default function useOrg(session: any): {
2
+ getOrgs: (this: any, args_0?: any) => Promise<any>;
3
+ createOrg: (this: any, args_0?: any) => Promise<any>;
4
+ getCurrentOrg: (this: any, roleName?: any) => Promise<any>;
5
+ };
@@ -0,0 +1,47 @@
1
+ import { useMemoizedFn as e } from "ahooks";
2
+ import i from "@arcblock/ux/lib/Toast";
3
+ import { client as n } from "../../libs/client.js";
4
+ import { formatAxiosError as m } from "../../UserCenter/libs/utils.js";
5
+ function d(a) {
6
+ const c = e(async ({ search: t, page: r = 1, pageSize: o = 20 }) => {
7
+ try {
8
+ return await n.user.getOrgs({ search: t, page: r, pageSize: o });
9
+ } catch (s) {
10
+ return console.error(s), {
11
+ orgs: [],
12
+ paging: {
13
+ page: r,
14
+ pageSize: o,
15
+ total: 0
16
+ }
17
+ };
18
+ }
19
+ }), u = e(async ({ name: t, description: r }) => {
20
+ try {
21
+ return (await n.user.createOrg({ name: t, description: r })).data;
22
+ } catch (o) {
23
+ return console.error(o), i.error(m(o)), null;
24
+ }
25
+ }), g = e(async (t) => {
26
+ try {
27
+ return await n.user.getOrg(t);
28
+ } catch (r) {
29
+ return a.logout(), console.error(r), null;
30
+ }
31
+ }), l = e(async (t) => {
32
+ try {
33
+ const r = await n.user.getRole(t);
34
+ return r.orgId ? await g(r.orgId) : null;
35
+ } catch (r) {
36
+ return console.error(r), null;
37
+ }
38
+ });
39
+ return {
40
+ getOrgs: c,
41
+ createOrg: u,
42
+ getCurrentOrg: l
43
+ };
44
+ }
45
+ export {
46
+ d as default
47
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "3.1.44",
3
+ "version": "3.1.45",
4
4
  "description": "Some useful front-end web components that can be used in Blocklets.",
5
5
  "keywords": [
6
6
  "react",
@@ -35,9 +35,9 @@
35
35
  "dependencies": {
36
36
  "@abtnode/constant": "^1.16.49-beta-20250823-082650-626c1473",
37
37
  "@abtnode/util": "^1.16.49-beta-20250823-082650-626c1473",
38
- "@arcblock/bridge": "3.1.44",
39
- "@arcblock/icons": "3.1.44",
40
- "@arcblock/react-hooks": "3.1.44",
38
+ "@arcblock/bridge": "3.1.45",
39
+ "@arcblock/icons": "3.1.45",
40
+ "@arcblock/react-hooks": "3.1.45",
41
41
  "@arcblock/ws": "^1.21.3",
42
42
  "@blocklet/constant": "^1.16.49-beta-20250823-082650-626c1473",
43
43
  "@blocklet/did-space-react": "^1.1.16",
@@ -83,7 +83,7 @@
83
83
  "access": "public"
84
84
  },
85
85
  "devDependencies": {
86
- "@arcblock/did-connect-react": "3.1.44",
86
+ "@arcblock/did-connect-react": "3.1.45",
87
87
  "@types/dompurify": "^3.2.0",
88
88
  "@types/ua-parser-js": "^0.7.39",
89
89
  "@types/validator": "^13.15.2",
@@ -91,5 +91,5 @@
91
91
  "jest": "^29.7.0",
92
92
  "unbuild": "^2.0.0"
93
93
  },
94
- "gitHead": "fa84963f32d492f869850195429951e99d9b4df8"
94
+ "gitHead": "6706a870c69720bc0beae69a2c380247d4d0efaa"
95
95
  }
@@ -560,6 +560,7 @@ export default function UserCenter({
560
560
  sx={{
561
561
  flex: '1',
562
562
  order: isMobile ? 2 : 'unset',
563
+ width: !isMobile ? 'calc(100% - 424px)' : 'unset',
563
564
  }}>
564
565
  {userCenterTabs.length > 0 && currentTab ? (
565
566
  <Box
@@ -11,17 +11,29 @@ import LocaleSelector from '@arcblock/ux/lib/Locale/selector';
11
11
  import SessionBlocklet from '@arcblock/ux/lib/SessionBlocklet';
12
12
  import SessionUser from '@arcblock/ux/lib/SessionUser';
13
13
  import { Fragment } from 'react/jsx-runtime';
14
+ import { WELLKNOWN_BLOCKLET_ADMIN_PATH } from '@abtnode/constant';
14
15
 
15
16
  import { filterNavByRole, getLocalizedNavigation } from '../blocklets';
16
17
  import { SessionManagerProps } from '../types';
17
18
  import DomainWarning from './domain-warning';
18
19
  import NotificationAddon from './notification-addon';
20
+ import OrgsSwitch from './org-switch';
19
21
 
20
22
  const hasNotification = () => {
21
23
  const navigations = window?.blocklet?.navigation ?? [];
22
24
  return !!navigations.find((n) => n.id === '/userCenter/notification');
23
25
  };
24
26
 
27
+ const isOrgsEnabled = (blocklet) => {
28
+ const { settings = {} } = blocklet ?? window?.blocklet ?? {};
29
+ return settings?.org?.enabled || false;
30
+ };
31
+
32
+ const inDashboard = () => {
33
+ const { pathname = '' } = window.location || {};
34
+ return pathname.startsWith(WELLKNOWN_BLOCKLET_ADMIN_PATH);
35
+ };
36
+
25
37
  // eslint-disable-next-line no-shadow
26
38
  export default function HeaderAddons({
27
39
  formattedBlocklet,
@@ -86,6 +98,11 @@ export default function HeaderAddons({
86
98
  );
87
99
  }
88
100
 
101
+ // 在最前面添加 orgs switch, 在 Dashboard 中不显示
102
+ if (!inDashboard() && isOrgsEnabled(formattedBlocklet) && sessionCtx?.session?.user) {
103
+ addonsArray.unshift(<OrgsSwitch key="orgs-switch" session={sessionCtx.session} locale={locale} />);
104
+ }
105
+
89
106
  if (typeof addons === 'function') {
90
107
  addonsArray = addons(addonsArray) || [];
91
108
  }
@@ -0,0 +1,147 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
2
+ import { useState } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { useReactive, useMemoizedFn } from 'ahooks';
5
+ import noop from 'lodash/noop';
6
+ import Dialog from '@arcblock/ux/lib/Dialog';
7
+ import Spinner from '@mui/material/CircularProgress';
8
+ import DialogContentText from '@mui/material/DialogContentText';
9
+ import Typography from '@mui/material/Typography';
10
+ import TextField from '@mui/material/TextField';
11
+ import Alert from '@mui/material/Alert';
12
+ import Toast from '@arcblock/ux/lib/Toast';
13
+ import Button from '@arcblock/ux/lib/Button';
14
+ import { translate } from '@arcblock/ux/lib/Locale/util';
15
+
16
+ import { formatAxiosError } from '../../UserCenter/libs/utils';
17
+ import useOrg from './use-org';
18
+ import translations from './locales';
19
+
20
+ export default function CreateOrgDialog({ onSuccess = noop, onCancel = noop, locale = 'en' }) {
21
+ const [loading, setLoading] = useState(false);
22
+ const [error, setError] = useState('');
23
+ const { createOrg } = useOrg();
24
+ const t = useMemoizedFn((key, data = {}) => {
25
+ return translate(translations, key, locale, 'en', data);
26
+ });
27
+
28
+ const form = useReactive({
29
+ name: '',
30
+ description: '',
31
+ });
32
+
33
+ const onSubmit = async () => {
34
+ const _name = form.name.trim();
35
+ if (!_name) {
36
+ setError(t('nameEmpty'));
37
+ return;
38
+ }
39
+
40
+ if (_name.length > 25) {
41
+ setError(t('nameTooLong', { length: 25 }));
42
+ return;
43
+ }
44
+
45
+ const _description = form.description.trim();
46
+
47
+ if (_description.length > 255) {
48
+ setError(t('descriptionTooLong', { length: 25 }));
49
+ return;
50
+ }
51
+
52
+ setError('');
53
+ setLoading(true);
54
+
55
+ try {
56
+ await createOrg({ name: _name, description: _description });
57
+ onSuccess();
58
+ } catch (err) {
59
+ console.error(err);
60
+ const errMsg = formatAxiosError(err);
61
+ setError(errMsg);
62
+ Toast.error(errMsg);
63
+ } finally {
64
+ setLoading(false);
65
+ }
66
+ };
67
+
68
+ const body = (
69
+ <div>
70
+ <Typography component="div" style={{ marginTop: 16 }}>
71
+ <TextField
72
+ label={t('mutate.name')}
73
+ autoComplete="off"
74
+ variant="outlined"
75
+ name="name"
76
+ data-cy="mutate-org-input-name"
77
+ fullWidth
78
+ autoFocus
79
+ value={form.name}
80
+ onChange={(e) => {
81
+ setError('');
82
+ form.name = e.target.value;
83
+ }}
84
+ disabled={loading}
85
+ />
86
+ </Typography>
87
+
88
+ <Typography component="div" style={{ marginTop: 16, marginBottom: 16 }}>
89
+ <TextField
90
+ label={t('mutate.description')}
91
+ autoComplete="off"
92
+ variant="outlined"
93
+ name="description"
94
+ data-cy="mutate-org-input-description"
95
+ fullWidth
96
+ value={form.description}
97
+ onChange={(e) => {
98
+ setError('');
99
+ form.description = e.target.value;
100
+ }}
101
+ disabled={loading}
102
+ multiline
103
+ rows={3}
104
+ />
105
+ </Typography>
106
+ </div>
107
+ );
108
+
109
+ return (
110
+ <Dialog
111
+ title={t('mutate.title', { mode: t('create') })}
112
+ fullWidth
113
+ open
114
+ onClose={onCancel}
115
+ showCloseButton={false}
116
+ actions={
117
+ <>
118
+ <Button onClick={onCancel} color="inherit">
119
+ {t('cancel')}
120
+ </Button>
121
+ <Button
122
+ data-cy="mutate-org-confirm"
123
+ onClick={onSubmit}
124
+ color="primary"
125
+ disabled={loading}
126
+ variant="contained"
127
+ autoFocus>
128
+ {loading && <Spinner size={16} />}
129
+ {t('create')}
130
+ </Button>
131
+ </>
132
+ }>
133
+ <DialogContentText component="div">{body}</DialogContentText>
134
+ {!!error && (
135
+ <Alert severity="error" style={{ width: '100%', margin: 0 }}>
136
+ {error}
137
+ </Alert>
138
+ )}
139
+ </Dialog>
140
+ );
141
+ }
142
+
143
+ CreateOrgDialog.propTypes = {
144
+ onSuccess: PropTypes.func,
145
+ onCancel: PropTypes.func,
146
+ locale: PropTypes.string,
147
+ };