Compare commits
3 Commits
3c744c4509
...
012db596e8
| Author | SHA1 | Date | |
|---|---|---|---|
| 012db596e8 | |||
| fdb8284b51 | |||
| 000f46d583 |
2
.env
2
.env
@@ -1 +1 @@
|
|||||||
VITE_SIMPLE_REST_URL=http://localhost:8083/core/api/admin
|
VITE_SIMPLE_REST_URL=http://localhost:8081/core/api/admin
|
||||||
|
|||||||
31
eslint.config.mjs
Normal file
31
eslint.config.mjs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import globals from 'globals';
|
||||||
|
import pluginJs from '@eslint/js';
|
||||||
|
import pluginReact from 'eslint-plugin-react';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
files: ['**/*.{js,mjs,cjs,jsx}'],
|
||||||
|
rules: {
|
||||||
|
semi: 0,
|
||||||
|
'no-unused-vars': 1,
|
||||||
|
'comma-dangle': [1, {
|
||||||
|
arrays: 'only-multiline',
|
||||||
|
objects: 'only-multiline',
|
||||||
|
imports: 'only-multiline',
|
||||||
|
exports: 'only-multiline',
|
||||||
|
functions: 'only-multiline',
|
||||||
|
}],
|
||||||
|
yoda: ['error', 'always'],
|
||||||
|
'operator-linebreak': ['error', 'before'],
|
||||||
|
indent: ['error', 2, { SwitchCase: 1 }],
|
||||||
|
'space-before-function-paren': ['error', {
|
||||||
|
anonymous: 'never',
|
||||||
|
named: 'never',
|
||||||
|
asyncArrow: 'always',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ languageOptions: { globals: globals.browser } },
|
||||||
|
pluginJs.configs.recommended,
|
||||||
|
pluginReact.configs.flat.recommended,
|
||||||
|
];
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
"@mui/icons-material": "^5.16.14",
|
"@mui/icons-material": "^5.16.14",
|
||||||
"@mui/material": "^5.16.14",
|
"@mui/material": "^5.16.14",
|
||||||
"@tanstack/react-query": "^5.63.0",
|
"@tanstack/react-query": "^5.63.0",
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"ra-data-simple-rest": "^5.4.0",
|
"ra-data-simple-rest": "^5.4.0",
|
||||||
"react": "^18.3.0",
|
"react": "^18.3.0",
|
||||||
"react-admin": "^5.4.0",
|
"react-admin": "^5.4.0",
|
||||||
|
|||||||
76
pnpm-lock.yaml
generated
76
pnpm-lock.yaml
generated
@@ -23,6 +23,12 @@ importers:
|
|||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: ^5.63.0
|
specifier: ^5.63.0
|
||||||
version: 5.63.0(react@18.3.1)
|
version: 5.63.0(react@18.3.1)
|
||||||
|
axios:
|
||||||
|
specifier: ^1.7.9
|
||||||
|
version: 1.7.9
|
||||||
|
lodash:
|
||||||
|
specifier: ^4.17.21
|
||||||
|
version: 4.17.21
|
||||||
ra-data-simple-rest:
|
ra-data-simple-rest:
|
||||||
specifier: ^5.4.0
|
specifier: ^5.4.0
|
||||||
version: 5.4.3(ra-core@5.4.3(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.54.2(react@18.3.1))(react-router-dom@6.28.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-router@6.28.1(react@18.3.1))(react@18.3.1))
|
version: 5.4.3(ra-core@5.4.3(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.54.2(react@18.3.1))(react-router-dom@6.28.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-router@6.28.1(react@18.3.1))(react@18.3.1))
|
||||||
@@ -792,6 +798,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
asynckit@0.4.0:
|
||||||
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
attr-accept@2.2.5:
|
attr-accept@2.2.5:
|
||||||
resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
|
resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -803,6 +812,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
axios@1.7.9:
|
||||||
|
resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
|
||||||
|
|
||||||
babel-plugin-macros@3.1.0:
|
babel-plugin-macros@3.1.0:
|
||||||
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
||||||
engines: {node: '>=10', npm: '>=6'}
|
engines: {node: '>=10', npm: '>=6'}
|
||||||
@@ -856,6 +868,10 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
concat-map@0.0.1:
|
concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
|
||||||
@@ -918,6 +934,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
delayed-stream@1.0.0:
|
||||||
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
dir-glob@3.0.1:
|
dir-glob@3.0.1:
|
||||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1099,9 +1119,22 @@ packages:
|
|||||||
flatted@3.3.2:
|
flatted@3.3.2:
|
||||||
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
|
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
|
||||||
|
|
||||||
|
follow-redirects@1.15.9:
|
||||||
|
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
|
||||||
for-each@0.3.3:
|
for-each@0.3.3:
|
||||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||||
|
|
||||||
|
form-data@4.0.1:
|
||||||
|
resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
fs.realpath@1.0.0:
|
fs.realpath@1.0.0:
|
||||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||||
|
|
||||||
@@ -1417,6 +1450,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
|
|
||||||
|
mime-db@1.52.0:
|
||||||
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
mime-types@2.1.35:
|
||||||
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||||
|
|
||||||
@@ -1542,6 +1583,9 @@ packages:
|
|||||||
prop-types@15.8.1:
|
prop-types@15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0:
|
||||||
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
|
|
||||||
punycode@2.3.1:
|
punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2673,6 +2717,8 @@ snapshots:
|
|||||||
get-intrinsic: 1.2.7
|
get-intrinsic: 1.2.7
|
||||||
is-array-buffer: 3.0.5
|
is-array-buffer: 3.0.5
|
||||||
|
|
||||||
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
attr-accept@2.2.5: {}
|
attr-accept@2.2.5: {}
|
||||||
|
|
||||||
autosuggest-highlight@3.3.4:
|
autosuggest-highlight@3.3.4:
|
||||||
@@ -2683,6 +2729,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
possible-typed-array-names: 1.0.0
|
possible-typed-array-names: 1.0.0
|
||||||
|
|
||||||
|
axios@1.7.9:
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.15.9
|
||||||
|
form-data: 4.0.1
|
||||||
|
proxy-from-env: 1.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
|
||||||
babel-plugin-macros@3.1.0:
|
babel-plugin-macros@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
@@ -2741,6 +2795,10 @@ snapshots:
|
|||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
dependencies:
|
||||||
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
|
||||||
convert-source-map@1.9.0: {}
|
convert-source-map@1.9.0: {}
|
||||||
@@ -2805,6 +2863,8 @@ snapshots:
|
|||||||
has-property-descriptors: 1.0.2
|
has-property-descriptors: 1.0.2
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
|
|
||||||
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
dir-glob@3.0.1:
|
dir-glob@3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-type: 4.0.0
|
path-type: 4.0.0
|
||||||
@@ -3118,10 +3178,18 @@ snapshots:
|
|||||||
|
|
||||||
flatted@3.3.2: {}
|
flatted@3.3.2: {}
|
||||||
|
|
||||||
|
follow-redirects@1.15.9: {}
|
||||||
|
|
||||||
for-each@0.3.3:
|
for-each@0.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-callable: 1.2.7
|
is-callable: 1.2.7
|
||||||
|
|
||||||
|
form-data@4.0.1:
|
||||||
|
dependencies:
|
||||||
|
asynckit: 0.4.0
|
||||||
|
combined-stream: 1.0.8
|
||||||
|
mime-types: 2.1.35
|
||||||
|
|
||||||
fs.realpath@1.0.0: {}
|
fs.realpath@1.0.0: {}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
@@ -3438,6 +3506,12 @@ snapshots:
|
|||||||
braces: 3.0.3
|
braces: 3.0.3
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
mime-db@1.52.0: {}
|
||||||
|
|
||||||
|
mime-types@2.1.35:
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.52.0
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 1.1.11
|
brace-expansion: 1.1.11
|
||||||
@@ -3563,6 +3637,8 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0: {}
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
query-string@7.1.3:
|
query-string@7.1.3:
|
||||||
|
|||||||
19
src/App.tsx
19
src/App.tsx
@@ -1,14 +1,7 @@
|
|||||||
import {
|
import { Admin, Resource } from "react-admin";
|
||||||
Admin,
|
|
||||||
EditGuesser,
|
|
||||||
ListGuesser,
|
|
||||||
Resource,
|
|
||||||
ShowGuesser,
|
|
||||||
} from "react-admin";
|
|
||||||
import { Layout } from "./Layout";
|
import { Layout } from "./Layout";
|
||||||
import { dataProvider } from "./dataProvider";
|
import { AdminDashboard, PersonList, PersonShow } from "@admin";
|
||||||
import { authProvider } from "./authProvider";
|
import { authProvider, dataProvider } from "@core";
|
||||||
import { AdminDashboard } from '@admin';
|
|
||||||
|
|
||||||
export const App = () => (
|
export const App = () => (
|
||||||
<Admin
|
<Admin
|
||||||
@@ -19,9 +12,9 @@ export const App = () => (
|
|||||||
>
|
>
|
||||||
<Resource
|
<Resource
|
||||||
name="person"
|
name="person"
|
||||||
list={ListGuesser}
|
options={{ label: "Users" }}
|
||||||
edit={EditGuesser}
|
list={PersonList}
|
||||||
show={ShowGuesser}
|
show={PersonShow}
|
||||||
/>
|
/>
|
||||||
</Admin>
|
</Admin>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import { Card, CardContent } from "@mui/material";
|
import { Card, CardContent, Typography } from "@mui/material";
|
||||||
import { Title, useDataProvider } from "react-admin";
|
import { Title } from "react-admin";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
|
||||||
|
|
||||||
export const AdminDashboard = () => {
|
export const AdminDashboard = () => {
|
||||||
const dataProvider = useDataProvider();
|
|
||||||
const { data } = useQuery({
|
|
||||||
queryKey: ["dashboard"],
|
|
||||||
queryFn: () => dataProvider.person(),
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card sx={{ mt: 5 }}>
|
||||||
<Title title="Welcome to the administration" />
|
<Title title="Welcome to the administration" />
|
||||||
<CardContent>Lorem ipsum sic dolor amet...</CardContent>
|
<CardContent>
|
||||||
|
<Typography>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet
|
||||||
|
impedit, temporibus? Amet dolor fuga hic libero molestiae nemo
|
||||||
|
perferendis quas quis repellendus voluptas? Aliquid doloremque, est
|
||||||
|
labore odit optio similique.
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ import { Menu } from "react-admin";
|
|||||||
export const AdminMenu = () => (
|
export const AdminMenu = () => (
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.DashboardItem />
|
<Menu.DashboardItem />
|
||||||
|
<Menu.ResourceItem name="person" />
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export { AdminMenu } from './admin-menu';
|
export { AdminMenu } from './admin-menu';
|
||||||
export { AdminDashboard } from './admin-dashboard';
|
export { AdminDashboard } from './admin-dashboard';
|
||||||
|
export * from './resources';
|
||||||
|
|||||||
1
src/admin-components/resources/index.ts
Normal file
1
src/admin-components/resources/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './person';
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import React, { FC } from 'react';
|
||||||
|
import { isObject } from "lodash";
|
||||||
|
import { useRecordContext } from 'react-admin';
|
||||||
|
import { Chip, Stack } from '@mui/material';
|
||||||
|
|
||||||
|
interface FieldProps {
|
||||||
|
source: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ArrayField: FC<FieldProps> = ({ source }) => {
|
||||||
|
const record = useRecordContext();
|
||||||
|
const objects = record?.[source];
|
||||||
|
|
||||||
|
if (!objects) return "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack direction="row" gap={1}>
|
||||||
|
{objects.map((currentObject: string, key: number) => {
|
||||||
|
if (isObject(currentObject)) {
|
||||||
|
return (
|
||||||
|
<Chip key={`${key}-people`} size="small" label={currentObject.name} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Chip key={`${key}-people`} size="small" label={currentObject} />
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { ArrayField } from "./array-field.tsx";
|
||||||
3
src/admin-components/resources/person/index.ts
Normal file
3
src/admin-components/resources/person/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export { PersonList } from './list.tsx';
|
||||||
|
export { PersonShow } from './show.tsx';
|
||||||
|
export * from './components';
|
||||||
103
src/admin-components/resources/person/list.tsx
Normal file
103
src/admin-components/resources/person/list.tsx
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import React, { Fragment, useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
BooleanField,
|
||||||
|
Datagrid,
|
||||||
|
isEmpty,
|
||||||
|
ListContextProvider,
|
||||||
|
ListToolbar,
|
||||||
|
Pagination,
|
||||||
|
TextField,
|
||||||
|
Title,
|
||||||
|
TopToolbar,
|
||||||
|
useDataProvider,
|
||||||
|
WrapperField,
|
||||||
|
} from "react-admin";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { ArrayField } from "./components";
|
||||||
|
import { TextField as MuiTextField } from "@mui/material";
|
||||||
|
|
||||||
|
export const PersonList = () => {
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [perPage, setPerPage] = useState(25);
|
||||||
|
const [firstName, setFirstName] = useState("");
|
||||||
|
const dataProvider = useDataProvider();
|
||||||
|
const { data, isPending, refetch } = useQuery({
|
||||||
|
queryKey: ["personList", page, perPage, firstName],
|
||||||
|
queryFn: () => {
|
||||||
|
const httpParams = new URLSearchParams({
|
||||||
|
page: `${page - 1}`,
|
||||||
|
size: `${perPage}`,
|
||||||
|
...(isEmpty(firstName)
|
||||||
|
? {}
|
||||||
|
: { filters: `firstName::like_ignore_case::${firstName}` }),
|
||||||
|
});
|
||||||
|
|
||||||
|
return dataProvider.personList(httpParams);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await refetch();
|
||||||
|
})();
|
||||||
|
}, [page, perPage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Title title="Users" />
|
||||||
|
<ListToolbar
|
||||||
|
actions={
|
||||||
|
<TopToolbar>
|
||||||
|
<FilterName setFirstName={setFirstName} />
|
||||||
|
</TopToolbar>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Datagrid
|
||||||
|
resource="person"
|
||||||
|
data={data?.content}
|
||||||
|
total={data?.totalElements}
|
||||||
|
isPending={isPending}
|
||||||
|
sort={undefined}
|
||||||
|
bulkActionButtons={false}
|
||||||
|
>
|
||||||
|
<TextField source="firstName" />
|
||||||
|
<TextField source="lastName" />
|
||||||
|
<TextField source="email" label="Email User ID" />
|
||||||
|
<TextField source="id" label="User ID" />
|
||||||
|
<TextField source="status" />
|
||||||
|
<BooleanField source="userAccess" label="Access to the Platform" />
|
||||||
|
<WrapperField label="Company">
|
||||||
|
<ArrayField source="parties" />
|
||||||
|
</WrapperField>
|
||||||
|
<WrapperField label="Programs assigned">
|
||||||
|
<ArrayField source="assignedPrograms" />
|
||||||
|
</WrapperField>
|
||||||
|
<WrapperField label="Functions assigned">
|
||||||
|
<ArrayField source="assignedFunctions" />
|
||||||
|
</WrapperField>
|
||||||
|
</Datagrid>
|
||||||
|
<ListContextProvider
|
||||||
|
value={{
|
||||||
|
page,
|
||||||
|
perPage,
|
||||||
|
total: data?.totalElements ?? 0,
|
||||||
|
setPage,
|
||||||
|
setPerPage,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Pagination />
|
||||||
|
</ListContextProvider>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FilterName = ({ setFirstName }) => {
|
||||||
|
return (
|
||||||
|
<MuiTextField
|
||||||
|
label="First name"
|
||||||
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setFirstName(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
114
src/admin-components/resources/person/show.tsx
Normal file
114
src/admin-components/resources/person/show.tsx
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
BooleanField,
|
||||||
|
DateField,
|
||||||
|
Labeled,
|
||||||
|
Show,
|
||||||
|
SimpleShowLayout,
|
||||||
|
TextField,
|
||||||
|
} from "react-admin";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
Stack,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { ArrayField } from "@admin";
|
||||||
|
|
||||||
|
export const PersonShow = () => {
|
||||||
|
return (
|
||||||
|
<Show>
|
||||||
|
<SimpleShowLayout>
|
||||||
|
<Card sx={{ border: 1 }}>
|
||||||
|
<CardHeader title="General info" />
|
||||||
|
<CardContent>
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
flexWrap: "wrap",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
direction="row"
|
||||||
|
columnGap={5}
|
||||||
|
rowGap={2}
|
||||||
|
>
|
||||||
|
<Labeled label="Name">
|
||||||
|
<Stack direction="row" gap={1}>
|
||||||
|
<TextField sx={{ textTransform: "" }} source="title" />
|
||||||
|
<TextField source="firstName" />
|
||||||
|
<TextField source="lastName" />
|
||||||
|
</Stack>
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="E-mail address">
|
||||||
|
<TextField source="email" />
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="User ID">
|
||||||
|
<TextField source="id" />
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="Access to the Platform">
|
||||||
|
<BooleanField source="userAccess" />
|
||||||
|
</Labeled>
|
||||||
|
<Box>
|
||||||
|
<Typography
|
||||||
|
sx={{ color: "rgba(255, 255, 255, 0.7)" }}
|
||||||
|
variant="caption"
|
||||||
|
>
|
||||||
|
Company
|
||||||
|
</Typography>
|
||||||
|
<ArrayField source="parties" />
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ flexBasis: "100%" }} />
|
||||||
|
<Labeled label="Access to the Platform">
|
||||||
|
<BooleanField source="userAccess" />
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="Position">
|
||||||
|
<TextField source="jobPosition" emptyText={"\u2014"} />
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="Phone number">
|
||||||
|
<TextField source="phoneNumber" emptyText={"\u2014"} />
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="Mobile number">
|
||||||
|
<TextField source="mobileNumber" emptyText={"\u2014"} />
|
||||||
|
</Labeled>
|
||||||
|
<Box />
|
||||||
|
</Stack>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card sx={{ border: 1 }}>
|
||||||
|
<CardHeader title="Platform info" />
|
||||||
|
<CardContent>
|
||||||
|
<Stack
|
||||||
|
sx={{ justifyContent: "flex-start", alignItems: "center" }}
|
||||||
|
direction="row"
|
||||||
|
gap={5}
|
||||||
|
>
|
||||||
|
<Labeled label="Last changes date">
|
||||||
|
<DateField
|
||||||
|
source="updateDate"
|
||||||
|
locales="fr-CA"
|
||||||
|
emptyText={"\u2014"}
|
||||||
|
/>
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="User Access Active From">
|
||||||
|
<DateField
|
||||||
|
source="userAccessFrom"
|
||||||
|
locales="fr-CA"
|
||||||
|
emptyText={"\u2014"}
|
||||||
|
/>
|
||||||
|
</Labeled>
|
||||||
|
<Labeled label="User Access Active To">
|
||||||
|
<DateField
|
||||||
|
source="userAccessTo"
|
||||||
|
locales="fr-CA"
|
||||||
|
emptyText={"\u2014"}
|
||||||
|
/>
|
||||||
|
</Labeled>
|
||||||
|
</Stack>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</SimpleShowLayout>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -10,6 +10,7 @@ export const authProvider: AuthProvider = {
|
|||||||
response = await fetch(
|
response = await fetch(
|
||||||
new Request("http://localhost:8080/atsp-idp/token", {
|
new Request("http://localhost:8080/atsp-idp/token", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
grant_type: "authorization_code",
|
grant_type: "authorization_code",
|
||||||
code: "code",
|
code: "code",
|
||||||
@@ -36,9 +37,9 @@ export const authProvider: AuthProvider = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { refresh_token } = await response.json();
|
const { access_token } = await response.json();
|
||||||
localStorage.setItem("token", refresh_token);
|
localStorage.setItem("user", access_token);
|
||||||
localStorage.setItem("user", refresh_token);
|
localStorage.setItem("token", access_token);
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
@@ -1,19 +1,10 @@
|
|||||||
import { useQueryEngine } from "@core";
|
import { useQueryEngine } from './hooks';
|
||||||
|
|
||||||
export const dataProviderExtension = () => {
|
export const dataProviderExtension = () => {
|
||||||
const { fetchCommon } = useQueryEngine();
|
const { fetchCommon } = useQueryEngine();
|
||||||
|
const url = import.meta.env.VITE_SIMPLE_REST_URL;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
person: () =>
|
personList: (params: URLSearchParams) => fetchCommon(`${url}/person?${params}`),
|
||||||
fetchCommon(
|
|
||||||
"http://localhost:8081/core/api/admin/person",
|
|
||||||
{
|
|
||||||
headers: new Headers({
|
|
||||||
Accept: "application/json",
|
|
||||||
'X-XSRF-TOKEN': 'c3aKjTfLsPSdmiMtTaj933RbsQMR6IWmf9C5ZImMh9pCmDGkEETougKpiZew-UcZe4XJ5xE4nDpwirWLR-SOXbm94-Im-QLB',
|
|
||||||
'Cookie': 'LAST_LOGIN_LOCATION=http://localhost:3000; SESSION=652f7c23-fe94-4727-a980-59052e75aab2; XSRF-TOKEN=c2b75b9c-cd46-48ec-9ab0-847901d8da3e',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
31
src/admin-core/dataProvider.ts
Normal file
31
src/admin-core/dataProvider.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { fetchUtils, withLifecycleCallbacks } from 'react-admin';
|
||||||
|
import simpleRestProvider from "ra-data-simple-rest";
|
||||||
|
import { dataProviderExtension } from "@core";
|
||||||
|
|
||||||
|
const fetchJson = (url, options = {}) => {
|
||||||
|
if (!options.headers) {
|
||||||
|
options.headers = new Headers({ Accept: "application/json" });
|
||||||
|
}
|
||||||
|
options.credentials = "include";
|
||||||
|
options.headers.set(
|
||||||
|
"Authorization",
|
||||||
|
`Bearer ${localStorage.getItem("user")}`,
|
||||||
|
);
|
||||||
|
options.headers.set("X-XSRF-TOKEN", localStorage.getItem("user"));
|
||||||
|
return fetchUtils.fetchJson(url, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dataProvider = withLifecycleCallbacks(
|
||||||
|
{
|
||||||
|
...simpleRestProvider(import.meta.env.VITE_SIMPLE_REST_URL, fetchJson),
|
||||||
|
...dataProviderExtension(),
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
resource: "person",
|
||||||
|
afterRead: async (data: object) => {
|
||||||
|
return data.original;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
export const useQueryEngine = () => {
|
export const useQueryEngine = () => {
|
||||||
const defaultHeaders = {
|
const defaultHeaders = {
|
||||||
Accept: 'application/ld+json',
|
Accept: "application/json",
|
||||||
'Content-Type': 'application/ld+json',
|
"Content-Type": "application/json",
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = async (request) => {
|
const response = async (request: Request) => {
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await fetch(request);
|
response = await fetch(request);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('Network error');
|
throw new Error("Network error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (200 > response?.status || 300 <= response?.status) {
|
if (200 > response?.status || 300 <= response?.status) {
|
||||||
@@ -20,58 +20,76 @@ export const useQueryEngine = () => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
return ({
|
const decodeJwt = (token: string) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(window.atob(token.split(".")[1]));
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
defaultHeaders,
|
defaultHeaders,
|
||||||
fetchCommon: async (url, options = {}) => {
|
fetchCommon: async (url: string, options: object = {}) => {
|
||||||
|
const token = decodeJwt(localStorage.getItem("user"));
|
||||||
|
|
||||||
|
document.cookie = `XSRF-TOKEN=${token.sub}; SESSION=${token.jti}`;
|
||||||
|
|
||||||
return await response(
|
return await response(
|
||||||
new Request(url, {
|
new Request(url, {
|
||||||
...(options?.method ? { method: options.method } : { method: 'GET' }),
|
credentials: "include",
|
||||||
|
...(options?.method ? { method: options.method } : { method: "GET" }),
|
||||||
...(options.replaceHeaders
|
...(options.replaceHeaders
|
||||||
? { headers: options.replaceHeaders }
|
? { headers: new Headers(options.replaceHeaders) }
|
||||||
: {
|
: {
|
||||||
headers: {
|
headers: new Headers({
|
||||||
...defaultHeaders,
|
...defaultHeaders,
|
||||||
Authorization: `Bearer ${localStorage.getItem('user')}`,
|
Authorization: `Bearer ${localStorage.getItem("user")}`,
|
||||||
|
"X-XSRF-TOKEN": localStorage.getItem("user"),
|
||||||
...(options?.headers ? { ...options.headers } : {}),
|
...(options?.headers ? { ...options.headers } : {}),
|
||||||
},
|
}),
|
||||||
}),
|
}),
|
||||||
...(options?.body ? { body: options.body } : {}),
|
...(options?.body ? { body: options.body } : {}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
fetchMultipart: async (url, options) => {
|
fetchMultipart: async (url: string, options: object = {}) => {
|
||||||
return await response(
|
return await response(
|
||||||
new Request(url, {
|
new Request(url, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/ld+json',
|
Accept: "application/json",
|
||||||
/**
|
/**
|
||||||
* DO NOT SPECIFY THIS - Because the boundary data in it
|
* DO NOT SPECIFY THIS - Because the boundary data in it
|
||||||
* @see https://stackoverflow.com/a/71392989/3111514
|
* @see https://stackoverflow.com/a/71392989/3111514
|
||||||
*/
|
*/
|
||||||
// 'Content-Type': 'multipart/form-data',
|
// 'Content-Type': 'multipart/form-data',
|
||||||
Authorization: `Bearer ${localStorage.getItem('user')}`,
|
Authorization: `Bearer ${localStorage.getItem("user")}`,
|
||||||
},
|
},
|
||||||
...options,
|
...options,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
fetchPlain: async (url, options = {}, withAuth = false) => {
|
fetchPlain: async (url: string, options: object = {}, withAuth = false) => {
|
||||||
return await response(
|
return await response(
|
||||||
new Request(url, {
|
new Request(url, {
|
||||||
...(options?.method ? { method: options.method } : { method: 'GET' }),
|
...(options?.method ? { method: options.method } : { method: "GET" }),
|
||||||
...(options.replaceHeaders
|
...(options.replaceHeaders
|
||||||
? { headers: options.replaceHeaders }
|
? { headers: options.replaceHeaders }
|
||||||
: {
|
: {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
...(options?.headers ? { headers: options.headers } : {}),
|
...(options?.headers ? { headers: options.headers } : {}),
|
||||||
...(withAuth ? { Authorization: `Bearer ${localStorage.getItem('user')}` } : {}),
|
...(withAuth
|
||||||
|
? {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("user")}`,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
...(options?.body ? { body: options.body } : {}),
|
...(options?.body ? { body: options.body } : {}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
export { dataProviderExtension } from './data-provider-extension';
|
export { dataProviderExtension } from './data-provider-extension';
|
||||||
|
export { dataProvider } from './dataProvider.ts';
|
||||||
|
export { authProvider } from './authProvider.ts';
|
||||||
export * from './hooks';
|
export * from './hooks';
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import simpleRestProvider from "ra-data-simple-rest";
|
|
||||||
import { dataProviderExtension } from "@core";
|
|
||||||
|
|
||||||
export const dataProvider = {
|
|
||||||
...simpleRestProvider(import.meta.env.VITE_SIMPLE_REST_URL),
|
|
||||||
...dataProviderExtension(),
|
|
||||||
};
|
|
||||||
@@ -7,6 +7,8 @@ export default defineConfig({
|
|||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
host: true,
|
host: true,
|
||||||
|
port: 3000,
|
||||||
|
cors: false,
|
||||||
},
|
},
|
||||||
base: "./",
|
base: "./",
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|||||||
Reference in New Issue
Block a user