Skip to content

Commit f5b15aa

Browse files
committed
Add support for admin configuration through props instead of elements
1 parent 5dabdd5 commit f5b15aa

25 files changed

+925
-43
lines changed

examples/with-config/README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# with-config
2+
3+
## Installation
4+
5+
Install the application dependencies by running:
6+
7+
```sh
8+
npm install
9+
# or
10+
yarn install
11+
```
12+
13+
## Development
14+
15+
Start the application in development mode by running:
16+
17+
```sh
18+
npm run dev
19+
# or
20+
yarn dev
21+
```
22+
23+
## Production
24+
25+
Build the application in production mode by running:
26+
27+
```sh
28+
npm run build
29+
# or
30+
yarn build
31+
```
32+
33+
## DataProvider
34+
35+
The included data provider use [FakeREST](https://github.com/marmelab/fakerest) to simulate a backend.
36+
You'll find a `data.json` file in the `src` directory that includes some fake data for testing purposes.
37+
38+
It includes two resources, posts and comments.
39+
Posts have the following properties: `id`, `title` and `content`.
40+
Comments have the following properties: `id`, `post_id` and `content`.
41+
42+
## Authentication
43+
44+
The included auth provider should only be used for development and test purposes.
45+
You'll find a `users.json` file in the `src` directory that includes the users you can use.
46+
47+
You can sign in to the application with the following usernames and password:
48+
- janedoe / password
49+
- johndoe / password
50+

examples/with-config/index.html

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta
6+
name="viewport"
7+
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
8+
/>
9+
<meta name="theme-color" content="#000000" />
10+
<link rel="manifest" href="./manifest.json" />
11+
<link rel="shortcut icon" href="./favicon.ico" />
12+
<title>with-config</title>
13+
<style>
14+
body {
15+
margin: 0;
16+
padding: 0;
17+
font-family: sans-serif;
18+
}
19+
20+
.loader-container {
21+
display: flex;
22+
align-items: center;
23+
justify-content: center;
24+
flex-direction: column;
25+
position: absolute;
26+
top: 0;
27+
bottom: 0;
28+
left: 0;
29+
right: 0;
30+
background-color: #fafafa;
31+
}
32+
33+
/* CSS Spinner from https://projects.lukehaas.me/css-loaders/ */
34+
35+
.loader,
36+
.loader:before,
37+
.loader:after {
38+
border-radius: 50%;
39+
}
40+
41+
.loader {
42+
color: #283593;
43+
font-size: 11px;
44+
text-indent: -99999em;
45+
margin: 55px auto;
46+
position: relative;
47+
width: 10em;
48+
height: 10em;
49+
box-shadow: inset 0 0 0 1em;
50+
-webkit-transform: translateZ(0);
51+
-ms-transform: translateZ(0);
52+
transform: translateZ(0);
53+
}
54+
55+
.loader:before,
56+
.loader:after {
57+
position: absolute;
58+
content: '';
59+
}
60+
61+
.loader:before {
62+
width: 5.2em;
63+
height: 10.2em;
64+
background: #fafafa;
65+
border-radius: 10.2em 0 0 10.2em;
66+
top: -0.1em;
67+
left: -0.1em;
68+
-webkit-transform-origin: 5.2em 5.1em;
69+
transform-origin: 5.2em 5.1em;
70+
-webkit-animation: load2 2s infinite ease 1.5s;
71+
animation: load2 2s infinite ease 1.5s;
72+
}
73+
74+
.loader:after {
75+
width: 5.2em;
76+
height: 10.2em;
77+
background: #fafafa;
78+
border-radius: 0 10.2em 10.2em 0;
79+
top: -0.1em;
80+
left: 5.1em;
81+
-webkit-transform-origin: 0px 5.1em;
82+
transform-origin: 0px 5.1em;
83+
-webkit-animation: load2 2s infinite ease;
84+
animation: load2 2s infinite ease;
85+
}
86+
87+
@-webkit-keyframes load2 {
88+
0% {
89+
-webkit-transform: rotate(0deg);
90+
transform: rotate(0deg);
91+
}
92+
100% {
93+
-webkit-transform: rotate(360deg);
94+
transform: rotate(360deg);
95+
}
96+
}
97+
98+
@keyframes load2 {
99+
0% {
100+
-webkit-transform: rotate(0deg);
101+
transform: rotate(0deg);
102+
}
103+
100% {
104+
-webkit-transform: rotate(360deg);
105+
transform: rotate(360deg);
106+
}
107+
}
108+
</style>
109+
<link rel="preconnect" href="https://fonts.gstatic.com" />
110+
<link
111+
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
112+
rel="stylesheet"
113+
/>
114+
</head>
115+
116+
<body>
117+
<noscript> You need to enable JavaScript to run this app. </noscript>
118+
<div id="root">
119+
<div class="loader-container">
120+
<div class="loader">Loading...</div>
121+
</div>
122+
</div>
123+
</body>
124+
<script type="module" src="/src/index.tsx"></script>
125+
</html>

examples/with-config/package.json

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "with-config",
3+
"private": true,
4+
"scripts": {
5+
"dev": "vite",
6+
"build": "vite build",
7+
"serve": "vite preview",
8+
"type-check": "tsc --noEmit"
9+
},
10+
"dependencies": {
11+
"ra-data-fakerest": "^4.9.2",
12+
"react": "^18.2.0",
13+
"react-admin": "^4.9.0",
14+
"react-dom": "^18.2.0"
15+
},
16+
"devDependencies": {
17+
"@types/node": "^18.16.1",
18+
"@types/react": "^18.0.22",
19+
"@types/react-dom": "^18.0.7",
20+
"@vitejs/plugin-react": "^2.2.0",
21+
"typescript": "^4.6.4",
22+
"vite": "^3.2.0"
23+
}
24+
}
14.7 KB
Binary file not shown.
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"short_name": "with-config",
3+
"name": "{{name}}",
4+
"icons": [
5+
{
6+
"src": "favicon.ico",
7+
"sizes": "64x64 32x32 24x24 16x16",
8+
"type": "image/x-icon"
9+
}
10+
],
11+
"start_url": "./index.html",
12+
"display": "standalone",
13+
"theme_color": "#000000",
14+
"background_color": "#ffffff"
15+
}

examples/with-config/src/App.tsx

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {
2+
Admin,
3+
ListGuesser,
4+
EditGuesser,
5+
ShowGuesser,
6+
CardContentInner,
7+
Button,
8+
} from 'react-admin';
9+
import { Link } from 'react-router-dom';
10+
import { dataProvider } from './dataProvider';
11+
import { authProvider } from './authProvider';
12+
13+
export const App = () => (
14+
<Admin
15+
dataProvider={dataProvider}
16+
authProvider={authProvider}
17+
resources={(permissions: any) => ({
18+
posts: {
19+
edit: EditGuesser,
20+
list: ListGuesser,
21+
routes: [
22+
{
23+
path: 'all/*',
24+
element: <ListGuesser />,
25+
},
26+
{
27+
path: '*',
28+
element: (
29+
<CardContentInner>
30+
Posts Dashboard
31+
<br />
32+
<Button
33+
component={Link}
34+
to="all"
35+
label="All posts"
36+
/>
37+
</CardContentInner>
38+
),
39+
},
40+
],
41+
},
42+
comments: {
43+
list: ListGuesser,
44+
edit: EditGuesser,
45+
show: ShowGuesser,
46+
},
47+
})}
48+
customRoutes={(permissions: any) => [
49+
{ path: 'custom', element: <div>Custom route</div> },
50+
]}
51+
customRoutesWithoutLayout={[
52+
{
53+
path: 'custom-no-layout',
54+
element: <div>Custom route no layout</div>,
55+
},
56+
]}
57+
/>
58+
);

examples/with-config/src/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Authentication
2+
3+
The included auth provider should only be used for development and test purposes.
4+
You'll find a `users.json` file in the `src` directory that includes the users you can use.
5+
6+
You can sign in to the application with the following usernames and password:
7+
- janedoe / password
8+
- johndoe / password
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { AuthProvider, HttpError } from 'react-admin';
2+
import data from './users.json';
3+
4+
/**
5+
* This authProvider is only for test purposes. Don't use it in production.
6+
*/
7+
export const authProvider: AuthProvider = {
8+
login: ({ username, password }) => {
9+
const user = data.users.find(
10+
u => u.username === username && u.password === password
11+
);
12+
13+
if (user) {
14+
let { password, ...userToPersist } = user;
15+
localStorage.setItem('user', JSON.stringify(userToPersist));
16+
return Promise.resolve();
17+
}
18+
19+
return Promise.reject(
20+
new HttpError('Unauthorized', 401, {
21+
message: 'Invalid username or password',
22+
})
23+
);
24+
},
25+
logout: () => {
26+
localStorage.removeItem('user');
27+
return Promise.resolve();
28+
},
29+
checkError: () => Promise.resolve(),
30+
checkAuth: () =>
31+
localStorage.getItem('user') ? Promise.resolve() : Promise.reject(),
32+
getPermissions: () => Promise.resolve(['admin']),
33+
getIdentity: () => {
34+
const persistedUser = localStorage.getItem('user');
35+
const user = persistedUser ? JSON.parse(persistedUser) : null;
36+
37+
return Promise.resolve(user);
38+
},
39+
};
40+
41+
export default authProvider;

0 commit comments

Comments
 (0)