From 561f2d154947df8b5849438d1b9c665533c7a975 Mon Sep 17 00:00:00 2001 From: Philippe Coicadan <philcoicadan@arolios.org> Date: Mon, 30 Dec 2024 18:18:39 +0100 Subject: [PATCH] some improvements and bug fixing --- src/pages/dashboard/index.jsx | 21 +++++---- src/pages/export/index.jsx | 2 +- src/resources/instances/index.jsx | 11 ++--- src/resources/settings/index.jsx | 75 ++++++++++++++++--------------- src/resources/users/index.jsx | 2 +- src/utils/authProvider/index.jsx | 2 +- src/utils/dataProvider/index.jsx | 19 +++++++- src/utils/fields/index.jsx | 22 ++++++--- src/utils/i18nProvider/en.js | 17 +++---- src/utils/i18nProvider/fr.js | 19 ++++---- 10 files changed, 111 insertions(+), 79 deletions(-) diff --git a/src/pages/dashboard/index.jsx b/src/pages/dashboard/index.jsx index 901e4dd..fe3f93a 100644 --- a/src/pages/dashboard/index.jsx +++ b/src/pages/dashboard/index.jsx @@ -1,29 +1,32 @@ -import { useCreatePath} from 'react-admin'; +import { useCreatePath, useGetList} from 'react-admin'; import {useNavigate } from 'react-router-dom'; -import { useContext , useEffect} from "react"; +import { useContext , useEffect, useState} 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') ; + const createPath = useCreatePath(); - useEffect(() => { + const { mapDomainNameResource } = useContext(ClassifierContext); - if (def_dom) { + + + useEffect(() => { + + if (sessionStorage.getItem('arolios_model_default_domain')) { 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); - } else { const path = createPath({ resource: 'domains', type: 'list' }); return navigate(path); } - }, []); + }, []); } export default CustomDashboard; \ No newline at end of file diff --git a/src/pages/export/index.jsx b/src/pages/export/index.jsx index ed3556d..7671a03 100644 --- a/src/pages/export/index.jsx +++ b/src/pages/export/index.jsx @@ -50,7 +50,7 @@ const ExportData = () => { .then ( json => { notify ('arolios.export_success', {type: 'success', messageArgs: { title: `${data.query.title}`}}); downloadJSON (JSON.stringify(json["elements"]), "export"); - redirect (createPath( { resource: 'domains', type: 'list' })); + redirect ('/'); return Promise.resolve(); }) .catch(() => { diff --git a/src/resources/instances/index.jsx b/src/resources/instances/index.jsx index 6aed809..6448ca3 100644 --- a/src/resources/instances/index.jsx +++ b/src/resources/instances/index.jsx @@ -1,6 +1,7 @@ import { List, Datagrid, ShowButton, EditButton, Loading, Show, Edit, SimpleShowLayout, SimpleForm, - Create, TopToolbar, ExportButton, CreateButton, SaveButton, Toolbar, DeleteWithConfirmButton, SearchInput, useTranslate, EmptyClasses} from 'react-admin'; + Create, TopToolbar, ExportButton, CreateButton, SaveButton, Toolbar, DeleteWithConfirmButton, SearchInput, useTranslate, EmptyClasses, + useRecordSelection} from 'react-admin'; import { useContext} from "react"; import { AssociationMemberEndContext, ClassifierContext } from "../../utils/contexts"; import { useProperties } from "../../utils/properties"; @@ -219,7 +220,7 @@ const assocFunctions = { const classFilters = ( loading ) => { - if (loading) return []; + // if (loading) return []; const arr1 = [ <SearchInput source="_s" alwaysOn />] return arr1; @@ -474,14 +475,14 @@ export const AssocInstanceShow = () => { ) } -const EditToolbar = () => { +const EditToolbar = ( {type} ) => { const translate = useTranslate(); return ( <Toolbar> <SaveButton /> <DeleteWithConfirmButton resource='instances' - confirmContent={translate('arolios.delete_confirm_msg')} + confirmTitle = {translate('arolios.delete_confirm_title', { name : type}) } redirect='/' /> @@ -506,7 +507,7 @@ export const ClassInstanceEdit = () => { <Loading /> ) : ( <div> - <SimpleForm toolbar={<EditToolbar />}> + <SimpleForm toolbar={<EditToolbar type={csf_name} />}> { diff --git a/src/resources/settings/index.jsx b/src/resources/settings/index.jsx index f749531..3cf8848 100644 --- a/src/resources/settings/index.jsx +++ b/src/resources/settings/index.jsx @@ -1,6 +1,6 @@ -import { Toolbar, SaveButton, PasswordInput, Create, Edit, SimpleForm, SelectInput, required , ReferenceInput, TopToolbar, useNotify, useRedirect} from "react-admin"; +import { Toolbar, SaveButton, PasswordInput, Create, Edit, SimpleForm, SelectInput, required, ReferenceInput, TopToolbar, useNotify, useRedirect} from "react-admin"; import * as MUI from '@mui/material'; -import { useCreatePath, useTranslate } from "react-admin"; +import { useCreatePath, useTranslate} from "react-admin"; import { useNavigate } from 'react-router-dom'; @@ -20,20 +20,20 @@ export const PasswordCreate = () => { } return ( - - - <Create title="arolios.change_password" mutationOptions={{ onSuccess }} > - - <SimpleForm> - - <PasswordInput label="arolios.current_password" source="current_password" fullWidth validate={required()}/> - <PasswordInput label="arolios.new_password" source="new_password" fullWidth validate={required()}/> - <PasswordInput label="arolios.confirm_password" source="confirm_password" fullWidth validate={[required(), equalToNewPassword]}/> - </SimpleForm> + <Create title="arolios.change_password" mutationOptions={{ onSuccess }} > - </Create> + <SimpleForm> + + <PasswordInput label="arolios.current_password" source="current_password" fullWidth validate={required()} /> + <PasswordInput label="arolios.new_password" source="new_password" fullWidth validate={required()} /> + <PasswordInput label="arolios.confirm_password" source="confirm_password" fullWidth validate={[required(), equalToNewPassword]} /> + + + </SimpleForm> + + </Create> ) } @@ -46,47 +46,50 @@ const ChangePasswordButton = () => { const link = createPath({ type: 'create', resource: 'password' - }); - + }); + navigate(link); }; - return (<MUI.Link component="button" variant="body2" onClick={handleClick} >{translate('arolios.change_password')}</MUI.Link>); + return (<MUI.Link component="button" variant="body2" onClick={handleClick} >{translate('arolios.change_password')}</MUI.Link>); } - const SettingActions = () => ( +const SettingActions = () => ( <TopToolbar> <ChangePasswordButton /> </TopToolbar> - ) +) + - const EditToolbar = () => { +const EditToolbar = () => { return ( <Toolbar> - <SaveButton /> + <SaveButton /> </Toolbar> ) } + export const SettingsEdit = () => { const translate = useTranslate(); + return ( - - - <Edit title={translate('resources.settings.name',2)} actions={<SettingActions />} redirect={false} mutationOptions={{ meta:{ prefix: 'settings' }}} queryOptions={{ meta:{ prefix: 'settings', context: 'rfu'}}}> - - <SimpleForm toolbar= {<EditToolbar />}> - - <ReferenceInput source="model_language" reference="languages" sort={{field: 'code', order: 'ASC'}} queryOptions={{ meta:{ getmany_context: 'languages'} }}> - <SelectInput label= "arolios.model_language" optionText="name" optionValue="code" validate={required()}/> - </ReferenceInput> - - </SimpleForm> - - - </Edit>) - - + + + <Edit title={translate('resources.settings.name', 2)} actions={<SettingActions />} redirect={false} mutationOptions={{ meta: { prefix: 'settings' } }} mutationMode="pessimistic" queryOptions={{ meta: { prefix: 'settings', context: 'rfu' } } }> + + <SimpleForm toolbar={<EditToolbar />}> + + <ReferenceInput source="model_language" reference="languages" sort={{ field: 'code', order: 'ASC' }} queryOptions={{ meta: { getmany_context: 'languages' } }}> + <SelectInput label="arolios.model_language" optionText="name" optionValue="code" validate={required()} /> + </ReferenceInput> + + </SimpleForm> + + + </Edit>) + + } diff --git a/src/resources/users/index.jsx b/src/resources/users/index.jsx index 5876e69..c640d70 100644 --- a/src/resources/users/index.jsx +++ b/src/resources/users/index.jsx @@ -75,7 +75,7 @@ export const UserCreate = () => { return ( - <Create> + <Create redirect="list"> <SimpleForm> <TextInput label="arolios.user_identifier" source="identifier" multiline fullWidth resettable validate={required()}/> diff --git a/src/utils/authProvider/index.jsx b/src/utils/authProvider/index.jsx index ff87c4d..d32d3ea 100644 --- a/src/utils/authProvider/index.jsx +++ b/src/utils/authProvider/index.jsx @@ -79,7 +79,7 @@ const authProvider = { }, canEdit: (role) => { - return role === 'admin' || role === 'author' ; + return role === 'admin' || role === 'producer' ; } }; diff --git a/src/utils/dataProvider/index.jsx b/src/utils/dataProvider/index.jsx index b691612..002e6db 100644 --- a/src/utils/dataProvider/index.jsx +++ b/src/utils/dataProvider/index.jsx @@ -43,7 +43,11 @@ const CustomDataProvider = { querySep = '&'; } if (field) { - query +=`${querySep}s=${field}`; + //eliminate field translation + const field_arr1 = field.split('.'); + const field_arr2 = field_arr1.map ( (item) => ( item.startsWith ('_t')) ? item.substring(2) : item); + const true_field = field_arr2.join('.'); + query +=`${querySep}s=${true_field}`; querySep = '&'; } if (order) { @@ -316,7 +320,18 @@ const CustomDataProvider = { const {prefix, suffix ,context } = params.meta || {}; if (prefix === 'settings') { - localStorage.setItem("arolios_model_language", params.data.model_language); + localStorage.setItem("arolios_model_language", params.data.model_language); + + const url = `${apiUrl}/domains?lang=${params.data.model_language}` + httpClient(url).then(({ headers, json }) => { + if (json["total"] === 1) { + sessionStorage.setItem('arolios_model_default_domain', JSON.stringify({ name: json["elements"][0]['name'], _tname: json["elements"][0]['_tname'] })); + } else { + sessionStorage.removeItem('arolios_model_default_domain'); + }; + + }); + return Promise.resolve({data: params.data}); } let url = `${apiUrl}/`; diff --git a/src/utils/fields/index.jsx b/src/utils/fields/index.jsx index e29edb0..d35e7dd 100644 --- a/src/utils/fields/index.jsx +++ b/src/utils/fields/index.jsx @@ -65,8 +65,9 @@ const MemberEndShowButton = ( {resource, resourceDisplay, prefix, field, sx }) = export const concatenateIdFieldValues = ( record ) => { let allIdFields = "" ; + let enumFields = []; for (const [key, value] of Object.entries(record.properties)) { - if (key[0] !== '_') { + // if (key[0] !== '_') { if (value instanceof Object) { if (value.hasOwnProperty("properties")) { // linked prop allIdFields= allIdFields.concat(" ", concatenateIdFieldValues(record['properties'][key])); @@ -77,10 +78,13 @@ export const concatenateIdFieldValues = ( record ) => { } } } - } else { + } else if (key.startsWith ("_t") ){ + allIdFields = allIdFields.concat(" ", String(value)); + enumFields.push(key.substring(2)); + } else if ( enumFields.indexOf( key ) === -1) { allIdFields = allIdFields.concat(" ", String(value)); } - } + // } } allIdFields = allIdFields.trim(); return allIdFields; @@ -207,8 +211,10 @@ export const InsertListField = ( property, prefix) => { }; } case "_enumeration": - return (<TextField key={`${prefix}.${property.id_name}`} label={property._tpathname} source={source} />); - + { + const source_enum = `${prefix}._t${property.id_name}`; + return (<TextField key={`${prefix}.${property.id_name}`} label={property._tpathname} source={source_enum} />); + } case "_composite_type": break; case "_class": @@ -251,8 +257,10 @@ export const InsertShowField = (property, prefix) => { }; } case "_enumeration": - return (<TextField key={`${prefix}.${property.id_name}`} label={property._tpathname} source={source} />); - + { + const source_enum = `${prefix}._t${property.id_name}`; + return (<TextField key={`${prefix}.${property.id_name}`} label={property._tpathname} source={source_enum} />); + } case "_composite_type": break; diff --git a/src/utils/i18nProvider/en.js b/src/utils/i18nProvider/en.js index 90bbcb2..6f3286e 100644 --- a/src/utils/i18nProvider/en.js +++ b/src/utils/i18nProvider/en.js @@ -62,22 +62,22 @@ export const en = { model_loading: 'Data model loading', translation_loading: 'Translations loading', data_loading: 'Data loading', - delete_confirm_msg: 'Do you confirm the deletion?', + delete_confirm_title: 'Delete %{name}', classifier: 'Classifier', - list_of: '%{type}: List of data', - instance_of: 'Instance of %{type}', + list_of: '%{type}: List of items', + instance_of: 'Item of %{type}', trash_contents: "Trash contents", empty_trash: "Empty the trash", empty_trash_success: "Trash emptied successfully", empty_trash_error: "Error while emptying the trash : %{message}", recover: "Recover", - recover_success: "Data recovered successfully", - recover_error: "Error while recovering data: %{message}", + recover_success: "Item(s) recovered successfully", + recover_error: "Error while recovering item(s): %{message}", eliminate: "Delete", eliminate_title: "Delete definitively", - eliminate_confirm_msg: "You will not be able to recover these data. Are you sure ?", - empty_trash_title: "Delete definitively the data contained in the trash", - empty_trash_confirm_msg: "You will not be able to recover the data contained in the trash. Are you sure ?", + eliminate_confirm_msg: "You will not be able to recover this item. Are you sure ?", + empty_trash_title: "Delete definitively the items contained in the trash", + empty_trash_confirm_msg: "You will not be able to recover the items contained in the trash. Are you sure ?", code: "Code", model_language: "Model language", version: "Version", @@ -108,6 +108,7 @@ export const en = { current_password: 'Current password', new_password: 'New password', password_updated: 'password updated', + settings_updated: 'settings updated', value: 'Value' }, } diff --git a/src/utils/i18nProvider/fr.js b/src/utils/i18nProvider/fr.js index 6330f91..cd39d18 100644 --- a/src/utils/i18nProvider/fr.js +++ b/src/utils/i18nProvider/fr.js @@ -63,22 +63,22 @@ export const fr = { model_loading: 'Chargement du modèle de données', translation_loading: 'Chargement de traductions', data_loading: 'Chargement de données', - delete_confirm_msg: 'Confirmez-vous la suppression?', + delete_confirm_title: 'Supprimer %{name}', classifier: 'Classifieur', - list_of: '%{type}: Liste de données', - instance_of: 'Instance de %{type}', + list_of: "%{type}: Liste d'éléments", + instance_of: 'Element de %{type}', trash_contents: "Contenu de la corbeille", empty_trash: "Vider la corbeille", empty_trash_success: "Corbeille vidée", empty_trash_error: "Erreur en vidant la corbeille : %{message}", - recover: "Restaurer", - recover_success: "Donnée(s) restaurée(s)", - recover_error: "Erreur dans la restauration de donnée(s): %{message}", + recover: "Récuperer", + recover_success: "Donnée(s) récupérée(s)", + recover_error: "Erreur dans la récupération de donnée(s): %{message}", eliminate: "Supprimer", eliminate_title: "Supprimer definitivement", - eliminate_confirm_msg: "Vous ne pourrez pas récupérer ces données. Etes-vous sûr ?", - empty_trash_title: "Supprimer définitivement les données contenues dans la corbeille", - empty_trash_confirm_msg: "Vous ne pourrez pas récupérer les données contenues dans la corbeille. Etes-vous sûr ?", + eliminate_confirm_msg: "Vous ne pourrez pas récupérer cet élément. Etes-vous sûr ?", + empty_trash_title: "Supprimer définitivement les éléments contenus dans la corbeille", + empty_trash_confirm_msg: "Vous ne pourrez pas récupérer les éléments contenus dans la corbeille. Etes-vous sûr ?", code: "Code", model_language: "Langue du modèle", version: "Version", @@ -109,6 +109,7 @@ export const fr = { current_password: 'mot de passe actuel', new_password: 'nouveau mot de passe', password_updated: 'mot de passe modifié', + settings_updated: 'réglages modifiés', value: 'Valeur' }, } -- GitLab