@authhero/react-admin 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/.eslintrc.js +21 -0
  2. package/.vercelignore +4 -0
  3. package/CHANGELOG.md +56 -0
  4. package/LICENSE +21 -0
  5. package/README.md +50 -0
  6. package/index.html +125 -0
  7. package/package.json +61 -0
  8. package/prettier.config.js +1 -0
  9. package/public/favicon.ico +0 -0
  10. package/public/manifest.json +15 -0
  11. package/src/App.spec.tsx +42 -0
  12. package/src/App.tsx +232 -0
  13. package/src/AuthCallback.tsx +138 -0
  14. package/src/Layout.tsx +12 -0
  15. package/src/TenantsApp.tsx +115 -0
  16. package/src/auth0DataProvider.ts +1242 -0
  17. package/src/authProvider.ts +521 -0
  18. package/src/components/CertificateErrorDialog.tsx +116 -0
  19. package/src/components/DomainSelector.tsx +401 -0
  20. package/src/components/TenantAppBar.tsx +83 -0
  21. package/src/components/TenantLayout.tsx +25 -0
  22. package/src/components/TenantsAppBar.tsx +21 -0
  23. package/src/components/TenantsLayout.tsx +28 -0
  24. package/src/components/activity/ActivityDashboard.tsx +381 -0
  25. package/src/components/activity/index.ts +1 -0
  26. package/src/components/branding/BrandingList.tsx +0 -0
  27. package/src/components/branding/BrandingShow.tsx +0 -0
  28. package/src/components/branding/ThemesTab.tsx +286 -0
  29. package/src/components/branding/edit.tsx +149 -0
  30. package/src/components/branding/hooks/useThemesData.ts +123 -0
  31. package/src/components/branding/index.ts +2 -0
  32. package/src/components/branding/list.tsx +12 -0
  33. package/src/components/clients/create.tsx +12 -0
  34. package/src/components/clients/edit.tsx +1285 -0
  35. package/src/components/clients/index.ts +3 -0
  36. package/src/components/clients/list.tsx +37 -0
  37. package/src/components/common/DateAgo.tsx +6 -0
  38. package/src/components/common/JsonOutput.tsx +26 -0
  39. package/src/components/common/index.ts +1 -0
  40. package/src/components/connections/create.tsx +35 -0
  41. package/src/components/connections/edit.tsx +212 -0
  42. package/src/components/connections/index.ts +3 -0
  43. package/src/components/connections/list.tsx +15 -0
  44. package/src/components/custom-domains/create.tsx +26 -0
  45. package/src/components/custom-domains/edit.tsx +101 -0
  46. package/src/components/custom-domains/index.ts +3 -0
  47. package/src/components/custom-domains/list.tsx +16 -0
  48. package/src/components/flows/create.tsx +30 -0
  49. package/src/components/flows/edit.tsx +238 -0
  50. package/src/components/flows/index.ts +3 -0
  51. package/src/components/flows/list.tsx +15 -0
  52. package/src/components/forms/FlowEditor.tsx +1363 -0
  53. package/src/components/forms/NodeEditor.tsx +1119 -0
  54. package/src/components/forms/RichTextEditor.tsx +145 -0
  55. package/src/components/forms/create.tsx +30 -0
  56. package/src/components/forms/edit.tsx +256 -0
  57. package/src/components/forms/index.ts +3 -0
  58. package/src/components/forms/list.tsx +16 -0
  59. package/src/components/hooks/create.tsx +96 -0
  60. package/src/components/hooks/edit.tsx +114 -0
  61. package/src/components/hooks/index.ts +3 -0
  62. package/src/components/hooks/list.tsx +17 -0
  63. package/src/components/listActions/PostListActions.tsx +10 -0
  64. package/src/components/logs/LogIcon.tsx +32 -0
  65. package/src/components/logs/LogShow.tsx +82 -0
  66. package/src/components/logs/LogType.tsx +38 -0
  67. package/src/components/logs/index.ts +4 -0
  68. package/src/components/logs/list.tsx +41 -0
  69. package/src/components/organizations/create.tsx +13 -0
  70. package/src/components/organizations/edit.tsx +682 -0
  71. package/src/components/organizations/index.ts +3 -0
  72. package/src/components/organizations/list.tsx +21 -0
  73. package/src/components/resource-servers/create.tsx +87 -0
  74. package/src/components/resource-servers/edit.tsx +121 -0
  75. package/src/components/resource-servers/index.ts +3 -0
  76. package/src/components/resource-servers/list.tsx +47 -0
  77. package/src/components/roles/create.tsx +12 -0
  78. package/src/components/roles/edit.tsx +426 -0
  79. package/src/components/roles/index.ts +3 -0
  80. package/src/components/roles/list.tsx +24 -0
  81. package/src/components/sessions/edit.tsx +101 -0
  82. package/src/components/sessions/index.ts +3 -0
  83. package/src/components/sessions/list.tsx +20 -0
  84. package/src/components/sessions/show.tsx +113 -0
  85. package/src/components/settings/edit.tsx +236 -0
  86. package/src/components/settings/index.ts +2 -0
  87. package/src/components/settings/list.tsx +14 -0
  88. package/src/components/tenants/create.tsx +20 -0
  89. package/src/components/tenants/edit.tsx +54 -0
  90. package/src/components/tenants/index.ts +2 -0
  91. package/src/components/tenants/list.tsx +67 -0
  92. package/src/components/themes/edit.tsx +200 -0
  93. package/src/components/themes/index.ts +2 -0
  94. package/src/components/themes/list.tsx +12 -0
  95. package/src/components/users/create.tsx +144 -0
  96. package/src/components/users/edit.tsx +1711 -0
  97. package/src/components/users/index.ts +3 -0
  98. package/src/components/users/list.tsx +35 -0
  99. package/src/data.json +121 -0
  100. package/src/dataProvider.ts +97 -0
  101. package/src/index.tsx +106 -0
  102. package/src/lib/logs.ts +21 -0
  103. package/src/types/reactflow.d.ts +86 -0
  104. package/src/utils/domainUtils.ts +169 -0
  105. package/src/utils/tokenUtils.ts +75 -0
  106. package/src/vite-env.d.ts +1 -0
  107. package/tsconfig.json +37 -0
  108. package/tsconfig.node.json +10 -0
  109. package/vercel.json +17 -0
  110. package/vite.config.ts +30 -0
@@ -0,0 +1,3 @@
1
+ export * from "./list";
2
+ export * from "./create";
3
+ export * from "./edit";
@@ -0,0 +1,24 @@
1
+ import { List, Datagrid, TextField, DateField, TextInput } from "react-admin";
2
+ import { PostListActions } from "../listActions/PostListActions";
3
+
4
+ export function RoleList() {
5
+ const filters = [
6
+ <TextInput key="search" label="Search" source="q" alwaysOn />,
7
+ ];
8
+
9
+ return (
10
+ <List
11
+ actions={<PostListActions />}
12
+ filters={filters}
13
+ sort={{ field: "name", order: "ASC" }}
14
+ >
15
+ <Datagrid rowClick="edit" bulkActionButtons={false}>
16
+ <TextField source="id" />
17
+ <TextField source="name" />
18
+ <TextField source="description" />
19
+ <DateField source="created_at" showTime={true} />
20
+ <DateField source="updated_at" showTime={true} />
21
+ </Datagrid>
22
+ </List>
23
+ );
24
+ }
@@ -0,0 +1,101 @@
1
+ import {
2
+ Edit,
3
+ SimpleShowLayout,
4
+ TextField,
5
+ DateField,
6
+ FunctionField,
7
+ ArrayField,
8
+ SingleFieldList,
9
+ ChipField,
10
+ Labeled,
11
+ ReferenceField,
12
+ TabbedForm,
13
+ } from "react-admin";
14
+ import { Stack, Typography, Card, CardContent, Box } from "@mui/material";
15
+ import { JsonOutput } from "../common/JsonOutput";
16
+
17
+ export function SessionEdit() {
18
+ return (
19
+ <Edit>
20
+ <SimpleShowLayout>
21
+ <Stack spacing={2} direction="row" sx={{ mb: 2 }}>
22
+ <Labeled label="Session ID">
23
+ <TextField source="id" />
24
+ </Labeled>
25
+ </Stack>
26
+
27
+ <TabbedForm>
28
+ <TabbedForm.Tab label="Details">
29
+ <Stack spacing={2} direction="row">
30
+ <Labeled label="User ID">
31
+ <ReferenceField reference="users" source="user_id" link="show">
32
+ <TextField source="email" />
33
+ </ReferenceField>
34
+ </Labeled>
35
+ </Stack>
36
+
37
+ <Stack spacing={2} direction="row">
38
+ <Labeled label="Created At">
39
+ <DateField source="created_at" showTime />
40
+ </Labeled>
41
+ <Labeled label="Last Used At">
42
+ <DateField source="used_at" showTime emptyText="-" />
43
+ </Labeled>
44
+ </Stack>
45
+
46
+ <Stack spacing={2} direction="row">
47
+ <Labeled label="Expires At">
48
+ <DateField source="expires_at" showTime emptyText="-" />
49
+ </Labeled>
50
+ <Labeled label="Idle Expires At">
51
+ <DateField source="idle_expires_at" showTime emptyText="-" />
52
+ </Labeled>
53
+ </Stack>
54
+
55
+ <Labeled label="Status">
56
+ <FunctionField
57
+ render={(record) => (record.revoked_at ? "Revoked" : "Active")}
58
+ />
59
+ </Labeled>
60
+
61
+ <Typography variant="h6">Client Applications</Typography>
62
+ <ArrayField source="clients">
63
+ <SingleFieldList>
64
+ <ChipField source="" />
65
+ </SingleFieldList>
66
+ </ArrayField>
67
+ </TabbedForm.Tab>
68
+
69
+ <TabbedForm.Tab label="Device">
70
+ <Stack spacing={2}>
71
+ <Labeled label="Last IP Address">
72
+ <TextField source="device.last_ip" emptyText="-" />
73
+ </Labeled>
74
+ <Labeled label="Last User Agent">
75
+ <TextField source="device.last_user_agent" emptyText="-" />
76
+ </Labeled>
77
+ <Labeled label="Initial IP Address">
78
+ <TextField source="device.initial_ip" emptyText="-" />
79
+ </Labeled>
80
+ <Labeled label="Initial User Agent">
81
+ <TextField source="device.initial_user_agent" emptyText="-" />
82
+ </Labeled>
83
+ </Stack>
84
+ </TabbedForm.Tab>
85
+
86
+ <TabbedForm.Tab label="Raw">
87
+ <Box sx={{ mt: 1 }}>
88
+ <Card variant="outlined">
89
+ <CardContent>
90
+ <FunctionField
91
+ render={(record) => <JsonOutput data={record} />}
92
+ />
93
+ </CardContent>
94
+ </Card>
95
+ </Box>
96
+ </TabbedForm.Tab>
97
+ </TabbedForm>
98
+ </SimpleShowLayout>
99
+ </Edit>
100
+ );
101
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./list";
2
+ export * from "./edit";
3
+ export * from "./show";
@@ -0,0 +1,20 @@
1
+ import { List, Datagrid, TextField, TextInput } from "react-admin";
2
+ import { PostListActions } from "../listActions/PostListActions";
3
+
4
+ export function SessionsList() {
5
+ const postFilters = [
6
+ <TextInput key="search" label="Search" source="q" alwaysOn />,
7
+ ];
8
+
9
+ return (
10
+ <List
11
+ actions={<PostListActions />}
12
+ filters={postFilters}
13
+ sort={{ field: "date", order: "DESC" }}
14
+ >
15
+ <Datagrid bulkActionButtons={false} rowClick="show">
16
+ <TextField source="description" />
17
+ </Datagrid>
18
+ </List>
19
+ );
20
+ }
@@ -0,0 +1,113 @@
1
+ import {
2
+ Show,
3
+ SimpleShowLayout,
4
+ TextField,
5
+ DateField,
6
+ FunctionField,
7
+ ArrayField,
8
+ SingleFieldList,
9
+ ChipField,
10
+ Labeled,
11
+ ReferenceField,
12
+ TabbedShowLayout,
13
+ } from "react-admin";
14
+ import { Stack, Typography, Card, CardContent, Box } from "@mui/material";
15
+ import { JsonOutput } from "../common/JsonOutput";
16
+
17
+ export function SessionShow() {
18
+ return (
19
+ <Show>
20
+ <SimpleShowLayout>
21
+ <Stack spacing={2} direction="row" sx={{ mb: 2 }}>
22
+ <Labeled label="Session ID">
23
+ <TextField source="id" />
24
+ </Labeled>
25
+ </Stack>
26
+
27
+ <TabbedShowLayout>
28
+ <TabbedShowLayout.Tab label="Details">
29
+ <Stack spacing={2} direction="row">
30
+ <Labeled label="User ID">
31
+ <ReferenceField reference="users" source="user_id" link="show">
32
+ <TextField source="email" />
33
+ </ReferenceField>
34
+ </Labeled>
35
+ </Stack>
36
+
37
+ <Stack spacing={2} direction="row">
38
+ <Labeled label="Created At">
39
+ <DateField source="created_at" showTime />
40
+ </Labeled>
41
+ <Labeled label="Last Used At">
42
+ <DateField source="used_at" showTime emptyText="-" />
43
+ </Labeled>
44
+ </Stack>
45
+
46
+ <Stack spacing={2} direction="row">
47
+ <Labeled label="Expires At">
48
+ <DateField source="expires_at" showTime emptyText="-" />
49
+ </Labeled>
50
+ <Labeled label="Idle Expires At">
51
+ <DateField source="idle_expires_at" showTime emptyText="-" />
52
+ </Labeled>
53
+ </Stack>
54
+
55
+ <Labeled label="Status">
56
+ <FunctionField
57
+ render={(record) => (record.revoked_at ? "Revoked" : "Active")}
58
+ />
59
+ </Labeled>
60
+
61
+ <Typography variant="h6">Client Applications</Typography>
62
+ <ArrayField source="clients">
63
+ <SingleFieldList>
64
+ <ChipField source="" />
65
+ </SingleFieldList>
66
+ </ArrayField>
67
+ </TabbedShowLayout.Tab>
68
+
69
+ <TabbedShowLayout.Tab label="Device">
70
+ <Box sx={{ mt: 1 }}>
71
+ <Card variant="outlined" sx={{ mb: 2 }}>
72
+ <CardContent>
73
+ <Stack spacing={2}>
74
+ <Labeled label="Last IP Address">
75
+ <TextField source="device.last_ip" emptyText="-" />
76
+ </Labeled>
77
+ <Labeled label="Last User Agent">
78
+ <TextField
79
+ source="device.last_user_agent"
80
+ emptyText="-"
81
+ />
82
+ </Labeled>
83
+ <Labeled label="Initial IP Address">
84
+ <TextField source="device.initial_ip" emptyText="-" />
85
+ </Labeled>
86
+ <Labeled label="Initial User Agent">
87
+ <TextField
88
+ source="device.initial_user_agent"
89
+ emptyText="-"
90
+ />
91
+ </Labeled>
92
+ </Stack>
93
+ </CardContent>
94
+ </Card>
95
+ </Box>
96
+ </TabbedShowLayout.Tab>
97
+
98
+ <TabbedShowLayout.Tab label="Raw">
99
+ <Box sx={{ mt: 1 }}>
100
+ <Card variant="outlined">
101
+ <CardContent>
102
+ <FunctionField
103
+ render={(record) => <JsonOutput data={record} />}
104
+ />
105
+ </CardContent>
106
+ </Card>
107
+ </Box>
108
+ </TabbedShowLayout.Tab>
109
+ </TabbedShowLayout>
110
+ </SimpleShowLayout>
111
+ </Show>
112
+ );
113
+ }
@@ -0,0 +1,236 @@
1
+ import {
2
+ Edit,
3
+ TextInput,
4
+ TabbedForm,
5
+ BooleanInput,
6
+ NumberInput,
7
+ ArrayInput,
8
+ SimpleFormIterator,
9
+ } from "react-admin";
10
+ import { Stack } from "@mui/material";
11
+
12
+ export function SettingsEdit() {
13
+ return (
14
+ <Edit>
15
+ <TabbedForm>
16
+ <TabbedForm.Tab label="General">
17
+ <Stack spacing={2}>
18
+ <TextInput source="friendly_name" label="Friendly Name" fullWidth />
19
+ <TextInput source="picture_url" label="Picture URL" fullWidth />
20
+ <TextInput source="support_email" label="Support Email" fullWidth />
21
+ <TextInput source="support_url" label="Support URL" fullWidth />
22
+ <TextInput
23
+ source="default_directory"
24
+ label="Default Directory"
25
+ fullWidth
26
+ />
27
+ <TextInput
28
+ source="default_audience"
29
+ label="Default Audience"
30
+ fullWidth
31
+ />
32
+ <TextInput
33
+ source="default_organization"
34
+ label="Default Organization"
35
+ fullWidth
36
+ />
37
+ <TextInput
38
+ source="default_redirection_uri"
39
+ label="Default Redirection URI"
40
+ fullWidth
41
+ />
42
+ </Stack>
43
+ </TabbedForm.Tab>
44
+
45
+ <TabbedForm.Tab label="Session">
46
+ <Stack spacing={2}>
47
+ <NumberInput
48
+ source="idle_session_lifetime"
49
+ label="Idle Session Lifetime (hours)"
50
+ helperText="Hours before an idle session expires"
51
+ />
52
+ <NumberInput
53
+ source="session_lifetime"
54
+ label="Session Lifetime (hours)"
55
+ helperText="Maximum session duration in hours"
56
+ />
57
+ <TextInput
58
+ source="session_cookie.mode"
59
+ label="Session Cookie Mode"
60
+ helperText="persistent or non-persistent"
61
+ />
62
+ </Stack>
63
+ </TabbedForm.Tab>
64
+
65
+ <TabbedForm.Tab label="Sessions Management">
66
+ <BooleanInput
67
+ source="sessions.oidc_logout_prompt_enabled"
68
+ label="Enable OIDC Logout Prompt"
69
+ />
70
+ </TabbedForm.Tab>
71
+
72
+ <TabbedForm.Tab label="Localization">
73
+ <ArrayInput source="enabled_locales" label="Enabled Locales">
74
+ <SimpleFormIterator inline>
75
+ <TextInput source="" label="" helperText="e.g., en, es, fr" />
76
+ </SimpleFormIterator>
77
+ </ArrayInput>
78
+ </TabbedForm.Tab>
79
+
80
+ <TabbedForm.Tab label="Error Page">
81
+ <Stack spacing={2}>
82
+ <TextInput
83
+ source="error_page.url"
84
+ label="Error Page URL"
85
+ fullWidth
86
+ />
87
+ <TextInput
88
+ source="error_page.html"
89
+ label="Error Page HTML"
90
+ multiline
91
+ rows={10}
92
+ fullWidth
93
+ />
94
+ <BooleanInput
95
+ source="error_page.show_log_link"
96
+ label="Show Log Link"
97
+ />
98
+ </Stack>
99
+ </TabbedForm.Tab>
100
+
101
+ <TabbedForm.Tab label="Change Password">
102
+ <Stack spacing={2}>
103
+ <BooleanInput source="change_password.enabled" label="Enabled" />
104
+ <TextInput
105
+ source="change_password.html"
106
+ label="Custom HTML"
107
+ multiline
108
+ rows={10}
109
+ fullWidth
110
+ />
111
+ </Stack>
112
+ </TabbedForm.Tab>
113
+
114
+ <TabbedForm.Tab label="Guardian MFA">
115
+ <Stack spacing={2}>
116
+ <BooleanInput source="guardian_mfa_page.enabled" label="Enabled" />
117
+ <TextInput
118
+ source="guardian_mfa_page.html"
119
+ label="Custom HTML"
120
+ multiline
121
+ rows={10}
122
+ fullWidth
123
+ />
124
+ </Stack>
125
+ </TabbedForm.Tab>
126
+
127
+ <TabbedForm.Tab label="Feature Flags">
128
+ <Stack spacing={2}>
129
+ <BooleanInput
130
+ source="flags.allow_legacy_delegation_grant_types"
131
+ label="Allow Legacy Delegation Grant Types"
132
+ />
133
+ <BooleanInput
134
+ source="flags.allow_legacy_ro_grant_types"
135
+ label="Allow Legacy RO Grant Types"
136
+ />
137
+ <BooleanInput
138
+ source="flags.allow_legacy_tokeninfo_endpoint"
139
+ label="Allow Legacy Token Info Endpoint"
140
+ />
141
+ <BooleanInput
142
+ source="flags.disable_clickjack_protection_headers"
143
+ label="Disable Clickjack Protection Headers"
144
+ />
145
+ <BooleanInput
146
+ source="flags.enable_apis_section"
147
+ label="Enable APIs Section"
148
+ />
149
+ <BooleanInput
150
+ source="flags.enable_client_connections"
151
+ label="Enable Client Connections"
152
+ />
153
+ <BooleanInput
154
+ source="flags.enable_custom_domain_in_emails"
155
+ label="Enable Custom Domain in Emails"
156
+ />
157
+ <BooleanInput
158
+ source="flags.enable_dynamic_client_registration"
159
+ label="Enable Dynamic Client Registration"
160
+ />
161
+ <BooleanInput
162
+ source="flags.enable_idtoken_api2"
163
+ label="Enable ID Token API v2"
164
+ />
165
+ <BooleanInput
166
+ source="flags.enable_legacy_logs_search_v2"
167
+ label="Enable Legacy Logs Search v2"
168
+ />
169
+ <BooleanInput
170
+ source="flags.enable_legacy_profile"
171
+ label="Enable Legacy Profile"
172
+ />
173
+ <BooleanInput
174
+ source="flags.enable_pipeline2"
175
+ label="Enable Pipeline 2"
176
+ />
177
+ <BooleanInput
178
+ source="flags.enable_public_signup_user_exists_error"
179
+ label="Enable Public Signup User Exists Error"
180
+ />
181
+ <BooleanInput
182
+ source="flags.use_scope_descriptions_for_consent"
183
+ label="Use Scope Descriptions for Consent"
184
+ />
185
+ <BooleanInput
186
+ source="flags.disable_management_api_sms_obfuscation"
187
+ label="Disable Management API SMS Obfuscation"
188
+ />
189
+ <BooleanInput
190
+ source="flags.enable_adfs_waad_email_verification"
191
+ label="Enable ADFS WAAD Email Verification"
192
+ />
193
+ <BooleanInput
194
+ source="flags.revoke_refresh_token_grant"
195
+ label="Revoke Refresh Token Grant"
196
+ />
197
+ <BooleanInput
198
+ source="flags.dashboard_log_streams_next"
199
+ label="Dashboard Log Streams Next"
200
+ />
201
+ <BooleanInput
202
+ source="flags.dashboard_insights_view"
203
+ label="Dashboard Insights View"
204
+ />
205
+ <BooleanInput
206
+ source="flags.disable_fields_map_fix"
207
+ label="Disable Fields Map Fix"
208
+ />
209
+ <BooleanInput
210
+ source="flags.mfa_show_factor_list_on_enrollment"
211
+ label="MFA Show Factor List on Enrollment"
212
+ />
213
+ </Stack>
214
+ </TabbedForm.Tab>
215
+
216
+ <TabbedForm.Tab label="Advanced">
217
+ <Stack spacing={2}>
218
+ <TextInput
219
+ source="sandbox_version"
220
+ label="Sandbox Version"
221
+ fullWidth
222
+ />
223
+ <ArrayInput
224
+ source="sandbox_versions_available"
225
+ label="Available Sandbox Versions"
226
+ >
227
+ <SimpleFormIterator inline>
228
+ <TextInput source="" label="" />
229
+ </SimpleFormIterator>
230
+ </ArrayInput>
231
+ </Stack>
232
+ </TabbedForm.Tab>
233
+ </TabbedForm>
234
+ </Edit>
235
+ );
236
+ }
@@ -0,0 +1,2 @@
1
+ export { SettingsList } from "./list";
2
+ export { SettingsEdit } from "./edit";
@@ -0,0 +1,14 @@
1
+ import { useEffect } from "react";
2
+ import { useRedirect, useBasename } from "react-admin";
3
+
4
+ export function SettingsList() {
5
+ const redirect = useRedirect();
6
+ const basename = useBasename();
7
+
8
+ useEffect(() => {
9
+ // For singleton resources, redirect to edit with "settings" as the ID
10
+ redirect(`${basename}/settings/settings`);
11
+ }, [redirect, basename]);
12
+
13
+ return null;
14
+ }
@@ -0,0 +1,20 @@
1
+ import { Create, SimpleForm, TextInput, required } from "react-admin";
2
+
3
+ export function TenantsCreate() {
4
+ return (
5
+ <Create>
6
+ <SimpleForm>
7
+ <TextInput source="id" />
8
+ <TextInput
9
+ source="friendly_name"
10
+ label="Name"
11
+ validate={[required()]}
12
+ />
13
+ <TextInput source="audience" validate={[required()]} />
14
+ <TextInput source="sender_email" validate={[required()]} />
15
+ <TextInput source="sender_name" validate={[required()]} />
16
+ <TextInput source="support_url" label="Support Url" />
17
+ </SimpleForm>
18
+ </Create>
19
+ );
20
+ }
@@ -0,0 +1,54 @@
1
+ import {
2
+ DateField,
3
+ Edit,
4
+ FieldTitle,
5
+ Labeled,
6
+ SelectInput,
7
+ TabbedForm,
8
+ TextInput,
9
+ } from "react-admin";
10
+ import { ColorInput } from "react-admin-color-picker";
11
+
12
+ export function TenantsEdit() {
13
+ return (
14
+ <Edit>
15
+ <TabbedForm>
16
+ <TabbedForm.Tab label="Info">
17
+ <TextInput source="id" />
18
+ <TextInput source="name" />
19
+ <TextInput source="audience" label="Audience" />
20
+ <TextInput source="support_url" label="Support Url" />
21
+ <Labeled label={<FieldTitle source="created_at" />}>
22
+ <DateField source="created_at" showTime={true} />
23
+ </Labeled>
24
+ <Labeled label={<FieldTitle source="updated_at" />}>
25
+ <DateField source="updated_at" showTime={true} />
26
+ </Labeled>
27
+ </TabbedForm.Tab>
28
+ <TabbedForm.Tab label="Communication">
29
+ <TextInput source="sender_email" />
30
+ <TextInput source="sender_name" />
31
+ </TabbedForm.Tab>
32
+ <TabbedForm.Tab label="Style">
33
+ <SelectInput
34
+ source="language"
35
+ label="Languages"
36
+ choices={[
37
+ { id: "en", name: "English" },
38
+ { id: "nb", name: "Norwegian" },
39
+ { id: "sv", name: "Swedish" },
40
+ { id: "it", name: "Italian" },
41
+ { id: "pl", name: "Polish" },
42
+ { id: "da", name: "Danish" },
43
+ { id: "cs", name: "Czech" },
44
+ { id: "fi", name: "Finnish" },
45
+ ]}
46
+ />
47
+ <ColorInput source="primary_color" label="Primary Color" />
48
+ <ColorInput source="secondary_color" label="Secondary Color" />
49
+ <TextInput source="logo" label="Logo" />
50
+ </TabbedForm.Tab>
51
+ </TabbedForm>
52
+ </Edit>
53
+ );
54
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./create";
2
+ export * from "./list";
@@ -0,0 +1,67 @@
1
+ import {
2
+ List,
3
+ Datagrid,
4
+ TextField,
5
+ DateField,
6
+ UrlField,
7
+ SimpleList,
8
+ TextInput,
9
+ } from "react-admin";
10
+ import { useMediaQuery } from "@mui/material";
11
+ import { PostListActions } from "../listActions/PostListActions";
12
+
13
+ // Use the standard List component but with proper logging
14
+ export function TenantsList(props) {
15
+ const isSmall = useMediaQuery((theme: any) => theme.breakpoints.down("sm"));
16
+
17
+ // Handle navigation to tenant-specific view
18
+ const handleTenantNavigation = (tenantId: string) => {
19
+ // Navigate to the tenant-specific view by changing the full URL
20
+ // This will trigger the root router to switch to the tenant-specific BrowserRouter
21
+ window.location.href = `/${tenantId}`;
22
+ };
23
+
24
+ // The standard filters
25
+ const postFilters = [
26
+ <TextInput key="search" label="Search" source="q" alwaysOn />,
27
+ ];
28
+
29
+ return (
30
+ <List
31
+ resource={props.resource || "tenants"}
32
+ actions={<PostListActions />}
33
+ filters={postFilters}
34
+ >
35
+ {isSmall ? (
36
+ <SimpleList
37
+ primaryText={(record) => record.friendly_name}
38
+ secondaryText={(record) => record.id}
39
+ linkType={false}
40
+ onClick={(record: any) => {
41
+ handleTenantNavigation(String(record.id));
42
+ }}
43
+ />
44
+ ) : (
45
+ <Datagrid
46
+ rowClick={(_id, _resource, record) => {
47
+ handleTenantNavigation(String(record.id));
48
+ return "";
49
+ }}
50
+ bulkActionButtons={false}
51
+ rowSx={(tenant) => ({
52
+ ...(tenant.id === "DEFAULT_SETTINGS" && {
53
+ backgroundColor: "#f0f0f0",
54
+ }),
55
+ })}
56
+ >
57
+ <TextField source="friendly_name" label="Name" />
58
+ <UrlField source="id" />
59
+ <TextField source="audience" />
60
+ <DateField source="created_at" showTime={true} />
61
+ <DateField source="updated_at" showTime={true} />
62
+ <TextField source="support_url" label="Support Url" />
63
+ </Datagrid>
64
+ )}
65
+ </List>
66
+ );
67
+ }