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/material": "^5.16.14",
|
||||
"@tanstack/react-query": "^5.63.0",
|
||||
"axios": "^1.7.9",
|
||||
"lodash": "^4.17.21",
|
||||
"ra-data-simple-rest": "^5.4.0",
|
||||
"react": "^18.3.0",
|
||||
"react-admin": "^5.4.0",
|
||||
|
||||
76
pnpm-lock.yaml
generated
76
pnpm-lock.yaml
generated
@@ -23,6 +23,12 @@ importers:
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.63.0
|
||||
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:
|
||||
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))
|
||||
@@ -792,6 +798,9 @@ packages:
|
||||
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
attr-accept@2.2.5:
|
||||
resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -803,6 +812,9 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
axios@1.7.9:
|
||||
resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
|
||||
|
||||
babel-plugin-macros@3.1.0:
|
||||
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
||||
engines: {node: '>=10', npm: '>=6'}
|
||||
@@ -856,6 +868,10 @@ packages:
|
||||
color-name@1.1.4:
|
||||
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:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
@@ -918,6 +934,10 @@ packages:
|
||||
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1099,9 +1119,22 @@ packages:
|
||||
flatted@3.3.2:
|
||||
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:
|
||||
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:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
@@ -1417,6 +1450,14 @@ packages:
|
||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||
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:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
@@ -1542,6 +1583,9 @@ packages:
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
punycode@2.3.1:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -2673,6 +2717,8 @@ snapshots:
|
||||
get-intrinsic: 1.2.7
|
||||
is-array-buffer: 3.0.5
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
attr-accept@2.2.5: {}
|
||||
|
||||
autosuggest-highlight@3.3.4:
|
||||
@@ -2683,6 +2729,14 @@ snapshots:
|
||||
dependencies:
|
||||
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:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
@@ -2741,6 +2795,10 @@ snapshots:
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
convert-source-map@1.9.0: {}
|
||||
@@ -2805,6 +2863,8 @@ snapshots:
|
||||
has-property-descriptors: 1.0.2
|
||||
object-keys: 1.1.1
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
dependencies:
|
||||
path-type: 4.0.0
|
||||
@@ -3118,10 +3178,18 @@ snapshots:
|
||||
|
||||
flatted@3.3.2: {}
|
||||
|
||||
follow-redirects@1.15.9: {}
|
||||
|
||||
for-each@0.3.3:
|
||||
dependencies:
|
||||
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: {}
|
||||
|
||||
fsevents@2.3.3:
|
||||
@@ -3438,6 +3506,12 @@ snapshots:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
|
||||
mime-db@1.52.0: {}
|
||||
|
||||
mime-types@2.1.35:
|
||||
dependencies:
|
||||
mime-db: 1.52.0
|
||||
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.11
|
||||
@@ -3563,6 +3637,8 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
react-is: 16.13.1
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
query-string@7.1.3:
|
||||
|
||||
19
src/App.tsx
19
src/App.tsx
@@ -1,14 +1,7 @@
|
||||
import {
|
||||
Admin,
|
||||
EditGuesser,
|
||||
ListGuesser,
|
||||
Resource,
|
||||
ShowGuesser,
|
||||
} from "react-admin";
|
||||
import { Admin, Resource } from "react-admin";
|
||||
import { Layout } from "./Layout";
|
||||
import { dataProvider } from "./dataProvider";
|
||||
import { authProvider } from "./authProvider";
|
||||
import { AdminDashboard } from '@admin';
|
||||
import { AdminDashboard, PersonList, PersonShow } from "@admin";
|
||||
import { authProvider, dataProvider } from "@core";
|
||||
|
||||
export const App = () => (
|
||||
<Admin
|
||||
@@ -19,9 +12,9 @@ export const App = () => (
|
||||
>
|
||||
<Resource
|
||||
name="person"
|
||||
list={ListGuesser}
|
||||
edit={EditGuesser}
|
||||
show={ShowGuesser}
|
||||
options={{ label: "Users" }}
|
||||
list={PersonList}
|
||||
show={PersonShow}
|
||||
/>
|
||||
</Admin>
|
||||
);
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import { Card, CardContent } from "@mui/material";
|
||||
import { Title, useDataProvider } from "react-admin";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Card, CardContent, Typography } from "@mui/material";
|
||||
import { Title } from "react-admin";
|
||||
|
||||
export const AdminDashboard = () => {
|
||||
const dataProvider = useDataProvider();
|
||||
const { data } = useQuery({
|
||||
queryKey: ["dashboard"],
|
||||
queryFn: () => dataProvider.person(),
|
||||
});
|
||||
|
||||
console.log(data);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card sx={{ mt: 5 }}>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,5 +3,6 @@ import { Menu } from "react-admin";
|
||||
export const AdminMenu = () => (
|
||||
<Menu>
|
||||
<Menu.DashboardItem />
|
||||
<Menu.ResourceItem name="person" />
|
||||
</Menu>
|
||||
);
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export { AdminMenu } from './admin-menu';
|
||||
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(
|
||||
new Request("http://localhost:8080/atsp-idp/token", {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: new URLSearchParams({
|
||||
grant_type: "authorization_code",
|
||||
code: "code",
|
||||
@@ -36,9 +37,9 @@ export const authProvider: AuthProvider = {
|
||||
);
|
||||
}
|
||||
|
||||
const { refresh_token } = await response.json();
|
||||
localStorage.setItem("token", refresh_token);
|
||||
localStorage.setItem("user", refresh_token);
|
||||
const { access_token } = await response.json();
|
||||
localStorage.setItem("user", access_token);
|
||||
localStorage.setItem("token", access_token);
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
@@ -1,19 +1,10 @@
|
||||
import { useQueryEngine } from "@core";
|
||||
import { useQueryEngine } from './hooks';
|
||||
|
||||
export const dataProviderExtension = () => {
|
||||
const { fetchCommon } = useQueryEngine();
|
||||
const url = import.meta.env.VITE_SIMPLE_REST_URL;
|
||||
|
||||
return {
|
||||
person: () =>
|
||||
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',
|
||||
}),
|
||||
},
|
||||
),
|
||||
personList: (params: URLSearchParams) => fetchCommon(`${url}/person?${params}`),
|
||||
};
|
||||
};
|
||||
|
||||
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 = () => {
|
||||
const defaultHeaders = {
|
||||
Accept: 'application/ld+json',
|
||||
'Content-Type': 'application/ld+json',
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
const response = async (request) => {
|
||||
const response = async (request: Request) => {
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = await fetch(request);
|
||||
} catch (e) {
|
||||
throw new Error('Network error');
|
||||
throw new Error("Network error");
|
||||
}
|
||||
|
||||
if (200 > response?.status || 300 <= response?.status) {
|
||||
@@ -20,58 +20,76 @@ export const useQueryEngine = () => {
|
||||
return response.json();
|
||||
};
|
||||
|
||||
return ({
|
||||
const decodeJwt = (token: string) => {
|
||||
try {
|
||||
return JSON.parse(window.atob(token.split(".")[1]));
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
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(
|
||||
new Request(url, {
|
||||
...(options?.method ? { method: options.method } : { method: 'GET' }),
|
||||
credentials: "include",
|
||||
...(options?.method ? { method: options.method } : { method: "GET" }),
|
||||
...(options.replaceHeaders
|
||||
? { headers: options.replaceHeaders }
|
||||
? { headers: new Headers(options.replaceHeaders) }
|
||||
: {
|
||||
headers: {
|
||||
headers: new Headers({
|
||||
...defaultHeaders,
|
||||
Authorization: `Bearer ${localStorage.getItem('user')}`,
|
||||
Authorization: `Bearer ${localStorage.getItem("user")}`,
|
||||
"X-XSRF-TOKEN": localStorage.getItem("user"),
|
||||
...(options?.headers ? { ...options.headers } : {}),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
...(options?.body ? { body: options.body } : {}),
|
||||
}),
|
||||
);
|
||||
},
|
||||
fetchMultipart: async (url, options) => {
|
||||
fetchMultipart: async (url: string, options: object = {}) => {
|
||||
return await response(
|
||||
new Request(url, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: 'application/ld+json',
|
||||
Accept: "application/json",
|
||||
/**
|
||||
* DO NOT SPECIFY THIS - Because the boundary data in it
|
||||
* @see https://stackoverflow.com/a/71392989/3111514
|
||||
*/
|
||||
// 'Content-Type': 'multipart/form-data',
|
||||
Authorization: `Bearer ${localStorage.getItem('user')}`,
|
||||
Authorization: `Bearer ${localStorage.getItem("user")}`,
|
||||
},
|
||||
...options,
|
||||
}),
|
||||
);
|
||||
},
|
||||
fetchPlain: async (url, options = {}, withAuth = false) => {
|
||||
fetchPlain: async (url: string, options: object = {}, withAuth = false) => {
|
||||
return await response(
|
||||
new Request(url, {
|
||||
...(options?.method ? { method: options.method } : { method: 'GET' }),
|
||||
...(options?.method ? { method: options.method } : { method: "GET" }),
|
||||
...(options.replaceHeaders
|
||||
? { headers: options.replaceHeaders }
|
||||
: {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
...(options?.headers ? { headers: options.headers } : {}),
|
||||
...(withAuth ? { Authorization: `Bearer ${localStorage.getItem('user')}` } : {}),
|
||||
...(withAuth
|
||||
? {
|
||||
Authorization: `Bearer ${localStorage.getItem("user")}`,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}),
|
||||
...(options?.body ? { body: options.body } : {}),
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
export { dataProviderExtension } from './data-provider-extension';
|
||||
export { dataProvider } from './dataProvider.ts';
|
||||
export { authProvider } from './authProvider.ts';
|
||||
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()],
|
||||
server: {
|
||||
host: true,
|
||||
port: 3000,
|
||||
cors: false,
|
||||
},
|
||||
base: "./",
|
||||
resolve: {
|
||||
|
||||
Reference in New Issue
Block a user