Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit 66cef15e authored by Philippe Coicadan's avatar Philippe Coicadan
Browse files

redesign reference input (create and edit), replace role author by producer,...

redesign reference input (create and edit), replace role author by producer, improve dataprocider getmany, fix in about, improve installation doc
parent 16f6851f
No related branches found
No related tags found
No related merge requests found
......@@ -18,23 +18,26 @@ Suivez les instructions que vous trouverez sur Internet, par exemple [ici](https
2. Placez-vous dans ce répertoire et tapez la commande: npm install
Cette commande installe tous les paquets React-Admin nécessaires ainsi que les paquets dont ils dépendent.
3. Pour construire la version de production,
1. modifiez dans le fichier .env le paramètre VITE_BACKEND_URL pour lui indiquer l'URL du serveur qui implémente l'**API AROLIOS**. Exemple: https://my_arolios_server
2. tapez la commande: npm build
1. copiez le fichier .env_template dans le fichier .env et modifiez le paramètre VITE_BACKEND_URL pour lui indiquer l'URL du serveur qui implémente l'**API AROLIOS**. Exemple: https://my_arolios_server
2. tapez la commande: npm run build
Un répertoire dist est créé avec les fichiers nécessaires à l'exécution
### Déploiement
1. Copiez le répertoire dist créé dans l'emplacement adéquat pour le serveur web (par exemple Apache) qui servira aux utilisateurs **AROLIOS WebUI**. Exemple /var/www/arolios_webui
2. Vérifiez la présence du fichier .htaccess fourni pour le serveur Apache. Si vous l'utilisez, il faut configurer Apache avec, par exemple sur Linux, les commandes suivantes:
1. Copiez le répertoire dist créé dans le répertoire adéquat pour le serveur web (par exemple Apache) qui servira aux utilisateurs **AROLIOS WebUI**. Exemple /var/www/arolios_webui
2. Si vous utilisez le serveur Apache (recommandé), copiez dans ce répertoire le fichier .htaccess fourni avec les sources. Dans ce cas, il faut configurer Apache avec, par exemple sur Linux, les commandes suivantes:
1. sudo a2enmode rewrite
2. sudo systemctl apache2 restart
3. Configurez votre serveur web (Apache par exemple) pour servir **AROLIOS WebUI**. Par exemple avec Apache sur Linux:
1. Placez vous dans le repertoire /etc/apache2/sites-available
2. Copiez le fichier 000-default.conf (par exemple arolios.conf)
3. Dans cette copie, renseignez les paramètres ServerName (l'URL pour adresser **AROLIOS WebUI**, par exemple www.my-arolios.example.com) et DocumentRoot (l'emplacement du fichier index.html, par exemple /var/www/arolios_webui)
4. Passez la commande: sudo a2ensite /etc/apache/sites-available/arolios.conf
5. Redémarrez le serveur Apache: sudo systemctl restart apache2
4. Si le serveur de l'API AROLIOS que vous avez renseigné dans le paramètre VITE_BACKEND_URL est lancé ainsi que votre serveur web servant **AROLIOS WebUI** (Apache par exemple), vous pouvez démarrer **AROLIOS WebUI** depuis votre navigateur web en l'adressant avec l'URL renseigné dans la configuration de votre serveur Web ( par exemple www.my-arolios.example.com)
1. Placez-vous dans le repertoire /etc/apache2/sites-available
2. Copiez le fichier 000-default.conf ou default-ssl.conf si vous voulez fonctionner en HTTPS (par exemple arolios.conf)
3. Dans cette copie, renseignez les paramètres ServerName (l'URL pour adresser **AROLIOS WebUI**, par exemple www.my-arolios.example.com) et DocumentRoot (l'emplacement du fichier index.html, par exemple /var/www/arolios_webui).
4. Si vous fonctionnez en mode HTTPS, renseignez dans votre fichier de configuration les lignes SSLCertificateFile et SSLCertificateKeyFile et après enregistrement passez la commande: sudo a2enmod ssl
5. Enregistrez votre site en passant la commande suivante (par exemple pour arolios.conf): sudo a2ensite arolios.conf
6. Redémarrez le serveur Apache: sudo systemctl restart apache2
4. Le serveur de l'API AROLIOS fonctionnant en mode HTTPS, chaque utilisateur potentiel doit installer dans son navigateur le certificat racine créé lors de l'installation du serveur (voir la documentation dans le dépôt **arolios-doc** ). Dans le paramétrage du navigateur, voir la rubrique des certificats, et importer votre certificat dans les autorités.
5. Si le serveur de l'API AROLIOS que vous avez renseigné dans le paramètre VITE_BACKEND_URL est lancé ainsi que votre serveur web servant **AROLIOS WebUI** (Apache par exemple), vous pouvez démarrer **AROLIOS WebUI** depuis votre navigateur web en l'adressant avec l'URL renseigné dans la configuration de votre serveur Web ( par exemple www.my-arolios.example.com).
en mode HTTPS éventuellement
En cas de difficulté, référez-vous à la documentation de votre serveur web ou aux articles disponibles sur Internet pour y déployer une application React.
......
......@@ -38,13 +38,13 @@ const About = () => {
return (
<div>
<p>AROLIOS WebUI &nbsp;{translate('arolios.WebUI_purpose')}.</p>
<p>AROLIOS WebUI &nbsp;{translate('arolios.webui_purpose')}.</p>
<p>AROLIOS &nbsp;{translate('arolios.trademark_registered')}.</p>
<p>AROLIOS WebUI &nbsp; &copy; 2024 Philippe Coicadan. {translate('arolios.all_rights_reserved')}.</p>
<p>AROLIOS WebUI &nbsp;{translate('arolios.license_intro')}</p>
<LicenseText/>
<p>{translate('arolios.source_link')}&nbsp; http://my_ repository/arolios-webui</p>
<p>{translate('arolios.source_link')}&nbsp; https://lab.frogg.it/philcoicadan/arolios-webui</p>
</div>
)
......
import { useCreatePath} from 'react-admin';
import {useNavigate } from 'react-router-dom';
import { useContext } from "react";
import { useContext , useEffect} from "react";
import { ClassifierContext} from '../../utils/contexts'
const CustomDashboard = () => {
const createPath = useCreatePath();
const navigate = useNavigate();
const {mapDomainNameResource} = useContext(ClassifierContext);
const def_dom = sessionStorage.getItem('arolios_model_default_domain') ;
useEffect(() => {
if (def_dom) {
const { name, _tname } = JSON.parse(sessionStorage.getItem('arolios_model_default_domain'));
const path = createPath({ resource: `${name}/classes`, type: 'list' });
mapDomainNameResource(name, _tname);
return navigate(path);
const def_dom = sessionStorage.getItem('arolios_model_default_domain') ;
if ( def_dom ) {
const { name, _tname} = JSON.parse(sessionStorage.getItem('arolios_model_default_domain'));
mapDomainNameResource (name, _tname);
return navigate(createPath( { resource: `${name}/classes`, type: 'list'}));
} else {
return navigate(createPath( { resource: 'domains', type: 'list' }));
}
} else {
const path = createPath({ resource: 'domains', type: 'list' });
return navigate(path);
}
}, []);
}
export default CustomDashboard;
\ No newline at end of file
import {List, Datagrid,
import {TextField, List, Datagrid,
ShowButton, EditButton, Loading, Show, Edit, SimpleShowLayout, SimpleForm,
Create, TopToolbar, ExportButton, CreateButton, SaveButton, Toolbar, DeleteWithConfirmButton, SearchInput, useTranslate, EmptyClasses} from 'react-admin';
import { useContext} from "react";
import { AssociationMemberEndContext, ClassifierContext, ClassSelectContext, ClassSelectProvider } from "../../utils/contexts";
import { AssociationMemberEndContext, ClassifierContext } from "../../utils/contexts";
import { useProperties } from "../../utils/properties";
import { InsertShowField , InsertListField, InsertEditField, concatenateIdFields} from "../../utils/fields" ;
import { useResourceContext, useResourceDefinition, useRecordContext, useCreatePath, usePermissions} from "react-admin";
import { idFromURL, extractResourceFromPathName} from "../../utils/utils";
import {useParams, useLocation} from "react-router-dom";
import {Box, Drawer, Typography} from '@mui/material';
import {Typography} from '@mui/material';
import Inbox from '@mui/icons-material/Inbox';
import { styled } from '@mui/material/styles';
import authProvider from '../../utils/authProvider';
......@@ -342,9 +342,9 @@ export const ClassInstanceList = () => {
>
{
classFunctions.unfoldProperties(properties).map ( ( prop ) => {
return InsertListField ( prop );
classFunctions.unfoldProperties(properties).map ( ( {property, prefix} ) => {
return InsertListField ( property, prefix);
} ) }
<ClassInstanceListShowButton/>
......@@ -358,57 +358,6 @@ export const ClassInstanceList = () => {
}
const SelectActions = () => (
<TopToolbar></TopToolbar>
);
export const ClassInstanceSelect = () => {
const {resource, source, open, setOpen, setSourceSelect } = useContext(ClassSelectContext);
const {properties, loading} = useProperties (resource,'classes', 'list');
return (
<Drawer
open={open}
anchor='right'
onClose= { () => setOpen(false)}
sx={{ maxWidth: 1/2}}
>
<List disableSyncWithLocation resource={resource} actions={<SelectActions />} filters={classFilters(properties, loading)} exporter={false} sort={{ field: 'id', order:"DESC"}} queryOptions={{ meta:{ prefix: 'classes', suffix: 'instances', properties: 'list'}}}>
{loading ? (
<Loading />
) : (
<Datagrid
bulkActionButtons={false}
rowClick= {(id, resource, record) => {
setSourceSelect(source, { id: record.id, display: concatenateIdFields(record)});
setOpen(false);
}
}
>
{
classFunctions.unfoldPropertiesNoLink(properties).map ( ( prop ) => {
return InsertListField ( prop );
} ) }
</Datagrid>
)
}
</List>
</Drawer>)
}
export const AssociationInstanceList = () => {
const resource = useResourceContext ();
......@@ -433,9 +382,8 @@ export const AssociationInstanceList = () => {
>
{
assocFunctions.unfoldProperties(properties).map ( ( prop ) => {
return InsertListField ( prop );
assocFunctions.unfoldProperties(properties).map ( ( {property, prefix} ) => {
return InsertListField ( property, prefix);
} ) }
<ShowButton/>
......@@ -455,8 +403,8 @@ return (
{
classFunctions.unfoldProperties(properties).map ( ( prop ) => {
return InsertShowField (prop);
classFunctions.unfoldProperties(properties).map ( ( {property, prefix} ) => {
return InsertShowField ( property, prefix);
} ) }
......@@ -514,8 +462,8 @@ export const AssocInstanceShow = () => {
<SimpleShowLayout>
{
assocFunctions.unfoldProperties(properties).map((prop) => {
return InsertShowField(prop);
assocFunctions.unfoldProperties(properties).map(({property, prefix}) => {
return InsertShowField ( property, prefix);
})}
......@@ -527,11 +475,10 @@ export const AssocInstanceShow = () => {
}
const EditToolbar = () => {
const { saveEnable } = useContext(ClassSelectContext);
const translate = useTranslate();
return (
<Toolbar>
<SaveButton alwaysEnable={saveEnable} />
<SaveButton />
<DeleteWithConfirmButton
resource='instances'
confirmContent={translate('arolios.delete_confirm_msg')}
......@@ -544,150 +491,134 @@ const EditToolbar = () => {
export const ClassInstanceEdit = () => {
const resource = useResourceContext ();
const resource = useResourceContext();
const createPath = useCreatePath();
const { classifierNames } = useContext(ClassifierContext);
const csf_name = classifierNames[resource];
const translate = useTranslate();
const {properties, loading} = useProperties (resource, 'classes', 'update');
const { properties, loading } = useProperties(resource, 'classes', 'update');
return (
<Box display="flex">
<ClassSelectProvider>
<Edit resource='instances' queryOptions={{ meta:{ context: 'rfu'}}} redirect={createPath( {resource: resource, type: 'list'})}>
<Edit title={translate('arolios.instance_of', { type: csf_name })} resource='instances' queryOptions={{ meta: { context: 'rfu' } }} redirect={createPath({ resource: resource, type: 'list' })}>
{loading ? (
<Loading />
) : (
<div>
<SimpleForm toolbar= {<EditToolbar />}>
<SimpleForm toolbar={<EditToolbar />}>
{
classFunctions.unfoldAllProperties(properties).map ( ( prop ) => {
return InsertEditField ( prop );
} ) }
{
</SimpleForm>
</div>
) }
</Edit>
classFunctions.unfoldAllProperties(properties).map(({ property, prefix }) => {
return InsertEditField(property, prefix);
})}
<ClassInstanceSelect />
</SimpleForm>
</div>
)}
</ClassSelectProvider>
</Box>)
</Edit>
)
}
export const AssocInstanceEdit = () => {
const resource = useResourceContext ();
const resource = useResourceContext();
const createPath = useCreatePath();
const {properties, loading} = useProperties (resource, 'associations', 'update');
const { properties, loading } = useProperties(resource, 'associations', 'update');
const { classifierNames } = useContext(ClassifierContext);
const csf_name = classifierNames[resource];
const translate = useTranslate();
return (
<Box display="flex">
<ClassSelectProvider>
<Edit resource='instances' queryOptions={{ meta:{ context: 'rfu'}}} redirect={createPath( {resource: resource, type: 'list'})}>
{loading ? (
<Loading />
) : (
<SimpleForm toolbar= {<EditToolbar />}>
{
assocFunctions.unfoldNotRefProperties(properties).map ( ( prop ) => {
return InsertEditField ( prop );
} ) }
<Edit title={translate('arolios.instance_of', { type: csf_name })} resource='instances' queryOptions={{ meta: { context: 'rfu' } }} redirect={createPath({ resource: resource, type: 'list' })}>
</SimpleForm>
) }
</Edit>
<ClassInstanceSelect />
{loading ? (
<Loading />
) : (
<SimpleForm toolbar={<EditToolbar />}>
</ClassSelectProvider>
</Box>)
}
{
assocFunctions.unfoldNotRefProperties(properties).map(({ property, prefix }) => {
return InsertEditField(property, prefix);
})}
const CreateToolbar = () => {
const { saveEnable } = useContext(ClassSelectContext);
return (
<Toolbar>
<SaveButton alwaysEnable={saveEnable} />
</Toolbar>
</SimpleForm>
)}
</Edit>
)
}
export const ClassInstanceCreate = () => {
const resource = useResourceContext ();
const resource = useResourceContext();
const { properties, loading } = useProperties(resource, 'classes', 'create');
const { classifierNames } = useContext(ClassifierContext);
const csf_name = classifierNames[resource];
const translate = useTranslate();
const {properties, loading} = useProperties (resource, 'classes', 'create');
return (
<Box display="flex">
<ClassSelectProvider>
<Create redirect='show' mutationOptions={{ meta:{ prefix: 'classes', suffix: 'instances'}} }>
<Create title={translate('arolios.instance_of', { type: csf_name })} redirect='show' mutationOptions={{ meta: { prefix: 'classes', suffix: 'instances' } }}>
{loading ? (
<Loading />
) : (
<div>
<SimpleForm toolbar= {<CreateToolbar />}>
{
classFunctions.unfoldAllProperties(properties).map ( ( prop ) => {
return InsertEditField ( prop );
} ) }
<SimpleForm>
</SimpleForm>
{
classFunctions.unfoldAllProperties(properties).map(({ property, prefix }) => {
return InsertEditField(property, prefix);
})}
</SimpleForm>
</div>
) }
</Create>
)}
<ClassInstanceSelect />
</Create>
</ClassSelectProvider>
</Box>)
)
}
export const AssocInstanceCreate = () => {
const resource = useResourceContext ();
const resource = useResourceContext();
const { properties, loading } = useProperties(resource, 'associations', 'create');
const { classifierNames } = useContext(ClassifierContext);
const csf_name = classifierNames[resource];
const translate = useTranslate();
const {properties, loading} = useProperties (resource, 'associations', 'create');
return (
<Box display="flex">
<ClassSelectProvider>
<Create redirect='show' mutationOptions={{ meta:{ prefix: 'associations', suffix: 'instances' }} }>
<Create title={translate('arolios.instance_of', { type: csf_name })} redirect='show' mutationOptions={{ meta: { prefix: 'associations', suffix: 'instances' } }}>
{loading ? (
<Loading />
) : (
<div>
<SimpleForm toolbar= {<CreateToolbar />}>
{
assocFunctions.unfoldAllProperties(properties).map ( ( prop ) => {
return InsertEditField ( prop );
} ) }
<SimpleForm>
</SimpleForm>
</div>
) }
</Create>
{
<ClassInstanceSelect />
assocFunctions.unfoldAllProperties(properties).map(({ property, prefix }) => {
return InsertEditField(property, prefix);
})}
</ClassSelectProvider>
</Box>)
</SimpleForm>
</div>
)}
</Create>
)
}
......@@ -720,8 +651,8 @@ export const InstanceAssocList = () => {
{
assocFunctions.unfoldProperties(properties).map ( ( prop ) => {
return InsertListField ( prop );
assocFunctions.unfoldProperties(properties).map ( ( {property,prefix }) => {
return InsertListField ( property, prefix);
} ) }
<ShowButton resource={assocResource}/>
......
......@@ -33,30 +33,6 @@ export const ClassifierProvider = ({ children }) => {
)
}
export const ClassSelectContext = createContext();
export const ClassSelectProvider = ({ children }) => {
const [resource, setResource] = useState('');
const [source, setSource] = useState('');
const [select, setSelect] =useState ({}) ;
const [open, setOpen] = useState (false);
const [saveEnable, setSaveEnable] = useState(false);
const setSourceSelect = ( key, value) => {
let newPair = {};
newPair[key] = value;
setSelect (selections => ({ ...selections, ...newPair}));
}
return (
<ClassSelectContext.Provider value={{ resource, setResource, source, setSource, open, setOpen, select, setSourceSelect, saveEnable , setSaveEnable }}>
{children}
</ClassSelectContext.Provider>
)
}
export const AssociationMemberEndContext = createContext();
export const AssociationMemberEndProvider = ( {children}) => {
......
......@@ -205,11 +205,43 @@ const CustomDataProvider = {
}
url += `${resource}/${instid}`;
return httpClient(url).then(({ headers, json }) => ({
data: json.map(record => ( {id:record.url, ...record})),
data: json.map(record => ( {id:idFromURL(record.url), ...record})),
total: 1,
}));
}
} else { // no case implemented
} else if (getmany_context === "references" ) {
const ids = params.ids;
const instid =ids[0] ;
// variant of getOne
const lang = localStorage.getItem ("arolios_model_language") || sessionStorage.getItem ("arolios_model_default_language");
let query = `?lang=${lang}`;
const querySep = '&';
const {prefix, suffix ,context } = params.meta || {};
let url = `${apiUrl}/`;
// suffix of the list query is the resource
if (suffix) {
url += `${suffix}`;
}
url += `/${instid}`;
if (context) {
query += `${querySep}c=${context}`;
}
if (query.length >0) {
url += `${query}`;
}
return httpClient(url).then(({ json }) => ({
data: [ json ],
total: 1
}));
} else { // no case implemented
const query = {
filter: JSON.stringify({ ids: params.ids }),
};
......
This diff is collapsed.
......@@ -100,7 +100,7 @@ export const en = {
user_roles: {
no: 'No role',
reader: 'Reader',
author: 'Author',
producer: 'Producer',
admin: 'Administrator'
},
password_not_identical: 'The passwords are not identical',
......
......@@ -101,7 +101,7 @@ export const fr = {
user_roles: {
no: 'Aucun rôle',
reader: 'Lecteur',
author: 'Auteur',
producer: 'Producteur',
admin: 'Administrateur'
},
password_not_identical: 'Les mots de passe ne sont pas identiques',
......
......@@ -5,7 +5,7 @@ export const roleChoices = () => {
return [
{ id: 'no', name: 'arolios.user_roles.no'},
{ id: 'reader', name: 'arolios.user_roles.reader'},
{ id: 'author', name: 'arolios.user_roles.author'},
{ id: 'producer', name: 'arolios.user_roles.producer'},
{ id: 'admin', name: 'arolios.user_roles.admin'}
]
......@@ -19,7 +19,7 @@ export const RenderRole = ( (record) => {
no: translate('arolios.user_roles.no'),
reader: translate('arolios.user_roles.reader'),
author: translate('arolios.user_roles.author'),
producer: translate('arolios.user_roles.producer'),
admin: translate('arolios.user_roles.admin')
}
return roles[record.role];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment