diff --git a/.eslintrc b/.eslintrc index fa53483ad..d53576901 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,7 +10,14 @@ "jsx-a11y/href-no-hash": 0, "no-useless-escape": "off", "no-duplicate-imports": "error", - "import/no-anonymous-default-export": 0 + "import/no-anonymous-default-export": 0, + "testing-library/no-container": 0, + "testing-library/no-node-access": 0, + "testing-library/render-result-naming-convention": 0, + "testing-library/prefer-screen-queries": 0, + "testing-library/prefer-presence-queries": 0, + "testing-library/no-unnecessary-act": 0, + "testing-library/no-wait-for-multiple-assertions": 0 }, "settings": { "react": { diff --git a/app/package.json b/app/package.json index f07468cdd..1778fa05e 100755 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "Bauhaus", - "version": "3.0.12", + "version": "3.0.13", "description": "Web application for the management of concepts, classifications and other statistical objects", "repository": { "type": "git", diff --git a/app/src/js/actions/collections/collection.js b/app/src/js/actions/collections/collection.js deleted file mode 100644 index 1c033bea6..000000000 --- a/app/src/js/actions/collections/collection.js +++ /dev/null @@ -1,7 +0,0 @@ -import loadMembers from './members'; -import loadGeneral from './general'; - -export default id => dispatch => { - //handy to return a promise in case we want to chain other actions - return Promise.all([dispatch(loadGeneral(id)), dispatch(loadMembers(id))]); -}; diff --git a/app/src/js/actions/collections/create.js b/app/src/js/actions/collections/create.js deleted file mode 100644 index 6154552b6..000000000 --- a/app/src/js/actions/collections/create.js +++ /dev/null @@ -1,23 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default collection => dispatch => { - dispatch({ - type: A.CREATE_COLLECTION, - payload: { - collection, - }, - }); - return api.postCollection(collection).then( - id => - dispatch({ - type: A.CREATE_COLLECTION_SUCCESS, - payload: { id, collection }, - }), - err => - dispatch({ - type: A.CREATE_COLLECTION_FAILURE, - payload: { err, collection }, - }) - ); -}; diff --git a/app/src/js/actions/collections/export-multi.js b/app/src/js/actions/collections/export-multi.js deleted file mode 100644 index 758fc1e53..000000000 --- a/app/src/js/actions/collections/export-multi.js +++ /dev/null @@ -1,38 +0,0 @@ -import exportOne from './export-one'; -import * as A from '../constants'; - -export default (ids, MimeType) => dispatch => { - dispatch({ - type: A.EXPORT_COLLECTION_LIST, - paylaod: { - ids, - MimeType, - }, - }); - return Promise.all(ids.map(id => dispatch(exportOne(id, MimeType)))).then( - ([...blobs]) => { - dispatch({ - type: A.EXPORT_COLLECTION_LIST_SUCCESS, - payload: { - ids, - MimeType, - blobs, - }, - }); - return Promise.resolve({ - ids, - MimeType, - blobs, - }); - }, - err => - dispatch({ - type: A.EXPORT_COLLECTION_LIST_FAILURE, - payload: { - err, - ids, - MimeType, - }, - }) - ); -}; diff --git a/app/src/js/actions/collections/export-one.js b/app/src/js/actions/collections/export-one.js deleted file mode 100644 index 6ebd3bfd2..000000000 --- a/app/src/js/actions/collections/export-one.js +++ /dev/null @@ -1,33 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { getContentDisposition } from '@inseefr/wilco'; -import FileSaver from 'file-saver'; - -export default (id, MimeType) => dispatch => { - var fileName = ''; - dispatch({ - type: A.EXPORT_COLLECTION, - payload: { id, MimeType }, - }); - return api - .getCollectionExport(id, MimeType) - .then( - res => { - dispatch({ type: A.EXPORT_COLLECTION_SUCCESS }); - //we do not want to save the pdf within the reducer, so we return - //it in order to process it later - return res; - }, - err => dispatch({ type: A.EXPORT_COLLECTION_FAILURE, payload: { err } }) - ) - .then(res => { - fileName = getContentDisposition( - res.headers.get('Content-Disposition') - )[1]; - return res; - }) - .then(res => res.blob()) - .then(blob => { - return FileSaver.saveAs(blob, fileName); - }); -}; diff --git a/app/src/js/actions/collections/general.js b/app/src/js/actions/collections/general.js deleted file mode 100644 index b8d1cd949..000000000 --- a/app/src/js/actions/collections/general.js +++ /dev/null @@ -1,25 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default id => dispatch => { - dispatch({ - type: A.LOAD_COLLECTION_GENERAL, - payload: { - id, - }, - }); - return api.getCollectionGeneral(id).then( - results => { - dispatch({ - type: A.LOAD_COLLECTION_GENERAL_SUCCESS, - payload: { id, results }, - }); - return results; - }, - err => - dispatch({ - type: A.LOAD_COLLECTION_GENERAL_FAILURE, - payload: { err, id }, - }) - ); -}; diff --git a/app/src/js/actions/collections/list.js b/app/src/js/actions/collections/list.js deleted file mode 100644 index 71cd1e944..000000000 --- a/app/src/js/actions/collections/list.js +++ /dev/null @@ -1,18 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { ArrayUtils } from 'bauhaus-utilities'; - -export default () => dispatch => { - dispatch({ - type: A.LOAD_COLLECTION_LIST, - payload: {}, - }); - return api.getCollectionList().then( - results => - dispatch({ - type: A.LOAD_COLLECTION_LIST_SUCCESS, - payload: { results: ArrayUtils.sortArrayByLabel(results) }, - }), - err => dispatch({ type: A.LOAD_COLLECTION_LIST_FAILURE, payload: { err } }) - ); -}; diff --git a/app/src/js/actions/collections/members.js b/app/src/js/actions/collections/members.js deleted file mode 100644 index b5e377a18..000000000 --- a/app/src/js/actions/collections/members.js +++ /dev/null @@ -1,25 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default id => dispatch => { - dispatch({ - type: A.LOAD_COLLECTION_MEMBERS, - payload: { - id, - }, - }); - return api.getCollectionMembersList(id).then( - results => { - dispatch({ - type: A.LOAD_COLLECTION_MEMBERS_SUCCESS, - payload: { id, results }, - }); - return results; - }, - err => - dispatch({ - type: A.LOAD_COLLECTION_MEMBERS_FAILURE, - payload: { err, id }, - }) - ); -}; diff --git a/app/src/js/actions/collections/send.js b/app/src/js/actions/collections/send.js deleted file mode 100644 index 09b80de41..000000000 --- a/app/src/js/actions/collections/send.js +++ /dev/null @@ -1,20 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default (id, mailInfo) => dispatch => { - dispatch({ - type: A.SEND_COLLECTION, - payload: { - mailInfo, - }, - }); - return api.postCollectionSend(id, mailInfo).then( - id => - dispatch({ type: A.SEND_COLLECTION_SUCCESS, payload: { id, mailInfo } }), - err => - dispatch({ - type: A.SEND_COLLECTION_FAILURE, - payload: { err, id, mailInfo }, - }) - ); -}; diff --git a/app/src/js/actions/collections/update.js b/app/src/js/actions/collections/update.js deleted file mode 100644 index 372a87b14..000000000 --- a/app/src/js/actions/collections/update.js +++ /dev/null @@ -1,25 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default (id, collection) => dispatch => { - dispatch({ - type: A.UPDATE_COLLECTION, - payload: { - id, - collection, - }, - }); - return api.putCollection(id, collection).then( - res => { - dispatch({ - type: A.UPDATE_COLLECTION_SUCCESS, - payload: { id, collection }, - }); - }, - err => - dispatch({ - type: A.UPDATE_COLLECTION_FAILURE, - payload: { err, id, collection }, - }) - ); -}; diff --git a/app/src/js/actions/collections/validate-list.js b/app/src/js/actions/collections/validate-list.js deleted file mode 100644 index 58368f5fd..000000000 --- a/app/src/js/actions/collections/validate-list.js +++ /dev/null @@ -1,22 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { ArrayUtils } from 'bauhaus-utilities'; - -export default () => dispatch => { - dispatch({ - type: A.LOAD_COLLECTION_VALIDATE_LIST, - payload: {}, - }); - return api.getCollectionValidateList().then( - results => - dispatch({ - type: A.LOAD_COLLECTION_VALIDATE_LIST_SUCCESS, - payload: { results: ArrayUtils.sortArrayByLabel(results) }, - }), - err => - dispatch({ - type: A.LOAD_COLLECTION_VALIDATE_LIST_FAILURE, - payload: { err }, - }) - ); -}; diff --git a/app/src/js/actions/collections/validate.js b/app/src/js/actions/collections/validate.js deleted file mode 100644 index a31a6826e..000000000 --- a/app/src/js/actions/collections/validate.js +++ /dev/null @@ -1,23 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default ids => dispatch => { - dispatch({ - type: A.VALIDATE_COLLECTION_LIST, - payload: { - ids, - }, - }); - return api.putCollectionValidList(ids).then( - res => - dispatch({ - type: A.VALIDATE_COLLECTION_LIST_SUCCESS, - payload: { ids }, - }), - err => - dispatch({ - type: A.VALIDATE_COLLECTION_LIST_FAILURE, - payload: { err, ids }, - }) - ); -}; diff --git a/app/src/js/actions/concepts/concept-and-all-notes.js b/app/src/js/actions/concepts/concept-and-all-notes.js deleted file mode 100644 index dd614c384..000000000 --- a/app/src/js/actions/concepts/concept-and-all-notes.js +++ /dev/null @@ -1,11 +0,0 @@ -import loadGeneral from './general'; -import loadLinks from './links'; -import loadAllNotes from './notes-all'; - -export default id => dispatch => - dispatch(loadGeneral(id)) - .then(general => { - const { conceptVersion } = general; - dispatch(loadAllNotes(id, Number(conceptVersion))); - }) - .then(() => dispatch(loadLinks(id))); diff --git a/app/src/js/actions/concepts/concept.js b/app/src/js/actions/concepts/concept.js deleted file mode 100644 index 2553a0b6b..000000000 --- a/app/src/js/actions/concepts/concept.js +++ /dev/null @@ -1,11 +0,0 @@ -import loadLinks from './links'; -import loadNotes from './notes-version'; -import loadGeneral from './general'; - -export default id => dispatch => - Promise.all([ - dispatch(loadGeneral(id)).then(({ conceptVersion }) => - dispatch(loadNotes(id, conceptVersion)) - ), - dispatch(loadLinks(id)), - ]); diff --git a/app/src/js/actions/concepts/create.js b/app/src/js/actions/concepts/create.js deleted file mode 100644 index af21219b3..000000000 --- a/app/src/js/actions/concepts/create.js +++ /dev/null @@ -1,19 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default concept => dispatch => { - dispatch({ - type: A.CREATE_CONCEPT, - payload: { - concept, - }, - }); - return api - .postConcept(concept) - .then( - id => - dispatch({ type: A.CREATE_CONCEPT_SUCCESS, payload: { id, concept } }), - err => - dispatch({ type: A.CREATE_CONCEPT_FAILURE, payload: { err, concept } }) - ); -}; diff --git a/app/src/js/actions/concepts/delete.js b/app/src/js/actions/concepts/delete.js deleted file mode 100644 index 11a06ceaa..000000000 --- a/app/src/js/actions/concepts/delete.js +++ /dev/null @@ -1,24 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default id => dispatch => { - dispatch({ - type: A.DELETE_CONCEPT, - payload: { - id, - }, - }); - return api.deleteConcept(id).then( - res => { - dispatch({ - type: A.DELETE_CONCEPT_SUCCESS, - payload: { id }, - }); - }, - err => - dispatch({ - type: A.DELETE_CONCEPT_FAILURE, - payload: { err, id }, - }) - ); -}; diff --git a/app/src/js/actions/concepts/delete.spec.js b/app/src/js/actions/concepts/delete.spec.js deleted file mode 100644 index 7ef99c027..000000000 --- a/app/src/js/actions/concepts/delete.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import remove from './delete'; -import * as A from 'js/actions/constants'; -import api from 'js/remote-api/concepts-api'; - -const dispatch = jest.fn(); -jest.mock('js/remote-api/concepts-api'); - -describe('Concepts actions', () => { - it('should call dispatch DELETE_CONCEPT_SUCCESS action with the sorted array', async () => { - api.deleteConcept = function() { - return Promise.resolve([{ label: 'bbb' }, { label: 'aaa' }]); - }; - await remove(1)(dispatch); - expect(dispatch).toHaveBeenCalledWith({ - type: A.DELETE_CONCEPT, - payload: { id: 1 }, - }); - expect(dispatch).toHaveBeenLastCalledWith({ - type: A.DELETE_CONCEPT_SUCCESS, - payload: { id: 1 }, - }); - }); - - it('should call dispatch DELETE_CONCEPT_FAILURE action with an error object', async () => { - api.deleteConcept = function() { - return Promise.reject('error'); - }; - await remove(1)(dispatch); - expect(dispatch).toHaveBeenCalledWith({ - type: A.DELETE_CONCEPT, - payload: { id: 1 }, - }); - expect(dispatch).toHaveBeenLastCalledWith({ - type: A.DELETE_CONCEPT_FAILURE, - payload: { err: 'error', id: 1 }, - }); - }); -}); diff --git a/app/src/js/actions/concepts/export-multi.js b/app/src/js/actions/concepts/export-multi.js deleted file mode 100644 index 6a53b98f0..000000000 --- a/app/src/js/actions/concepts/export-multi.js +++ /dev/null @@ -1,38 +0,0 @@ -import exportOne from './export-one'; -import * as A from '../constants'; - -export default (ids, MimeType) => dispatch => { - dispatch({ - type: A.EXPORT_CONCEPT_LIST, - payload: { - ids, - MimeType, - }, - }); - return Promise.all(ids.map(id => dispatch(exportOne(id, MimeType)))).then( - ([...blobs]) => { - dispatch({ - type: A.EXPORT_CONCEPT_LIST_SUCCESS, - payload: { - ids, - MimeType, - blobs, - }, - }); - return Promise.resolve({ - ids, - MimeType, - blobs, - }); - }, - err => - dispatch({ - type: A.EXPORT_CONCEPT_LIST_FAILURE, - payload: { - err, - ids, - MimeType, - }, - }) - ); -}; diff --git a/app/src/js/actions/concepts/export-one.js b/app/src/js/actions/concepts/export-one.js deleted file mode 100644 index f585076f2..000000000 --- a/app/src/js/actions/concepts/export-one.js +++ /dev/null @@ -1,33 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { getContentDisposition } from '@inseefr/wilco'; -import FileSaver from 'file-saver'; - -export default (id, MimeType) => dispatch => { - var fileName = ''; - dispatch({ - type: A.EXPORT_CONCEPT, - payload: { id, MimeType }, - }); - return api - .getConceptExport(id, MimeType) - .then( - res => { - dispatch({ type: A.EXPORT_CONCEPT_SUCCESS }); - //we do not want to save the pdf within the reducer, so we return - //it in order to process it later - return res; - }, - err => dispatch({ type: A.EXPORT_CONCEPT_FAILURE, payload: { err } }) - ) - .then(res => { - fileName = getContentDisposition( - res.headers.get('Content-Disposition') - )[1]; - return res; - }) - .then(res => res.blob()) - .then(blob => { - return FileSaver.saveAs(blob, fileName); - }); -}; diff --git a/app/src/js/actions/concepts/general.js b/app/src/js/actions/concepts/general.js deleted file mode 100644 index 70c596ed7..000000000 --- a/app/src/js/actions/concepts/general.js +++ /dev/null @@ -1,22 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default id => dispatch => { - dispatch({ - type: A.LOAD_CONCEPT_GENERAL, - payload: { - id, - }, - }); - return api.getConceptGeneral(id).then( - results => { - dispatch({ - type: A.LOAD_CONCEPT_GENERAL_SUCCESS, - payload: { id, results }, - }); - return results; - }, - err => - dispatch({ type: A.LOAD_CONCEPT_GENERAL_FAILURE, payload: { err, id } }) - ); -}; diff --git a/app/src/js/actions/concepts/links.js b/app/src/js/actions/concepts/links.js deleted file mode 100644 index a9dcbcba4..000000000 --- a/app/src/js/actions/concepts/links.js +++ /dev/null @@ -1,22 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default id => dispatch => { - dispatch({ - type: A.LOAD_CONCEPT_LINKS, - payload: { - id, - }, - }); - return api.getConceptLinkList(id).then( - results => { - dispatch({ - type: A.LOAD_CONCEPT_LINKS_SUCCESS, - payload: { id, results }, - }); - return results; - }, - err => - dispatch({ type: A.LOAD_CONCEPT_LINKS_FAILURE, payload: { err, id } }) - ); -}; diff --git a/app/src/js/actions/concepts/list.js b/app/src/js/actions/concepts/list.js deleted file mode 100755 index cb3c0deff..000000000 --- a/app/src/js/actions/concepts/list.js +++ /dev/null @@ -1,18 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { ArrayUtils } from 'bauhaus-utilities'; - -export default () => dispatch => { - dispatch({ - type: A.LOAD_CONCEPT_LIST, - payload: {}, - }); - return api.getConceptList().then( - results => - dispatch({ - type: A.LOAD_CONCEPT_LIST_SUCCESS, - payload: { results: ArrayUtils.sortArrayByLabel(results) }, - }), - err => dispatch({ type: A.LOAD_CONCEPT_LIST_FAILURE, payload: { err } }) - ); -}; diff --git a/app/src/js/actions/concepts/list.spec.js b/app/src/js/actions/concepts/list.spec.js deleted file mode 100644 index a18fb8ec6..000000000 --- a/app/src/js/actions/concepts/list.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import get from './list'; -import * as A from 'js/actions/constants'; -import api from 'js/remote-api/concepts-api'; - -const dispatch = jest.fn(); -jest.mock('js/remote-api/concepts-api'); - -describe('Concepts actions', () => { - it('should call dispatch LOAD_CONCEPT_LIST_SUCCESS action with the sorted array', async () => { - api.getConceptList = function() { - return Promise.resolve([{ label: 'bbb' }, { label: 'aaa' }]); - }; - await get()(dispatch); - expect(dispatch).toHaveBeenCalledWith({ - type: A.LOAD_CONCEPT_LIST, - payload: {}, - }); - expect(dispatch).toHaveBeenLastCalledWith({ - type: A.LOAD_CONCEPT_LIST_SUCCESS, - payload: { results: [{ label: 'aaa' }, { label: 'bbb' }] }, - }); - }); - - it('should call dispatch LOAD_CONCEPT_LIST_FAILURE action with an error object', async () => { - api.getConceptList = function() { - return Promise.reject('error'); - }; - await get()(dispatch); - expect(dispatch).toHaveBeenCalledWith({ - type: A.LOAD_CONCEPT_LIST, - payload: {}, - }); - expect(dispatch).toHaveBeenLastCalledWith({ - type: A.LOAD_CONCEPT_LIST_FAILURE, - payload: { err: 'error' }, - }); - }); -}); diff --git a/app/src/js/actions/concepts/notes-all.js b/app/src/js/actions/concepts/notes-all.js deleted file mode 100644 index f801c2100..000000000 --- a/app/src/js/actions/concepts/notes-all.js +++ /dev/null @@ -1,25 +0,0 @@ -import { ArrayUtils } from 'bauhaus-utilities'; -import * as A from '../constants'; -import loadNotesVersion from './notes-version'; - -export default (id, lastVersion) => dispatch => { - dispatch({ - type: A.LOAD_NOTES_ALL, - id, - lastVersion, - }); - return Promise.all( - // Add 1 because of range behaviour - ArrayUtils.range(1, lastVersion + 1).map(version => - dispatch(loadNotesVersion(id, version)) - ) - ).then( - results => - dispatch({ - type: A.LOAD_NOTES_ALL_SUCCESS, - id, - lastVersion, - }), - err => dispatch({ type: A.LOAD_NOTES_ALL_FAILURE, id, lastVersion, err }) - ); -}; diff --git a/app/src/js/actions/concepts/notes-version.js b/app/src/js/actions/concepts/notes-version.js deleted file mode 100644 index 3cb7dafab..000000000 --- a/app/src/js/actions/concepts/notes-version.js +++ /dev/null @@ -1,39 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import { HTMLUtils } from 'bauhaus-utilities'; -import { emptyNotes } from 'js/utils/concepts/notes'; -import * as A from '../constants'; - -export default (id, version) => dispatch => { - dispatch({ - type: A.LOAD_NOTES_VERSION, - payload: { - id, - version, - }, - }); - return api.getNoteVersionList(id, version).then( - notes => - dispatch({ - type: A.LOAD_NOTES_VERSION_SUCCESS, - payload: { - id, - version, - results: Object.assign( - {}, - emptyNotes, - Object.keys(notes).reduce((formatted, noteName) => { - formatted[noteName] = HTMLUtils.rmesHtmlToRawHtml( - notes[noteName] - ); - return formatted; - }, {}) - ), - }, - }), - err => - dispatch({ - type: A.LOAD_NOTES_VERSION_FAILURE, - payload: { err, id, version }, - }) - ); -}; diff --git a/app/src/js/actions/concepts/search-list.js b/app/src/js/actions/concepts/search-list.js deleted file mode 100755 index 7fd8e2890..000000000 --- a/app/src/js/actions/concepts/search-list.js +++ /dev/null @@ -1,37 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -import { ArrayUtils } from 'bauhaus-utilities'; - -const emptyItem = { - id: '', - label: '', - created: '', - modified: '', - disseminationStatus: '', - validationStatus: '', - definition: '', - creator: '', - isTopConceptOf: '', - valid: '', -}; - -export default () => dispatch => { - dispatch({ - type: A.LOAD_CONCEPT_SEARCH_LIST, - payload: {}, - }); - return api.getConceptSearchList().then( - results => - dispatch({ - type: A.LOAD_CONCEPT_SEARCH_LIST_SUCCESS, - payload: { - results: ArrayUtils.sortArrayByLabel(results).map(concept => - Object.assign({}, emptyItem, concept) - ), - }, - }), - err => - dispatch({ type: A.LOAD_CONCEPT_SEARCH_LIST_FAILURE, payload: { err } }) - ); -}; diff --git a/app/src/js/actions/concepts/send.js b/app/src/js/actions/concepts/send.js deleted file mode 100644 index d4ef3107d..000000000 --- a/app/src/js/actions/concepts/send.js +++ /dev/null @@ -1,19 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default (id, mailInfo) => dispatch => { - dispatch({ - type: A.SEND_CONCEPT, - payload: { - mailInfo, - }, - }); - return api.postConceptSend(id, mailInfo).then( - id => dispatch({ type: A.SEND_CONCEPT_SUCCESS, payload: { id, mailInfo } }), - err => - dispatch({ - type: A.SEND_CONCEPT_FAILURE, - payload: { err, id, mailInfo }, - }) - ); -}; diff --git a/app/src/js/actions/concepts/update.js b/app/src/js/actions/concepts/update.js deleted file mode 100644 index 4a0d62d9a..000000000 --- a/app/src/js/actions/concepts/update.js +++ /dev/null @@ -1,25 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default (id, concept) => dispatch => { - dispatch({ - type: A.UPDATE_CONCEPT, - payload: { - id, - concept, - }, - }); - return api.putConcept(id, concept).then( - res => { - dispatch({ - type: A.UPDATE_CONCEPT_SUCCESS, - payload: { id, concept }, - }); - }, - err => - dispatch({ - type: A.UPDATE_CONCEPT_FAILURE, - payload: { err, id, concept }, - }) - ); -}; diff --git a/app/src/js/actions/concepts/validate-list.js b/app/src/js/actions/concepts/validate-list.js deleted file mode 100644 index 80c6e4bcf..000000000 --- a/app/src/js/actions/concepts/validate-list.js +++ /dev/null @@ -1,19 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { ArrayUtils } from 'bauhaus-utilities'; - -export default () => dispatch => { - dispatch({ - type: A.LOAD_CONCEPT_VALIDATE_LIST, - payload: {}, - }); - return api.getConceptValidateList().then( - results => - dispatch({ - type: A.LOAD_CONCEPT_VALIDATE_LIST_SUCCESS, - payload: { results: ArrayUtils.sortArrayByLabel(results) }, - }), - err => - dispatch({ type: A.LOAD_CONCEPT_VALIDATE_LIST_FAILURE, payload: { err } }) - ); -}; diff --git a/app/src/js/actions/concepts/validate.js b/app/src/js/actions/concepts/validate.js deleted file mode 100644 index 990193208..000000000 --- a/app/src/js/actions/concepts/validate.js +++ /dev/null @@ -1,20 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; - -export default ids => dispatch => { - dispatch({ - type: A.VALIDATE_CONCEPT_LIST, - payload: { - ids, - }, - }); - return api.putConceptValidList(ids).then( - res => - dispatch({ - type: A.VALIDATE_CONCEPT_LIST_SUCCESS, - payload: { ids }, - }), - err => - dispatch({ type: A.VALIDATE_CONCEPT_LIST_FAILURE, payload: { err, ids } }) - ); -}; diff --git a/app/src/js/actions/constants/concepts.js b/app/src/js/actions/constants/concepts.js deleted file mode 100644 index d38993de4..000000000 --- a/app/src/js/actions/constants/concepts.js +++ /dev/null @@ -1,152 +0,0 @@ -//LOAD CONCEPTS -export const LOAD_CONCEPT_LIST = 'LOAD_CONCEPT_LIST'; -export const LOAD_CONCEPT_LIST_SUCCESS = 'LOAD_CONCEPT_LIST_SUCCESS'; -export const LOAD_CONCEPT_LIST_FAILURE = 'LOAD_CONCEPT_LIST_FAILURE'; - -// LOAD COLLECTION DASHBOARD LIST -export const LOAD_COLLECTION_DASHBOARD_LIST = 'LOAD_COLLECTION_DASHBOARD_LIST'; -export const LOAD_COLLECTION_DASHBOARD_LIST_SUCCESS = - 'LOAD_COLLECTION_DASHBOARD_LIST_SUCCESS'; -export const LOAD_COLLECTION_DASHBOARD_LIST_FAILURE = - 'LOAD_COLLECTION_DASHBOARD_LIST_FAILURE'; - -//LOAD CONCEPTS TO VALIDATE -export const LOAD_CONCEPT_VALIDATE_LIST = 'LOAD_CONCEPT_VALIDATE_LIST'; -export const LOAD_CONCEPT_VALIDATE_LIST_SUCCESS = - 'LOAD_CONCEPT_VALIDATE_LIST_SUCCESS'; -export const LOAD_CONCEPT_VALIDATE_LIST_FAILURE = - 'LOAD_CONCEPT_VALIDATE_LIST_FAILURE'; - -//LOAD CONCEPTS FOR SEARCH -export const LOAD_CONCEPT_SEARCH_LIST = 'LOAD_CONCEPT_SEARCH_LIST'; -export const LOAD_CONCEPT_SEARCH_LIST_SUCCESS = - 'LOAD_CONCEPT_SEARCH_LIST_SUCCESS'; -export const LOAD_CONCEPT_SEARCH_LIST_FAILURE = - 'LOAD_CONCEPT_SEARCH_LIST_FAILURE'; - -//VALIDATE CONCEPTS -export const VALIDATE_CONCEPT_LIST = 'VALIDATE_CONCEPT_LIST'; -export const VALIDATE_CONCEPT_LIST_SUCCESS = 'VALIDATE_CONCEPT_LIST_SUCCESS'; -export const VALIDATE_CONCEPT_LIST_FAILURE = 'VALIDATE_CONCEPT_LIST_FAILURE'; - -//EXPORT -export const EXPORT_CONCEPT = 'EXPORT_CONCEPT'; -export const EXPORT_CONCEPT_SUCCESS = 'EXPORT_CONCEPT_SUCCESS'; -export const EXPORT_CONCEPT_FAILURE = 'EXPORT_CONCEPT_FAILURE'; -export const EXPORT_CONCEPT_LIST = 'EXPORT_CONCEPT_LIST'; -export const EXPORT_CONCEPT_LIST_SUCCESS = 'EXPORT_CONCEPT_LIST_SUCCESS'; -export const EXPORT_CONCEPT_LIST_FAILURE = 'EXPORT_CONCEPT_LIST_FAILURE'; - -//SEND -export const SEND_CONCEPT = 'SEND_CONCEPT'; -export const SEND_CONCEPT_SUCCESS = 'SEND_CONCEPT_SUCCESS'; -export const SEND_CONCEPT_FAILURE = 'SEND_CONCEPT_FAILURE'; - -//CREATE CONCEPT -export const CREATE_CONCEPT = 'CREATE_CONCEPT'; -export const CREATE_CONCEPT_SUCCESS = 'CREATE_CONCEPT_SUCCESS'; -export const CREATE_CONCEPT_FAILURE = 'CREATE_CONCEPT_FAILURE'; - -//UPDATE CONCEPT -export const UPDATE_CONCEPT = 'UPDATE_CONCEPT'; -export const UPDATE_CONCEPT_SUCCESS = 'UPDATE_CONCEPT_SUCCESS'; -export const UPDATE_CONCEPT_FAILURE = 'UPDATE_CONCEPT_FAILURE'; - -//DELETE CONCEPT -export const DELETE_CONCEPT = 'DELETE_CONCEPT'; -export const DELETE_CONCEPT_SUCCESS = 'DELETE_CONCEPT_SUCCESS'; -export const DELETE_CONCEPT_FAILURE = 'DELETE_CONCEPT_FAILURE'; - -//LOAD GENERAL -export const LOAD_CONCEPT_GENERAL = 'LOAD_CONCEPT_GENERAL'; -export const LOAD_CONCEPT_GENERAL_SUCCESS = 'LOAD_CONCEPT_GENERAL_SUCCESS'; -export const LOAD_CONCEPT_GENERAL_FAILURE = 'LOAD_CONCEPT_GENERAL_FAILURE'; - -//LOAD LINKS -export const LOAD_CONCEPT_LINKS = 'LOAD_CONCEPT_LINKS'; -export const LOAD_CONCEPT_LINKS_SUCCESS = 'LOAD_CONCEPT_LINKS_SUCCESS'; -export const LOAD_CONCEPT_LINKS_FAILURE = 'LOAD_CONCEPT_LINKS_FAILURE'; - -//LOAD NOTES -export const LOAD_NOTES_VERSION = 'LOAD_NOTES_VERSION'; -export const LOAD_NOTES_VERSION_SUCCESS = 'LOAD_NOTES_VERSION_SUCCESS'; -export const LOAD_NOTES_VERSION_FAILURE = 'LOAD_NOTES_VERSION_FAILURE'; -export const LOAD_NOTES_ALL = 'LOAD_NOTES_ALL'; -export const LOAD_NOTES_ALL_SUCCESS = 'LOAD_NOTES_ALL_SUCCESS'; -export const LOAD_NOTES_ALL_FAILURE = 'LOAD_NOTES_ALL_FAILURE'; - -//LOAD COLLECTIONS -export const LOAD_COLLECTION_LIST = 'LOAD_COLLECTION_LIST'; -export const LOAD_COLLECTION_LIST_SUCCESS = 'LOAD_COLLECTION_LIST_SUCCESS'; -export const LOAD_COLLECTION_LIST_FAILURE = 'LOAD_COLLECTION_LIST_FAILURE'; - -//LOAD COLLECTIONS TO VALIDATE -export const LOAD_COLLECTION_VALIDATE_LIST = 'LOAD_COLLECTION_VALIDATE_LIST'; -export const LOAD_COLLECTION_VALIDATE_LIST_SUCCESS = - 'LOAD_COLLECTION_VALIDATE_LIST_SUCCESS'; -export const LOAD_COLLECTION_VALIDATE_LIST_FAILURE = - 'LOAD_COLLECTION_VALIDATE_LIST_FAILURE'; - -//VALIDATE COLLECTIONS -export const VALIDATE_COLLECTION_LIST = 'VALIDATE_COLLECTION_LIST'; -export const VALIDATE_COLLECTION_LIST_SUCCESS = - 'VALIDATE_COLLECTION_LIST_SUCCESS'; -export const VALIDATE_COLLECTION_LIST_FAILURE = - 'VALIDATE_COLLECTION_LIST_FAILURE'; - -//EXPORT -export const EXPORT_COLLECTION = 'EXPORT_COLLECTION'; -export const EXPORT_COLLECTION_SUCCESS = 'EXPORT_COLLECTION_SUCCESS'; -export const EXPORT_COLLECTION_FAILURE = 'EXPORT_COLLECTION_FAILURE'; -export const EXPORT_COLLECTION_LIST = 'EXPORT_COLLECTION_LIST'; -export const EXPORT_COLLECTION_LIST_SUCCESS = 'EXPORT_COLLECTION_LIST_SUCCESS'; -export const EXPORT_COLLECTION_LIST_FAILURE = 'EXPORT_COLLECTION_LIST_FAILURE'; - -//SEND -export const SEND_COLLECTION = 'SEND_COLLECTION'; -export const SEND_COLLECTION_SUCCESS = 'SEND_COLLECTION_SUCCESS'; -export const SEND_COLLECTION_FAILURE = 'SEND_COLLECTION_FAILURE'; - -//CREATE COLLECTION -export const CREATE_COLLECTION = 'CREATE_COLLECTION'; -export const CREATE_COLLECTION_SUCCESS = 'CREATE_COLLECTION_SUCCESS'; -export const CREATE_COLLECTION_FAILURE = 'CREATE_COLLECTION_FAILURE'; - -//UPDATE COLLECTION -export const UPDATE_COLLECTION = 'UPDATE_COLLECTION'; -export const UPDATE_COLLECTION_SUCCESS = 'UPDATE_COLLECTION_SUCCESS'; -export const UPDATE_COLLECTION_FAILURE = 'UPDATE_COLLECTION_FAILURE'; - -//LOAD GENERAL -export const LOAD_COLLECTION_GENERAL = 'LOAD_COLLECTION_GENERAL'; -export const LOAD_COLLECTION_GENERAL_SUCCESS = - 'LOAD_COLLECTION_GENERAL_SUCCESS'; -export const LOAD_COLLECTION_GENERAL_FAILURE = - 'LOAD_COLLECTION_GENERAL_FAILURE'; - -//LOAD MEMBERS -export const LOAD_COLLECTION_MEMBERS = 'LOAD_COLLECTION_MEMBERS'; -export const LOAD_COLLECTION_MEMBERS_SUCCESS = - 'LOAD_COLLECTION_MEMBERS_SUCCESS'; -export const LOAD_COLLECTION_MEMBERS_FAILURE = - 'LOAD_COLLECTION_MEMBERS_FAILURE'; - -//LOAD ROLE STATUS -export const LOAD_ROLE_LIST = 'LOAD_ROLE_LIST'; -export const LOAD_ROLE_LIST_SUCCESS = 'LOAD_ROLE_LIST_SUCCESS'; -export const LOAD_ROLE_LIST_FAILURE = 'LOAD_ROLE_LIST_FAILURE'; - -//LOAD AGENT LIST -export const LOAD_AGENT_LIST = 'LOAD_AGENT_LIST'; -export const LOAD_AGENT_LIST_SUCCESS = 'LOAD_AGENT_LIST_SUCCESS'; -export const LOAD_AGENT_LIST_FAILURE = 'LOAD_AGENT_LIST_FAILURE'; - -//ADD AGENT FROM ROLE LIST -export const ADD_ROLE = 'ADD_ROLE'; -export const ADD_ROLE_SUCCESS = 'ADD_ROLE_SUCCESS'; -export const ADD_ROLE_FAILURE = 'ADD_ROLE_FAILURE'; - -//DELETE AGENT FROM ROLE LIST -export const DELETE_ROLE = 'DELETE_ROLE'; -export const DELETE_ROLE_SUCCESS = 'DELETE_ROLE_SUCCESS'; -export const DELETE_ROLE_FAILURE = 'DELETE_ROLE_FAILURE'; diff --git a/app/src/js/actions/constants/index.js b/app/src/js/actions/constants/index.js index d2e5c91bc..4e7494ed4 100644 --- a/app/src/js/actions/constants/index.js +++ b/app/src/js/actions/constants/index.js @@ -1,4 +1,3 @@ export * from './app'; -export * from './concepts'; export * from './classifications'; export * from './operations'; diff --git a/app/src/js/actions/dashboard/collections.js b/app/src/js/actions/dashboard/collections.js deleted file mode 100644 index 515ae19ac..000000000 --- a/app/src/js/actions/dashboard/collections.js +++ /dev/null @@ -1,22 +0,0 @@ -import api from 'js/remote-api/concepts-api'; -import * as A from '../constants'; -import { ArrayUtils } from 'bauhaus-utilities'; - -export default () => dispatch => { - dispatch({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST, - payload: {}, - }); - return api.getCollectionDashboardList().then( - results => - dispatch({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST_SUCCESS, - payload: { results: ArrayUtils.sortArrayByLabel(results) }, - }), - err => - dispatch({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST_FAILURE, - payload: { err }, - }) - ); -}; diff --git a/app/src/js/actions/dashboard/collections.spec.js b/app/src/js/actions/dashboard/collections.spec.js deleted file mode 100644 index a20ef9af6..000000000 --- a/app/src/js/actions/dashboard/collections.spec.js +++ /dev/null @@ -1,37 +0,0 @@ -import get from './collections'; -import * as A from 'js/actions/constants'; -import api from 'js/remote-api/concepts-api'; - -const dispatch = jest.fn(); -jest.mock('js/remote-api/operations-api'); - -describe('get collection dashboard list', () => { - it('should call dispatch LOAD_COLLECTION_DASHBOARD_LIST_SUCCESS action with the sorted list', async () => { - api.getCollectionDashboardList = function(id) { - return Promise.resolve([{ label: 'bbb' }, { label: 'aaa' }]); - }; - await get()(dispatch); - expect(dispatch).toHaveBeenCalledWith({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST, - payload: {}, - }); - expect(dispatch).toHaveBeenLastCalledWith({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST_SUCCESS, - payload: { results: [{ label: 'aaa' }, { label: 'bbb' }] }, - }); - }); - it('should call dispatch LOAD_COLLECTION_DASHBOARD_LIST_FAILURE action with the error', async () => { - api.getCollectionDashboardList = function(id) { - return Promise.reject('error'); - }; - await get()(dispatch); - expect(dispatch).toHaveBeenCalledWith({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST, - payload: {}, - }); - expect(dispatch).toHaveBeenLastCalledWith({ - type: A.LOAD_COLLECTION_DASHBOARD_LIST_FAILURE, - payload: { err: 'error' }, - }); - }); -}); diff --git a/app/src/js/applications/administration/dashboard/concepts/home-container.js b/app/src/js/applications/administration/dashboard/concepts/home-container.js index dde6b909a..4abc61431 100644 --- a/app/src/js/applications/administration/dashboard/concepts/home-container.js +++ b/app/src/js/applications/administration/dashboard/concepts/home-container.js @@ -1,41 +1,49 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import React, { useEffect, useState } from 'react'; import { Loading } from '@inseefr/wilco'; -import * as select from 'js/reducers'; import Dashboard from './home'; -import loadConceptSearchList from 'js/actions/concepts/search-list'; -import loadCollectionDashboardList from 'js/actions/dashboard/collections'; +import api from '../../../../remote-api/concepts-api'; +import { ArrayUtils } from 'bauhaus-utilities'; -class DashboardContainer extends Component { - componentWillMount() { - const { conceptSearchList, collectionDashboardList } = this.props; - if (!conceptSearchList) this.props.loadConceptSearchList(); - if (!collectionDashboardList) this.props.loadCollectionDashboardList(); - } +const emptyItem = { + id: '', + label: '', + created: '', + modified: '', + disseminationStatus: '', + validationStatus: '', + definition: '', + creator: '', + isTopConceptOf: '', + valid: '', +}; - render() { - const { conceptSearchList, collectionDashboardList } = this.props; - if (!conceptSearchList || !collectionDashboardList) return ; +const DashboardContainer = () => { + const [loading, setLoading] = useState(true); + const [concepts, setConcepts] = useState([]); + const [collections, setCollections] = useState([]); - return ( - - ); - } -} + useEffect(() => { + Promise.all([ + api.getConceptSearchList(), + api.getCollectionDashboardList() + ]).then(([ conceptsList, collectionsList ]) => { -const mapStateToProps = state => ({ - conceptSearchList: select.getConceptSearchList(state), - collectionDashboardList: select.getCollectionDashboardList(state), -}); -const mapDispatchToProps = { - loadConceptSearchList, - loadCollectionDashboardList, -}; + setConcepts(ArrayUtils.sortArrayByLabel(conceptsList).map(concept => + Object.assign({}, emptyItem, concept) + )) + + setCollections(ArrayUtils.sortArrayByLabel(collectionsList)); + }).finally(() => setLoading(false)) + }, []) + if(loading){ + return ; + } -export default connect( - mapStateToProps, - mapDispatchToProps -)(DashboardContainer); + return ( + + ); +} +export default DashboardContainer; diff --git a/app/src/js/applications/codelists/routes/index.js b/app/src/js/applications/codelists/routes/index.js index 1c44628eb..cf5c4677d 100644 --- a/app/src/js/applications/codelists/routes/index.js +++ b/app/src/js/applications/codelists/routes/index.js @@ -10,7 +10,7 @@ import { CodeListsPartialHome, SearchFormPartialList, CodelistPartialComponentView, - CodeListsPartialEditContext, + CodelistPartialEdit, } from 'bauhaus-codelists'; const CodesListComponent = () => { @@ -37,11 +37,15 @@ const CodesListComponent = () => { path="/codelists/:id/modify" component={CodeListsEditContext} /> - + { diff --git a/app/src/js/applications/collections/edition-creation/creation-container.js b/app/src/js/applications/collections/edition-creation/creation-container.js index b4194fe36..3e905daa6 100644 --- a/app/src/js/applications/collections/edition-creation/creation-container.js +++ b/app/src/js/applications/collections/edition-creation/creation-container.js @@ -1,101 +1,69 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; -import { CREATE_COLLECTION } from 'js/actions/constants'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; import * as select from 'js/reducers'; -import loadConceptList from 'js/actions/concepts/list'; -import loadCollectionList from 'js/actions/collections/list'; -import loadStampList from 'js/actions/stamp'; -import createCollection from 'js/actions/collections/create'; import buildPayload from 'js/utils/collections/build-payload/build-payload'; import CollectionEditionCreation from './home'; import D from 'js/i18n'; import emptyCollection from 'js/utils/collections/empty-collection'; import { cleanId, Loading } from '@inseefr/wilco'; -import { OK } from 'js/constants'; -import { Stores } from 'bauhaus-utilities'; +import { ArrayUtils } from 'bauhaus-utilities'; +import globalApi from '../../../remote-api/api'; +import api from '../../../remote-api/concepts-api'; -class CreationContainer extends Component { - constructor(props) { - super(props); - this.state = { - creationRequested: false, - id: '', - }; +const CreationContainer = () => { + const history = useHistory() + const langs = useSelector(state => select.getLangs(state)); + const collection = useSelector(state => emptyCollection(state.app.properties.defaultContributor)); - this.handleCreation = (data) => { - this.props.createCollection(buildPayload(data, 'CREATE')); - this.setState({ - creationRequested: true, - id: data.general.id, - }); - }; - } - - componentWillMount() { - const { conceptList, collectionList, stampList } = this.props; - if (!conceptList) this.props.loadConceptList(); - if (!collectionList) this.props.loadCollectionList(); - if (stampList.length === 0) this.props.loadStampList(); - } + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); - render() { - const { - collection, - collectionList, - conceptList, - stampList, - creationStatus, - langs, - } = this.props; + const [collectionList, setCollectionList] = useState([]) + const [conceptList, setConceptList] = useState([]) + const [stampList, setStampList] = useState([]) - if (this.state.creationRequested) { - if (creationStatus === OK) { - return ; - } else return ; - } - if (conceptList && stampList) { - const { general, members } = collection; - return ( - - ); - } - return ; - } -} + useEffect(() => { + Promise.all([ + globalApi.getStampList(), + api.getConceptList(), + api.getCollectionList() + ]).then(([ stampsList, conceptsList, collectionsList ]) => { + setStampList(stampsList) + setConceptList(ArrayUtils.sortArrayByLabel(conceptsList)) + setCollectionList(ArrayUtils.sortArrayByLabel(collectionsList)) + }).finally(() => setLoading(false)) + }, []); -const mapStateToProps = (state, ownProps) => { - return { - collection: emptyCollection(state.app.properties.defaultContributor), - collectionList: select.getCollectionList(state), - conceptList: select.getConceptList(state), - stampList: Stores.Stamps.getStampList(state), - creationStatus: select.getStatus(state, CREATE_COLLECTION), - langs: select.getLangs(state), - }; -}; + const handleCreation = useCallback((data) => { + setSaving(true); + api.postCollection(buildPayload(data, 'CREATE')) + .then(() => { + history.push(`/collection/${cleanId(data.general.id)}`) + }) + .finally(() => setSaving(false)) + }, [history]); -const mapDispatchToProps = { - loadConceptList, - loadCollectionList, - loadStampList, - createCollection, -}; - -CreationContainer = connect( - mapStateToProps, - mapDispatchToProps -)(CreationContainer); + if(saving){ + return ; + } + if(loading){ + return + } + const { general, members } = collection; + return ( + + ); +} export default CreationContainer; diff --git a/app/src/js/applications/collections/edition-creation/edition-container.js b/app/src/js/applications/collections/edition-creation/edition-container.js index 59238c772..36177cb32 100644 --- a/app/src/js/applications/collections/edition-creation/edition-container.js +++ b/app/src/js/applications/collections/edition-creation/edition-container.js @@ -1,128 +1,81 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useHistory, useParams } from 'react-router-dom'; import * as select from 'js/reducers'; -import { UPDATE_COLLECTION } from 'js/actions/constants'; -import loadCollection from 'js/actions/collections/collection'; -import loadCollectionList from 'js/actions/collections/list'; -import loadConceptList from 'js/actions/concepts/list'; -import loadStampList from 'js/actions/stamp'; -import updateCollection from 'js/actions/collections/update'; import CollectionEditionCreation from './home'; import buildPayload from 'js/utils/collections/build-payload/build-payload'; import D from 'js/i18n'; -import { Loading, buildExtract, cleanId } from '@inseefr/wilco'; -import { OK } from 'js/constants'; -import { Stores } from 'bauhaus-utilities'; +import { Loading, cleanId } from '@inseefr/wilco'; +import { ArrayUtils } from 'bauhaus-utilities'; +import api from '../../../remote-api/concepts-api'; +import globalApi from '../../../remote-api/api'; -const extractId = buildExtract('id'); +const EditionContainer = () => { + const { id } = useParams(); + const history = useHistory(); + const langs = useSelector(state => select.getLangs(state)); -class EditionContainer extends Component { - constructor(props) { - super(props); - this.state = { - updateRequested: false, - id: '', - }; + const [loadingCollection, setLoadingCollection] = useState(true); + const [loadingExtraData, setLoadingExtraData] = useState(true); + const [saving, setSaving] = useState(false); - this.handleUpdate = (data) => { - this.props.updateCollection( - data.general.id, - buildPayload(data, 'UPDATE') - ); - this.setState({ - updateRequested: true, - id: data.general.id, - }); - }; - } + const [collection, setCollection] = useState({ }) + const [collectionList, setCollectionList] = useState([]) + const [conceptList, setConceptList] = useState([]) + const [stampList, setStampList] = useState([]) - componentWillMount() { - const { - id, - collection, - collectionList, - conceptList, - stampList, - } = this.props; - if (!collection) this.props.loadCollection(id); - if (!collectionList) this.props.loadCollectionList(); - if (!conceptList) this.props.loadConceptList(); - if (stampList.length === 0) this.props.loadStampList(); - } + useEffect(() => { + Promise.all([ + api.getCollectionGeneral(id), + api.getCollectionMembersList(id) + ]).then(([general, members]) => { + setCollection({ general, members }); + }).finally(() => setLoadingCollection(false)) + }, [id]) - render() { - const { - collection, - collectionList, - conceptList, - stampList, - updateStatus, - langs, - } = this.props; + useEffect(() => { + Promise.all([ + globalApi.getStampList(), + api.getConceptList(), + api.getCollectionList() + ]).then(([ stampsList, conceptsList, collectionsList ]) => { + setStampList(stampsList) + setConceptList(ArrayUtils.sortArrayByLabel(conceptsList)) + setCollectionList(ArrayUtils.sortArrayByLabel(collectionsList)) + }).finally(() => setLoadingExtraData(false)) + }, []); - if (this.state.updateRequested) { - if (this.props.updateStatus === OK) { - return ; - } else { - return ; - } - } - if (collection && collectionList && conceptList && stampList) { - const { general, members } = collection; + const handleUpdate = useCallback((data) => { + setSaving(true); + api.putCollection(data.general.id, buildPayload(data, 'UPDATE')) + .then(() => { + history.push(`/collection/${cleanId(id)}`) + }) + .finally(() => setSaving(false)) + }, [history, id]); - return ( - - ); - } - return ; + if(saving){ + return + } + if(loadingCollection || loadingExtraData){ + return } -} - -const mapStateToProps = (state, ownProps) => { - const id = extractId(ownProps); - return { - id, - collection: select.getCollection(state, id), - collectionList: select.getCollectionList(state), - conceptList: select.getConceptList(state), - stampList: Stores.Stamps.getStampList(state), - updateStatus: select.getStatus(state, UPDATE_COLLECTION), - langs: select.getLangs(state), - }; -}; - -const mapDispatchToProps = { - loadCollection, - loadCollectionList, - loadConceptList, - loadStampList, - updateCollection, -}; -EditionContainer = connect( - mapStateToProps, - mapDispatchToProps -)(EditionContainer); + const { general, members } = collection; -EditionContainer.propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - id: PropTypes.string.isRequired, - }), - }), -}; + return ( + + ); +} export default EditionContainer; diff --git a/app/src/js/applications/collections/export/home-container.js b/app/src/js/applications/collections/export/home-container.js index 40343d8aa..fcdbe4fad 100644 --- a/app/src/js/applications/collections/export/home-container.js +++ b/app/src/js/applications/collections/export/home-container.js @@ -1,46 +1,52 @@ import React, { useCallback, useState, useEffect } from 'react'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; +import { useHistory } from 'react-router-dom'; import CollectionsToExport from './home'; -import * as select from 'js/reducers'; -import { EXPORT_COLLECTION_LIST } from 'js/actions/constants'; -import { Loading } from '@inseefr/wilco'; -import exportCollectionList from 'js/actions/collections/export-multi'; -import loadCollectionList from 'js/actions/collections/list'; -import { OK } from 'js/constants'; -import { useTitle } from 'bauhaus-utilities'; +import { getContentDisposition, Loading } from '@inseefr/wilco'; +import { ArrayUtils, useTitle } from 'bauhaus-utilities'; import D from '../../../i18n/build-dictionary'; +import api from '../../../remote-api/concepts-api'; +import FileSaver from 'file-saver'; -const CollectionsToExportContainer = ({ - collections, - exportStatus, - loadCollectionList, - exportCollectionList, -}) => { +const CollectionsToExportContainer = () => { useTitle(D.collectionsTitle, D.exportTitle) - - const [exportRequested, setExportRequested] = useState(false); + const history = useHistory(); + const [collections, setCollections] = useState([]); + const [loading, setLoading] = useState(true); + const [exporting, setExporting] = useState(false); const handleExportCollectionList = useCallback( (ids, MimeType) => { - exportCollectionList(ids, MimeType); - setExportRequested(true); + setExporting(true); + Promise.all(ids.map(id => { + let fileName; + return api + .getCollectionExport(id, MimeType) + .then(res => { + fileName = getContentDisposition( + res.headers.get('Content-Disposition') + )[1]; + return res; + }) + .then(res => res.blob()) + .then(blob => { + return FileSaver.saveAs(blob, fileName); + }); + })) + .then(() => history.push("/collections")) + .finally(() => setExporting(false)) }, - [exportCollectionList] + [history] ); - useEffect(() => { - if (!collections) loadCollectionList(); - }, [collections, loadCollectionList]); - if (exportRequested) { - if (exportStatus === OK) { - return ; - } - return ; - } + useEffect(() => { + api.getCollectionList() + .then(body => setCollections(ArrayUtils.sortArrayByLabel(body))) + .finally(() => setLoading(false)) + }, []) - if (!collections) return ; + if(exporting) return ; + if (loading) return ; return ( ({ - collections: select.getCollectionList(state), - exportStatus: select.getStatus(state, EXPORT_COLLECTION_LIST), -}); - -const mapDispatchToProps = { - loadCollectionList, - exportCollectionList, -}; - -export default connect( - mapStateToProps, - mapDispatchToProps -)(CollectionsToExportContainer); +export default CollectionsToExportContainer; diff --git a/app/src/js/applications/collections/home-container.js b/app/src/js/applications/collections/home-container.js index 92585908b..2022ac367 100644 --- a/app/src/js/applications/collections/home-container.js +++ b/app/src/js/applications/collections/home-container.js @@ -1,20 +1,21 @@ -import React, { useEffect } from 'react'; -import { connect, useSelector } from 'react-redux'; +import React, { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import { Loading } from '@inseefr/wilco'; import CollectionsHome from './home'; -import loadCollectionList from 'js/actions/collections/list'; -import { Auth } from 'bauhaus-utilities'; +import { ArrayUtils, Auth } from 'bauhaus-utilities'; +import api from '../../remote-api/concepts-api'; -const CollectionsHomeContainer = ( { collections, loadCollectionList }) => { +const CollectionsHomeContainer = () => { const permission = useSelector(state => Auth.getPermission(state)); - + const [loading, setLoading] = useState(true); + const [collections, setCollections] = useState([]); useEffect(() => { - if (!collections) { - loadCollectionList(); - } - }, [collections, loadCollectionList]); + api.getCollectionList().then(body => { + setCollections(ArrayUtils.sortArrayByLabel(body)) + }).finally(() => setLoading(false)) + }, []); - if (!collections) { + if (loading) { return ; } return ( @@ -22,23 +23,4 @@ const CollectionsHomeContainer = ( { collections, loadCollectionList }) => { ); } -const mapStateToProps = state => { - if (!state.collectionList) { - return { - collections: [], - }; - } - let { results: collections } = state.collectionList; - return { - collections, - }; -}; - -const mapDispatchToProps = { - loadCollectionList, -}; - -export default connect( - mapStateToProps, - mapDispatchToProps -)(CollectionsHomeContainer); +export default CollectionsHomeContainer diff --git a/app/src/js/applications/collections/send/home-container.js b/app/src/js/applications/collections/send/home-container.js index e99c4d269..f9945377e 100644 --- a/app/src/js/applications/collections/send/home-container.js +++ b/app/src/js/applications/collections/send/home-container.js @@ -1,101 +1,57 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { Loading, buildExtract } from '@inseefr/wilco'; -import { SEND_COLLECTION } from 'js/actions/constants'; -import loadGeneral from 'js/actions/collections/general'; -import sendCollection from 'js/actions/collections/send'; -import * as select from 'js/reducers'; -import { OK } from 'js/constants'; +import React, { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { Loading } from '@inseefr/wilco'; +import { ERROR, OK, PENDING } from 'js/constants'; import SendStatus from './status'; import CollectionSend from './home'; - -const extractId = buildExtract('id'); - -class CollectionSendContainer extends Component { - constructor(props) { - super(props); - this.state = { - sendRequested: false, - }; - this.handleCollectionSend = (id, data) => { - this.props.sendCollection(id, data); - this.setState({ - sendRequested: true, - }); - }; - } - componentWillMount() { - const { id, loaded, loadGeneral } = this.props; - if (!loaded) loadGeneral(id); +import { useParams } from 'react-router-dom'; +import api from '../../../remote-api/concepts-api'; + + +const CollectionSendContainer = () => { + const { id } = useParams(); + const [general, setGeneral] = useState(); + const [loading, setLoading] = useState(true); + const [sending, setSending] = useState(); + + const properties = useSelector(state => state.app.properties) + useEffect(() => { + api.getCollectionGeneral(id) + .then(body => setGeneral(body)) + .finally(() => setLoading(false)) + }, [id]) + + const handleCollectionSend = (id, data) => { + setSending(PENDING) + api.postCollectionSend(id, data) + .then(() => setSending(OK)) + .catch(() => setSending(ERROR)); } + if (loading || !properties) return ; - render() { - const { - id, - prefLabelLg1, - isValidated, - properties, - loaded, - sendStatus, - } = this.props; - const { sendRequested } = this.state; - if (sendRequested) { - const urlBack = sendStatus === OK ? '/collections' : `/collection/${id}`; - return ( - - ); - } - if (!loaded || !properties) return ; + const { prefLabelLg1, isValidated } = general + + if (sending) { + const urlBack = sending === OK ? '/collections' : `/collection/${id}`; return ( - ); } -} -const mapStateToProps = (state, ownProps) => { - let prefLabelLg1, isValidated; - const id = extractId(ownProps); - const general = select.getCollectionGeneral(state, id); - if (general) { - ({ prefLabelLg1, isValidated } = general); - } - return { - id, - sendStatus: select.getStatus(state, SEND_COLLECTION), - loaded: Boolean(general), - prefLabelLg1, - isValidated, - properties: state.app.properties, - }; -}; - -const mapDispatchToProps = { - loadGeneral, - sendCollection, -}; + return ( + + ); -CollectionSendContainer = connect( - mapStateToProps, - mapDispatchToProps -)(CollectionSendContainer); - -CollectionSendContainer.propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - id: PropTypes.string.isRequired, - }), - }), -}; +} export default CollectionSendContainer; diff --git a/app/src/js/applications/collections/validation/home-container.js b/app/src/js/applications/collections/validation/home-container.js index 9decd5618..a834c9014 100644 --- a/app/src/js/applications/collections/validation/home-container.js +++ b/app/src/js/applications/collections/validation/home-container.js @@ -1,37 +1,36 @@ import React, { useEffect, useState } from 'react'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router'; +import { useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; import CollectionsToValidate from './home'; import { Loading } from '@inseefr/wilco'; -import * as select from 'js/reducers'; -import validateCollectionList from 'js/actions/collections/validate'; -import loadCollectionValidateList from 'js/actions/collections/validate-list'; -import { VALIDATE_COLLECTION_LIST } from 'js/actions/constants'; -import { OK } from 'js/constants'; -import { Auth, useTitle } from 'bauhaus-utilities'; +import { ArrayUtils, Auth, useTitle } from 'bauhaus-utilities'; import D from 'js/i18n'; +import api from '../../../remote-api/concepts-api'; -const CollectionsToValidateContainer = - ({ validateCollectionList, collections, loadCollectionValidateList, permission, validationStatus }) => { +const CollectionsToValidateContainer = () => { useTitle(D.collectionsTitle, D.btnValid); - const [validationRequested, setValidationRequested] = useState(false); + const permission = useSelector(state => Auth.getPermission(state)); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const [collections, setCollections] = useState([]); + const history = useHistory(); const handleValidateCollectionList = ids => { - validateCollectionList(ids); - setValidationRequested(true) + setSaving(true) + api.putCollectionValidList(ids) + .then(() => setSaving(false)) + .finally(() => history.push("/collections")) }; useEffect(() => { - if (!collections) loadCollectionValidateList(); - }, [collections, loadCollectionValidateList]); + api.getCollectionValidateList() + .then(results => setCollections(ArrayUtils.sortArrayByLabel(results))) + .then(() => setLoading(false)) + }, []); - if (validationRequested) { - if (validationStatus === OK) { - return ; - } else return ; - } - if (!collections) return ; + if(saving) return ; + if (loading) return ; return ( ({ - collections: select.getCollectionValidateList(state), - permission: Auth.getPermission(state), - validationStatus: select.getStatus(state, VALIDATE_COLLECTION_LIST), -}); - -const mapDispatchToProps = { - loadCollectionValidateList, - validateCollectionList, -}; - -export default connect( - mapStateToProps, - mapDispatchToProps -)(CollectionsToValidateContainer); +export default CollectionsToValidateContainer; diff --git a/app/src/js/applications/collections/visualization/home-container.js b/app/src/js/applications/collections/visualization/home-container.js index b95f22966..8335e700a 100644 --- a/app/src/js/applications/collections/visualization/home-container.js +++ b/app/src/js/applications/collections/visualization/home-container.js @@ -1,110 +1,66 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { VALIDATE_COLLECTION_LIST } from 'js/actions/constants'; -import validateCollection from 'js/actions/collections/validate'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import * as select from 'js/reducers'; -import loadCollections from 'js/actions/collections/collection'; -import loadStampList from 'js/actions/stamp'; -import { Loading, buildExtract } from '@inseefr/wilco'; +import { Loading } from '@inseefr/wilco'; import CollectionVisualization from './home'; -import { OK } from 'js/constants'; import { Auth, Stores } from 'bauhaus-utilities'; +import { useParams } from 'react-router-dom'; +import api from '../../../remote-api/concepts-api'; +import globalApi from '../../../remote-api/api'; -const extractId = buildExtract('id'); +const CollectionVisualizationContainer = () => { + const { id } = useParams(); + const [collection, setCollection] = useState(); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const [stamps, setStamps] = useState(); -class CollectionVisualizationContainer extends Component { - constructor(props) { - super(props); - this.state = { - validationRequested: false, - }; - this.handleCollectionValidation = (id) => { - this.props.validateCollection(id); - this.setState({ - validationRequested: true, - }); - }; - } - componentWillMount() { - const { id, collection, stampList } = this.props; - if (!collection) this.props.loadCollections(id); - if (stampList.length === 0) this.props.loadStampList(); - } - componentWillReceiveProps({ id, validationStatus }) { - if (id !== this.props.id) { - this.props.loadCollections(id); - } - if (this.state.validationRequested && validationStatus === OK) { - //validation has been processed successfully, we can show the - //component again - this.setState({ - validationRequested: false, - }); - //we need to load the collection again - this.props.loadCollections(id); - } - } - render() { - const { validationRequested } = this.state; - const { validationStatus, langs } = this.props; - if (validationRequested && validationStatus !== OK) { - //if validation is OK: nothing to do. We stay on this page and the collection will - //be loaded automatically (since the entries for the given collection in the store will - //be deleted). - if (validationStatus !== OK) return ; - } - const { id, permission, collection, stampList, secondLang } = this.props; - if (collection && stampList) { - const { general, members } = collection; - return ( - - ); - } - return ; - } -} + const permission = useSelector(state => Auth.getPermission(state)); + const secondLang = useSelector(state => Stores.SecondLang.getSecondLang(state)); + const langs = useSelector(state => select.getLangs(state)) -const mapStateToProps = (state, ownProps) => { - const id = extractId(ownProps); - return { - id, - permission: Auth.getPermission(state), - secondLang: Stores.SecondLang.getSecondLang(state), - collection: select.getCollection(state, id), - stampList: Stores.Stamps.getStampList(state), - validationStatus: select.getStatus(state, VALIDATE_COLLECTION_LIST), - langs: select.getLangs(state), - }; -}; + const fetchData = useCallback(() => { + Promise.all([ + api.getCollectionGeneral(id), + api.getCollectionMembersList(id), + globalApi.getStampList() + ]).then(([general, members, stamps]) => { + setCollection({ general, members}); + setStamps(stamps); + }).finally(() => setLoading(false)) + }, [id]); -const mapDispatchToProps = { - loadCollections, - loadStampList, - validateCollection: (id) => validateCollection([id]), -}; + useEffect(() => { + fetchData(); + }, [fetchData]) -CollectionVisualizationContainer = connect( - mapStateToProps, - mapDispatchToProps -)(CollectionVisualizationContainer); + const handleCollectionValidation = (id) => { + setSaving(true) + api.putCollectionValidList([id]) + .then(() => fetchData()) + .finally(() => setSaving(false)); + } + if(loading){ + return + } -CollectionVisualizationContainer.propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - id: PropTypes.string.isRequired, - }), - }), -}; + if(saving){ + return + } + const { general, members } = collection; + + return ( + + ); +} export default CollectionVisualizationContainer; diff --git a/app/src/js/applications/concepts/advanced-search/home-container.js b/app/src/js/applications/concepts/advanced-search/home-container.js index f86c7aae6..9e49019ff 100644 --- a/app/src/js/applications/concepts/advanced-search/home-container.js +++ b/app/src/js/applications/concepts/advanced-search/home-container.js @@ -1,56 +1,54 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; +import React, { useEffect, useState } from 'react'; import { Loading } from '@inseefr/wilco'; -import * as select from 'js/reducers'; import ConceptSearchList from './home'; -import loadStampList from 'js/actions/stamp'; -import loadConceptSearchList from 'js/actions/concepts/search-list'; -import { Stores } from 'bauhaus-utilities'; +import { ArrayUtils, Stores } from 'bauhaus-utilities'; +import api from '../../../remote-api/concepts-api'; +import apiGlobal from '../../../remote-api/api'; -class ConceptSearchListContainer extends Component { - componentWillMount() { - const { - conceptSearchList, - stampList, - disseminationStatusList, - } = this.props; - if (!conceptSearchList) this.props.loadConceptSearchList(); - if (stampList.length === 0) this.props.loadStampList(); - if (disseminationStatusList.length === 0) this.props.loadDisseminationStatusList(); - } +const emptyItem = { + id: '', + label: '', + created: '', + modified: '', + disseminationStatus: '', + validationStatus: '', + definition: '', + creator: '', + isTopConceptOf: '', + valid: '', +}; - render() { - const { - conceptSearchList, - stampList, - disseminationStatusList, - } = this.props; +const ConceptSearchListContainer = () => { + const [ loading, setLoading ] = useState(true); + const [ conceptSearchList, setConceptSearchList ] = useState([]); + const [ stampList, setStampList ] = useState([]); + const [ disseminationStatusList, setDisseminationStatusList ] = useState([]); - if (!(conceptSearchList && stampList && disseminationStatusList)) - return ; + useEffect(() => { + Promise.all([ + api.getConceptSearchList(), + apiGlobal.getStampList(), + Stores.DisseminationStatus.api.getDisseminationStatus() + ]).then(([ concepts, stamps, disseminations ]) => { + setConceptSearchList(ArrayUtils.sortArrayByLabel(concepts).map(concept => + Object.assign({}, emptyItem, concept) + )); + setStampList(stamps); + setDisseminationStatusList(disseminations); + }).finally(() => setLoading(false)) + }, []); - return ( - - ); + if(loading){ + return } -} -const mapStateToProps = (state) => ({ - conceptSearchList: select.getConceptSearchList(state), - stampList: Stores.Stamps.getStampList(state), - disseminationStatusList: Stores.DisseminationStatus.getDisseminationStatusList(state), -}); -const mapDispatchToProps = { - loadConceptSearchList, - loadStampList, - loadDisseminationStatusList: Stores.DisseminationStatus.loadDisseminationStatusList, -}; + return ( + + ); +} -export default connect( - mapStateToProps, - mapDispatchToProps -)(ConceptSearchListContainer); +export default ConceptSearchListContainer diff --git a/app/src/js/applications/concepts/compare/home-container.js b/app/src/js/applications/concepts/compare/home-container.js index 44f5ec134..b638b4215 100644 --- a/app/src/js/applications/concepts/compare/home-container.js +++ b/app/src/js/applications/concepts/compare/home-container.js @@ -1,64 +1,70 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { withRouter } from 'react-router-dom'; -import { Loading, buildExtract } from '@inseefr/wilco'; +import React, { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useParams } from 'react-router-dom'; +import { Loading } from '@inseefr/wilco'; import ConceptCompare from './home'; -import loadConceptAndAllNotes from 'js/actions/concepts/concept-and-all-notes'; import * as select from 'js/reducers'; -import { Stores } from 'bauhaus-utilities'; +import { ArrayUtils, HTMLUtils, Stores } from 'bauhaus-utilities'; +import api from '../../../remote-api/concepts-api'; +import { emptyNotes } from '../../../utils/concepts/notes'; -const extractId = buildExtract('id'); -class ConceptCompareContainer extends Component { - componentWillMount() { - const { id, general, notes } = this.props; - if (!(general && notes)) { - this.props.loadConceptAndAllNotes(id); - } - } +const ConceptCompareContainer = () => { + const { id } = useParams(); + const langs = useSelector(state => select.getLangs(state)); + const secondLang = useSelector(state => Stores.SecondLang.getSecondLang(state)) + const [loading, setLoading] = useState(true); - render() { - let { id, general, notes, secondLang, langs } = this.props; - if (!(notes && general)) return ; - return ( - - ); - } -} + const [general, setGeneral] = useState({}); + const [notes, setNotes] = useState({}); -ConceptCompareContainer.propTypes = { - id: PropTypes.string.isRequired, -}; + useEffect(() => { + api.getConceptGeneral(id) + .then(results => { + setGeneral(results); + return results + }) + .then(general => { + const { conceptVersion } = general; + return Promise.all( + ArrayUtils.range(1, +conceptVersion + 1).map(version => + api.getNoteVersionList(id, version).then(notes => ([version, notes])) + ) + ) + .then(notesAndVersions => { + setNotes(notesAndVersions.reduce((acc, notes) => { + return { + ...acc, + [notes[0]]: Object.assign( + {}, + emptyNotes, + Object.keys(notes[1]).reduce((formatted, noteName) => { + formatted[noteName] = HTMLUtils.rmesHtmlToRawHtml( + notes[1][noteName] + ); + return formatted; + }, {}) + ) + } + }, {})); + }) + .finally(() => setLoading(false)) + }) -const mapStateToProps = (state, ownProps) => { - const id = extractId(ownProps); - let notes; - const general = select.getConceptGeneral(state, id); - const langs = select.getLangs(state); - if (general) { - notes = select.getAllNotes(state, id, general.conceptVersion); - } - return { - id, - secondLang: Stores.SecondLang.getSecondLang(state), - general, - notes, - langs, - }; -}; + }, [id]) -const mapDispatchToProps = { - loadConceptAndAllNotes, -}; + if(loading){ + return + } -export default connect( - mapStateToProps, - mapDispatchToProps -)(withRouter(ConceptCompareContainer)); + return ( + + ); +} +export default ConceptCompareContainer; diff --git a/app/src/js/applications/concepts/edition-creation/creation-container.js b/app/src/js/applications/concepts/edition-creation/creation-container.js index 116aa148c..07ee0afb4 100644 --- a/app/src/js/applications/concepts/edition-creation/creation-container.js +++ b/app/src/js/applications/concepts/edition-creation/creation-container.js @@ -1,106 +1,74 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; -import { CREATE_CONCEPT } from 'js/actions/constants'; +import React, { useCallback, useState, useEffect } from 'react'; +import { useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; import * as select from 'js/reducers'; -import loadConceptList from 'js/actions/concepts/list'; -import loadStampList from 'js/actions/stamp'; -import createConcept from 'js/actions/concepts/create'; import buildPayloadCreation from 'js/utils/concepts/build-payload-creation-update/build-payload-creation'; import ConceptEditionCreation from './home'; import { mergeWithAllConcepts } from 'js/utils/concepts/links'; import D from 'js/i18n'; import emptyConcept from 'js/utils/concepts/empty-concept'; import { Loading } from '@inseefr/wilco'; -import { OK } from 'js/constants'; -import { Stores } from 'bauhaus-utilities'; +import { ArrayUtils, Stores } from 'bauhaus-utilities'; +import api from '../../../remote-api/concepts-api'; +import globalApi from '../../../remote-api/api'; -class CreationContainer extends Component { - constructor(props) { - super(props); - this.state = { - creationRequested: false, - id: '', - }; - this.handleCreation = (data) => { - this.props.createConcept(buildPayloadCreation(data)); - this.setState({ - creationRequested: true, - }); - }; - } +const CreationContainer = () => { + const langs = useSelector(state => select.getLangs(state)); + const maxLengthScopeNote = useSelector(state => Number(state.app.properties.maxLengthScopeNote)); - componentWillMount() { - const { conceptList, stampList, disseminationStatusList } = this.props; - if (!conceptList) this.props.loadConceptList(); - if (stampList.length === 0) this.props.loadStampList(); - if (disseminationStatusList.length === 0){ - this.props.loadDisseminationStatusList(); - } - } + const history = useHistory(); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); - render() { - const { - concept, - conceptList, - stampList, - disseminationStatusList, - maxLengthScopeNote, - creationStatus, - langs, - } = this.props; - if (this.state.creationRequested) { - if (creationStatus === OK) { - return ; - } else return ; - } - if (conceptList && stampList && disseminationStatusList) { - const { general, notes, links } = concept; - const conceptsWithLinks = mergeWithAllConcepts(conceptList, links); - return ( - - ); - } - return ; - } -} + const [concepts, setConcepts] = useState([]) + const [stamps, setStamps] = useState([]) + const [disseminationStatus, setDisseminationStatus] = useState([]) + + useEffect(() => { + Promise.all([ + api.getConceptList(), + globalApi.getStampList(), + Stores.DisseminationStatus.api.getDisseminationStatus() + ]).then(([conceptsList, stampsList, disseminationStatusList]) => { + setConcepts(ArrayUtils.sortArrayByLabel(conceptsList)) + setStamps(stampsList); + setDisseminationStatus(disseminationStatusList) + }).finally(() => setLoading(false)) + }, []) -const mapStateToProps = (state, ownProps) => { - return { - concept: emptyConcept(state.app.properties.defaultContributor), - conceptList: select.getConceptList(state), - stampList: Stores.Stamps.getStampList(state), - disseminationStatusList: Stores.DisseminationStatus.getDisseminationStatusList(state), - maxLengthScopeNote: Number(state.app.properties.maxLengthScopeNote), - id: select.getNewlyCreatedId(state), - creationStatus: select.getStatus(state, CREATE_CONCEPT), - langs: select.getLangs(state), - }; -}; -const mapDispatchToProps = { - loadConceptList, - loadDisseminationStatusList: Stores.DisseminationStatus.loadDisseminationStatusList, - loadStampList, - createConcept, -}; + const concept = useSelector(state => emptyConcept(state.app.properties.defaultContributor)); -CreationContainer = connect( - mapStateToProps, - mapDispatchToProps -)(CreationContainer); + const handleCreation = useCallback((data) => { + setSaving(true); + api.postConcept(buildPayloadCreation(data)) + .then((id) => history.push(`/concept/${id}`)) + .finally(() => setSaving(false)) + }, [history]) + if(loading){ + return + } + if(saving){ + return ; + } + + const { general, notes, links } = concept; + const conceptsWithLinks = mergeWithAllConcepts(concepts, links); + return ( + + ); +} export default CreationContainer; diff --git a/app/src/js/applications/concepts/edition-creation/edition-container.js b/app/src/js/applications/concepts/edition-creation/edition-container.js index 12b5cf7ab..6bb0374f0 100644 --- a/app/src/js/applications/concepts/edition-creation/edition-container.js +++ b/app/src/js/applications/concepts/edition-creation/edition-container.js @@ -1,129 +1,108 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useHistory, useParams } from 'react-router-dom'; import * as select from 'js/reducers'; -import { UPDATE_CONCEPT } from 'js/actions/constants'; -import loadConcept from 'js/actions/concepts/concept'; -import loadConceptList from 'js/actions/concepts/list'; -import loadStampList from 'js/actions/stamp'; -import updateConcept from 'js/actions/concepts/update'; import ConceptEditionCreation from './home'; import buildPayloadUpdate from 'js/utils/concepts/build-payload-creation-update/build-payload-update'; import { mergeWithAllConcepts } from 'js/utils/concepts/links'; import D from 'js/i18n'; -import { Loading, buildExtract } from '@inseefr/wilco'; -import { CLOSE_MATCH, OK } from 'js/constants'; -import { Stores } from 'bauhaus-utilities'; +import { Loading } from '@inseefr/wilco'; +import { CLOSE_MATCH } from 'js/constants'; +import { ArrayUtils, HTMLUtils, Stores } from 'bauhaus-utilities'; +import api from '../../../remote-api/concepts-api'; +import globalApi from '../../../remote-api/api'; +import { emptyNotes } from '../../../utils/concepts/notes'; +import * as generalUtils from '../../../utils/concepts/general'; -const extractId = buildExtract('id'); +const formatNotes = notes => { + return Object.assign( + {}, + emptyNotes, + Object.keys(notes).reduce((formatted, noteName) => { + formatted[noteName] = HTMLUtils.rmesHtmlToRawHtml( + notes[noteName] + ); + return formatted; + }, {}) + ); +} +const EditionContainer = () => { + const { id } = useParams(); + const history = useHistory(); -class EditionContainer extends Component { - constructor(props) { - super(props); - this.state = { - updateRequested: false, - }; + const langs = useSelector(state => select.getLangs(state)); + const maxLengthScopeNote = useSelector(state => Number(state.app.properties.maxLengthScopeNote)); - this.handleUpdate = (id, versioning, oldData, data) => { - this.props.updateConcept( - id, - buildPayloadUpdate(versioning, oldData, data) - ); - this.setState({ - updateRequested: true, - }); - }; - } + const [concept, setConcept] = useState({}) + const [concepts, setConcepts] = useState([]) + const [stamps, setStamps] = useState([]) + const [disseminationStatus, setDisseminationStatus] = useState([]) - componentWillMount() { - const { - id, - concept, - conceptList, - stampList, - disseminationStatusList, - } = this.props; - if (!concept) this.props.loadConcept(id); - if (!conceptList) this.props.loadConceptList(); - if (stampList.length === 0) this.props.loadStampList(); - if (disseminationStatusList.length === 0) this.props.loadDisseminationStatusList(); - } + const [loading, setLoading] = useState(true); + const [loadingExtraData, setLoadingExtraData] = useState(true); + const [saving, setSaving] = useState(false); - render() { - if (this.state.updateRequested) { - if (this.props.updateStatus === OK) { - return ; - } else return ; - } - const { - id, - concept, - conceptList, - stampList, - disseminationStatusList, - maxLengthScopeNote, - updateStatus, - langs, - } = this.props; - if (concept && conceptList && stampList && disseminationStatusList) { - const { general, notes, links } = concept; - const conceptsWithLinks = mergeWithAllConcepts(conceptList, links); - return ( - link.typeOfLink === CLOSE_MATCH)} - conceptsWithLinks={conceptsWithLinks} - disseminationStatusList={disseminationStatusList} - maxLengthScopeNote={maxLengthScopeNote} - stampList={stampList} - isActionProcessed={updateStatus} - save={this.handleUpdate} - langs={langs} - /> - ); - } - return ; - } -} -const mapStateToProps = (state, ownProps) => { - const id = extractId(ownProps); - return { - id, - concept: select.getConcept(state, id), - conceptList: select.getConceptList(state), - stampList: Stores.Stamps.getStampList(state), - disseminationStatusList: Stores.DisseminationStatus.getDisseminationStatusList(state), - maxLengthScopeNote: Number(state.app.properties.maxLengthScopeNote), - updateStatus: select.getStatus(state, UPDATE_CONCEPT), - langs: select.getLangs(state), - }; -}; + useEffect(() => { + api.getConceptGeneral(id).then(general => { + const { conceptVersion } = general; + return Promise.all([ + api.getNoteVersionList(id, conceptVersion), + api.getConceptLinkList(id) + ]).then(([notes, links]) => { + setConcept({ + general: Object.assign(generalUtils.empty(), general), + notes: formatNotes(notes), + links, + }) + }) + }) + .finally(() => setLoading(false)) + }, [id]); -const mapDispatchToProps = { - loadConcept, - loadConceptList, - loadDisseminationStatusList: Stores.DisseminationStatus.loadDisseminationStatusList, - loadStampList, - updateConcept, -}; + useEffect(() => { + Promise.all([ + api.getConceptList(), + globalApi.getStampList(), + Stores.DisseminationStatus.api.getDisseminationStatus() + ]).then(([conceptsList, stampsList, disseminationStatusList]) => { + setConcepts(ArrayUtils.sortArrayByLabel(conceptsList)) + setStamps(stampsList); + setDisseminationStatus(disseminationStatusList) + }).finally(() => setLoadingExtraData(false)) + }, []) -EditionContainer = connect( - mapStateToProps, - mapDispatchToProps -)(EditionContainer); + const handleUpdate = useCallback((id, versioning, oldData, data) => { + setSaving(true); + api.putConcept(id, buildPayloadUpdate(versioning, oldData, data)) + .then(() => history.push(`/concept/${id}`)) + .finally(() => setSaving(false)) + }, [history]) -EditionContainer.propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - id: PropTypes.string.isRequired, - }), - }), -}; + if(loading || loadingExtraData){ + return + } + if(saving){ + return ; + } + const { general, notes, links } = concept; + const conceptsWithLinks = mergeWithAllConcepts(concepts, links); + return ( + link.typeOfLink === CLOSE_MATCH)} + conceptsWithLinks={conceptsWithLinks} + disseminationStatusList={disseminationStatus} + maxLengthScopeNote={maxLengthScopeNote} + stampList={stamps} + save={handleUpdate} + langs={langs} + /> + ); +} export default EditionContainer; diff --git a/app/src/js/applications/concepts/edition-creation/links/index.js b/app/src/js/applications/concepts/edition-creation/links/index.js index fc9a96995..fedc83950 100644 --- a/app/src/js/applications/concepts/edition-creation/links/index.js +++ b/app/src/js/applications/concepts/edition-creation/links/index.js @@ -120,9 +120,6 @@ class LinksEdition extends Component { }; }; this.getActualType = () => linkTypes[this.state.activeTab].memberType; - this.isPanelParent = () => this.getActualType() === NARROWER; - //if the concept already has a parent, we cannot add a parent - this.isAddDisabled = members => this.isPanelParent() && members.length > 0; } updateEquivalentLinks = (links) => { this.props.handleChangeEquivalentLinks(links) @@ -141,15 +138,13 @@ class LinksEdition extends Component { handleClick={removeMember} /> )); - //if a concept already has a parent, no other parent can be added. - const handleClickAdd = !this.isAddDisabled(members) ? addMember : undefined; const hitEls = hits.map(({ id, label }) => ( )); @@ -193,10 +188,6 @@ class LinksEdition extends Component { } LinksEdition.propTypes = { - //all concepts not referenced by the actual concept, and hence which can - //be added as a parent, a child, a reference, a successor or a related - //concept. - //concepts are supposed to be sorted by `label` conceptsWithLinks: conceptsWithLinksPropTypes.isRequired, handleChange: PropTypes.func.isRequired, handleChangeEquivalentLinks: PropTypes.func.isRequired, diff --git a/app/src/js/applications/concepts/export/home-container.js b/app/src/js/applications/concepts/export/home-container.js index 9a4e927ad..ec70151d5 100644 --- a/app/src/js/applications/concepts/export/home-container.js +++ b/app/src/js/applications/concepts/export/home-container.js @@ -1,46 +1,54 @@ import React, { useEffect, useState } from 'react'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; -import * as select from 'js/reducers'; -import { EXPORT_CONCEPT_LIST } from 'js/actions/constants'; +import { useHistory } from 'react-router-dom'; import ConceptsToExport from './home'; -import { Loading } from '@inseefr/wilco'; -import exportConceptList from 'js/actions/concepts/export-multi'; -import loadConceptList from 'js/actions/concepts/list'; -import { OK } from 'js/constants'; -import { useTitle } from 'bauhaus-utilities'; +import { getContentDisposition, Loading } from '@inseefr/wilco'; +import { ArrayUtils, useTitle } from 'bauhaus-utilities'; import D from 'js/i18n'; +import api from '../../../remote-api/concepts-api'; +import FileSaver from 'file-saver'; -const ConceptsToExportContainer = ({ - concepts, - exportStatus, - loadConceptList, - exportConceptList - }) => { - useTitle(D.conceptsTitle, D.exportTitle) - const [exportRequested, setExportRequested] = useState(false) +const ConceptsToExportContainer = () => { + + useTitle(D.conceptsTitle, D.exportTitle); + const history = useHistory(); + const [concepts, setConcepts] = useState([]) + const [loading, setLoading] = useState(true); + const [exporting, setExporting] = useState(false); useEffect(() => { - if(!concepts){ - loadConceptList() - } - }, [concepts, loadConceptList]); + api.getConceptList().then(results => { + setConcepts(ArrayUtils.sortArrayByLabel(results)); + }).finally(() => setLoading(false)) + }, []) const handleExportConceptList = (ids, MimeType) => { - exportConceptList(ids, MimeType); - setExportRequested(true); + Promise.all(ids.map(id => { + let fileName; + return api + .getConceptExport(id, MimeType) + .then(res => { + fileName = getContentDisposition( + res.headers.get('Content-Disposition') + )[1]; + return res; + }) + .then(res => res.blob()) + .then(blob => { + return FileSaver.saveAs(blob, fileName); + }); + })) + .then(() => history.push("/concepts")) + .finally(() => setExporting(false)) } - if (exportRequested) { - if (exportStatus === OK) { - return ; - } - return ; - } - if (!concepts) { + if(exporting){ + return ; + } + if (loading) { return ; } + return ( ); } -const mapStateToProps = state => ({ - concepts: select.getConceptList(state), - exportStatus: select.getStatus(state, EXPORT_CONCEPT_LIST), -}); - -const mapDispatchToProps = { - loadConceptList, - exportConceptList, -}; -export default connect( - mapStateToProps, - mapDispatchToProps -)(ConceptsToExportContainer); +export default ConceptsToExportContainer diff --git a/app/src/js/applications/concepts/home.js b/app/src/js/applications/concepts/home.js index 4b6d60b8f..948d89bd8 100755 --- a/app/src/js/applications/concepts/home.js +++ b/app/src/js/applications/concepts/home.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { PageTitle, SearchableList, @@ -10,21 +10,24 @@ import { } from '@inseefr/wilco'; import check from 'js/utils/auth'; import D from 'js/i18n'; -import { useDispatch, useSelector } from 'react-redux'; -import { Auth } from 'bauhaus-utilities'; -import loadConceptList from 'js/actions/concepts/list'; -import * as select from 'js/reducers'; +import { useSelector } from 'react-redux'; +import { ArrayUtils, Auth } from 'bauhaus-utilities'; +import api from '../../remote-api/concepts-api'; const ConceptsHome = () => { const permission = useSelector(state => Auth.getPermission(state)) - const concepts = useSelector(state => select.getConceptList(state)); - const dispatch = useDispatch(); + const [concepts, setConcepts] = useState([]) + const [loading, setLoading] = useState(true); + useEffect(() => { - if (!concepts) { - dispatch(loadConceptList()) - } - }, [concepts, dispatch]); - if (!concepts) return ; + api.getConceptList() + .then(body => { + setConcepts(ArrayUtils.sortArrayByLabel(body)); + }) + .finally(() => setLoading(false)) + }, []); + + if (loading) return ; const { authType, roles } = permission; const authImpl = check(authType); diff --git a/app/src/js/applications/concepts/routes/index.js b/app/src/js/applications/concepts/routes/index.js index d12199942..457a99e53 100644 --- a/app/src/js/applications/concepts/routes/index.js +++ b/app/src/js/applications/concepts/routes/index.js @@ -7,7 +7,6 @@ import ConceptCompareContainer from 'js/applications/concepts/compare/home-conta import ConceptSendContainer from 'js/applications/concepts/send/home-container'; import ConceptCreationContainer from 'js/applications/concepts/edition-creation/creation-container'; import ConceptEditionContainer from 'js/applications/concepts/edition-creation/edition-container'; -//import ConceptDeletionContainer from 'js/applications/concepts/edition-creation/deletion-container'; import ConceptVisualizationContainer from 'js/applications/concepts/visualization/home-container'; import ConceptsToValidateContainer from 'js/applications/concepts/validation/home-container'; diff --git a/app/src/js/applications/concepts/send/home-container.js b/app/src/js/applications/concepts/send/home-container.js index 66b267aef..5a70d50e1 100644 --- a/app/src/js/applications/concepts/send/home-container.js +++ b/app/src/js/applications/concepts/send/home-container.js @@ -1,101 +1,55 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { buildExtract, Loading } from '@inseefr/wilco'; -import { SEND_CONCEPT } from 'js/actions/constants'; -import loadGeneral from 'js/actions/concepts/general'; -import sendConcept from 'js/actions/concepts/send'; -import * as select from 'js/reducers'; -import { OK } from 'js/constants'; +import React, { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { Loading } from '@inseefr/wilco'; +import { ERROR, OK, PENDING } from 'js/constants'; import SendStatus from './status'; import ConceptSend from './home'; +import { useParams } from 'react-router-dom'; +import api from '../../../remote-api/concepts-api'; + +const ConceptSendContainer = () => { + const { id } = useParams(); + const properties = useSelector(state => state.app.properties); + const [loading, setLoading] = useState(true); + const [general, setGeneral] = useState(); + const [sending, setSending] = useState(); + + useEffect(() => { + api.getConceptGeneral(id) + .then(body => setGeneral(body)) + .finally(() => setLoading(false)) + }, [id]) + + const handleConceptSend = (id, data) => { + setSending(PENDING) + api.postConceptSend(id, data) + .then(() => setSending(OK)) + .catch(() => setSending(ERROR)); + }; -const extractId = buildExtract('id'); - -class ConceptSendContainer extends Component { - constructor(props) { - super(props); - this.state = { - sendRequested: false, - }; - this.handleConceptSend = (id, data) => { - this.props.sendConcept(id, data); - this.setState({ - sendRequested: true, - }); - }; - } - componentWillMount() { - const { id, loaded, loadGeneral } = this.props; - if (!loaded) loadGeneral(id); - } + if (loading || !properties) return ; + const { prefLabelLg1, isValidated } = general; - render() { - const { - id, - prefLabelLg1, - isValidated, - properties, - loaded, - sendStatus, - } = this.props; - const { sendRequested } = this.state; - if (sendRequested) { - const urlBack = sendStatus === OK ? '/concepts' : `/concept/${id}`; - return ( - - ); - } - if (!loaded || !properties) return ; + if(sending){ + const urlBack = sending === OK ? '/concepts' : `/concept/${id}`; return ( - ); } -} -const mapStateToProps = (state, ownProps) => { - let prefLabelLg1, isValidated; - const id = extractId(ownProps); - const general = select.getConceptGeneral(state, id); - if (general) { - ({ prefLabelLg1, isValidated } = general); - } - return { - id, - sendStatus: select.getStatus(state, SEND_CONCEPT), - loaded: Boolean(general), - prefLabelLg1, - isValidated, - properties: state.app.properties, - }; -}; - -const mapDispatchToProps = { - loadGeneral, - sendConcept, -}; - -ConceptSendContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ConceptSendContainer); - -ConceptSendContainer.propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - id: PropTypes.string.isRequired, - }), - }), -}; + return ( + + ); +} export default ConceptSendContainer; diff --git a/app/src/js/applications/concepts/validation/home-container.js b/app/src/js/applications/concepts/validation/home-container.js index 17c5e136c..37893fa1f 100644 --- a/app/src/js/applications/concepts/validation/home-container.js +++ b/app/src/js/applications/concepts/validation/home-container.js @@ -1,40 +1,39 @@ import React, { useEffect, useState } from 'react'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Redirect } from 'react-router'; import ConceptsToValidate from './home'; import { Loading } from '@inseefr/wilco'; -import { VALIDATE_CONCEPT_LIST } from 'js/actions/constants'; -import * as select from 'js/reducers'; -import validateConceptList from 'js/actions/concepts/validate'; -import loadConceptValidateList from 'js/actions/concepts/validate-list'; -import { OK } from 'js/constants'; -import { Auth, useTitle } from 'bauhaus-utilities'; +import { OK, PENDING } from 'js/constants'; +import { ArrayUtils, Auth, useTitle } from 'bauhaus-utilities'; import D from 'js/i18n'; +import api from '../../../remote-api/concepts-api'; -const ConceptsToValidateContainer = ({ - concepts, validateConceptList, loadConceptValidateList, permission, validationStatus - }) => { +const ConceptsToValidateContainer = () => { useTitle(D.conceptsTitle, D.btnValid); - const [validationRequested, setValidationRequested] = useState(false); + const permission = useSelector(state => Auth.getPermission(state)) + const [loading, setLoading] = useState(true); + const [exporting, setExporting] = useState(); + const [concepts, setConcepts] = useState([]) const handleValidateConceptList = ids => { - validateConceptList(ids); - setValidationRequested(true) + setExporting(PENDING); + api.putConceptValidList(ids).finally(() => setExporting(OK)); }; useEffect(() => { - if (!concepts) loadConceptValidateList(); - }, [concepts, loadConceptValidateList]); - - if (validationRequested) { - if (validationStatus === OK) { - return ; - } else { - return ; - } + api.getConceptValidateList().then(body => { + setConcepts(ArrayUtils.sortArrayByLabel(body)) + }).finally(() => setLoading(false)); + }, []); + + if (exporting === OK) { + return ; + } else if(exporting === PENDING) { + return ; } - if (!concepts) return ; + + if (loading) return ; return ( ({ - concepts: select.getConceptValidateList(state), - permission: Auth.getPermission(state), - validationStatus: select.getStatus(state, VALIDATE_CONCEPT_LIST), -}); - -const mapDispatchToProps = { - loadConceptValidateList, - validateConceptList, -}; - -export default connect( - mapStateToProps, - mapDispatchToProps -)(ConceptsToValidateContainer); +export default ConceptsToValidateContainer; diff --git a/app/src/js/applications/concepts/visualization/home-container.js b/app/src/js/applications/concepts/visualization/home-container.js index 9b283ce3d..60106f6f2 100644 --- a/app/src/js/applications/concepts/visualization/home-container.js +++ b/app/src/js/applications/concepts/visualization/home-container.js @@ -1,189 +1,149 @@ -import React, { Component } from 'react'; -import { PropTypes } from 'prop-types'; -import { connect } from 'react-redux'; -import { Redirect } from 'react-router-dom'; -import { VALIDATE_CONCEPT_LIST } from 'js/actions/constants'; -import validateConcepts from 'js/actions/concepts/validate'; -import { - DELETE_CONCEPT, - DELETE_CONCEPT_FAILURE, - DELETE_CONCEPT_SUCCESS, -} from 'js/actions/constants/concepts'; -import deleteConcept from 'js/actions/concepts/delete'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { useHistory, useParams } from 'react-router-dom'; import * as select from 'js/reducers'; -import loadConcept from 'js/actions/concepts/concept'; -import loadConceptAndAllNotes from 'js/actions/concepts/concept-and-all-notes'; import check from 'js/utils/auth'; -import { Loading, buildExtract } from '@inseefr/wilco'; +import { Loading } from '@inseefr/wilco'; import ConceptVisualization from './home'; import ConceptVisualizationStandBy from './stand-by'; -import { OK } from 'js/constants'; -import { Auth, Stores } from 'bauhaus-utilities'; - -const extractId = buildExtract('id'); - -class ConceptVisualizationContainer extends Component { - constructor(props) { - super(props); - this.state = { - validationRequested: false, - deletionRequested: false, - }; - this.handleConceptValidation = id => { - this.props.validateConcept(id); - this.setState({ - validationRequested: true, - }); - }; - this.handleConceptDeletion = id => { - this.props.deleteConcept(id); - this.setState({ - deletionRequested: true, - }); - }; - } - componentWillMount() { - const { id, allNotes } = this.props; - if (!allNotes) { - this.props.loadConceptAndAllNotes(id); - } +import { ArrayUtils, Auth, HTMLUtils, Stores } from 'bauhaus-utilities'; +import api from '../../../remote-api/concepts-api'; +import { emptyNotes } from '../../../utils/concepts/notes'; + +const formatNotes = notes => { + return Object.assign( + {}, + emptyNotes, + Object.keys(notes).reduce((formatted, noteName) => { + formatted[noteName] = HTMLUtils.rmesHtmlToRawHtml( + notes[noteName] + ); + return formatted; + }, {}) + ); +} +const ConceptVisualizationContainer = () => { + const { id } = useParams(); + const history = useHistory(); + + const langs = useSelector(state => select.getLangs(state)); + const permission = useSelector(state => Auth.getPermission(state)); + const secondLang = useSelector(state => Stores.SecondLang.getSecondLang(state)); + + const [loading, setLoading] = useState(true); + const [publishing, setPublishing] = useState(false); + const [deleting, setDeleting] = useState(false); + + const [concept, setConcept] = useState({}); + const [allNotes, setAllNotes] = useState({}); + const [error, setError] = useState(); + + const fetchConcept = (id) => { + api.getConceptGeneral(id).then(general => { + const { conceptVersion } = general; + const concept$ = Promise.all([ + api.getNoteVersionList(id, conceptVersion), + api.getConceptLinkList(id) + ]).then(([notes, links]) => { + setConcept({ + general, + notes: formatNotes(notes), + links, + }) + }) + + const notes$ = Promise.all( + ArrayUtils.range(1, +conceptVersion + 1).map(version => { + return api.getNoteVersionList(id, version).then((notes) => ([ version, formatNotes(notes) ])) + }) + ).then(versionsAndNotes => { + setAllNotes(versionsAndNotes.reduce((acc, versionAndNotes) => { + return { + ...acc, + [versionAndNotes[0]]: versionAndNotes[1] + } + }, {})) + }) + + Promise.all([concept$, notes$]).finally(() => setLoading(false)); + }) } + useEffect(() => { + fetchConcept(id) + }, [id]) + + const handleConceptValidation = useCallback((id) => { + setPublishing(true); + + api.putConceptValidList([id]) + .then(() => fetchConcept(id)) + .finally(() => { + setPublishing(false); + }) + }, []); - componentWillReceiveProps({ id, validationStatus, deleteStatus }) { - if (id !== this.props.id) { - this.props.loadConceptAndAllNotes(id); - } - if (this.state.validationRequested && validationStatus === OK) { - //validation has been processed successfully, we can show the - //component again - this.setState({ - validationRequested: false, - }); - //we need to load the concept again - this.props.loadConcept(id); - } - if (this.state.deletionRequested && deleteStatus !== OK) { - //deletion has not been processed successfully, we show the - //component again - this.setState({ - deletionRequested: false, - showModalError: true, - }); - } + const handleConceptDeletion = useCallback(() => { + setDeleting(true) + api.deleteConcept(id) + .then(() => history.push(`/concepts`)) + .catch(e => setError(e)) + .finally(() => setDeleting(false)) + }, [history, id]); + + if(deleting){ + return ; } - render() { - const { validationRequested, deletionRequested } = this.state; - const { validationStatus, deleteStatus } = this.props; - - if (validationRequested && validationStatus !== OK) { - //if validation is OK: nothing to do. We stay on this page and the concept will - //be loaded automatically (since the entries for the given concept in the store will - //be deleted). - if (validationStatus !== OK) { - return ; - } - } - - if (deletionRequested && deleteStatus === OK) { - //if deletion is OK: we redirect to the concepts list. - return ; - } - - const { - id, - permission, - concept, - allNotes, - secondLang, - langs, - error, - } = this.props; - if (concept && allNotes) { - const { general, links } = concept; - let { notes } = concept; - const { conceptVersion, isValidated, creator } = general; - const { authType, roles, stamp } = permission; - const authImpl = check(authType); - const adminOrContributorOrConceptCreator = authImpl.isAdminOrContributorOrConceptCreator( - roles, - stamp, - creator - ); - if ( - !adminOrContributorOrConceptCreator && - isValidated === 'false' && - conceptVersion === '1' - ) - return ; - if ( - conceptVersion !== '1' && - isValidated === 'false' && - !adminOrContributorOrConceptCreator - ) { - general.isValidated = 'true'; - general.conceptVersion = (general.conceptVersion - 1).toString(); - notes = allNotes[general.conceptVersion]; - } - - return ( - - ); - } - return ; + if(publishing){ + return ; } -} + if(loading){ + return + } + + const { general, links } = concept; + let { notes } = concept; -const mapStateToProps = (state, ownProps) => { - const id = extractId(ownProps); - let allNotes; - const general = select.getConceptGeneral(state, id); - if (general) { - allNotes = select.getAllNotes(state, id, general.conceptVersion); + const { conceptVersion, isValidated, creator } = general; + const { authType, roles, stamp } = permission; + const authImpl = check(authType); + const adminOrContributorOrConceptCreator = authImpl.isAdminOrContributorOrConceptCreator( + roles, + stamp, + creator + ); + if ( + !adminOrContributorOrConceptCreator && + isValidated === 'false' && + conceptVersion === '1' + ) + return ; + + if ( + conceptVersion !== '1' && + isValidated === 'false' && + !adminOrContributorOrConceptCreator + ) { + general.isValidated = 'true'; + general.conceptVersion = (general.conceptVersion - 1).toString(); + notes = allNotes[general.conceptVersion]; } - return { - id, - permission: Auth.getPermission(state), - secondLang: Stores.SecondLang.getSecondLang(state), - concept: select.getConcept(state, id), - allNotes, - validationStatus: select.getStatus(state, VALIDATE_CONCEPT_LIST), - deleteStatus: select.getStatus(state, DELETE_CONCEPT), - deleteSuccessStatus: select.getStatus(state, DELETE_CONCEPT_SUCCESS), - deleteFailureStatus: select.getStatus(state, DELETE_CONCEPT_FAILURE), - langs: select.getLangs(state), - error: select.getError(state, DELETE_CONCEPT), - }; -}; - -const mapDispatchToProps = { - loadConcept, - loadConceptAndAllNotes, - validateConcept: id => validateConcepts([id]), - deleteConcept: id => deleteConcept(id), -}; - -ConceptVisualizationContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ConceptVisualizationContainer); - -ConceptVisualizationContainer.propTypes = { - match: PropTypes.shape({ - params: PropTypes.shape({ - id: PropTypes.string.isRequired, - }), - }), -}; + + + + return ( + + ); + +} export default ConceptVisualizationContainer; diff --git a/app/src/js/applications/concepts/visualization/links.js b/app/src/js/applications/concepts/visualization/links.js index b745da961..a89d5bef8 100644 --- a/app/src/js/applications/concepts/visualization/links.js +++ b/app/src/js/applications/concepts/visualization/links.js @@ -3,122 +3,79 @@ import { Link } from 'react-router-dom'; import { D1, D2 } from 'js/i18n'; import { Note } from '@inseefr/wilco'; import { ArrayUtils } from 'bauhaus-utilities'; -import { BROADER, NARROWER, REFERENCES, SUCCEED, RELATED, CLOSE_MATCH } from 'js/constants'; -const sortByLabelLg1 = ArrayUtils.sortArray('prefLabelLg1'); -const sortByLabelLg2 = ArrayUtils.sortArray('prefLabelLg2'); +import { BROADER, CLOSE_MATCH, IS_REPLACED_BY, NARROWER, REFERENCES, RELATED, SUCCEED } from 'js/constants'; +import "./links.scss"; -const CloseMatchLinks = ({links, Dictionnary}) => { +const CloseMatchLinks = ({ links, Dictionnary }) => { return links.length > 0 && ( -
  • {Dictionnary.equivalentTitle} :
  • - ) -} -function ConceptLinks({ secondLang, links }) { - var nbLinks = 0; +
  • {Dictionnary.equivalentTitle} : + +
  • + ); +}; - const narrower = []; - const broader = []; - const references = []; - const replaces = []; - const related = []; - const closeMatch = []; +const InternalLinks = ({ links, title, labelProperty }) => { + return links.length > 0 && ( + <> +
    {title}
    + { + ArrayUtils.sortArray(labelProperty)(links).map(link => ( +
    + {link[labelProperty]} +
    + )) + } + + ); +}; - for (var i = 0; i < links.length; i++) { - if (links[i].typeOfLink === NARROWER) { - narrower.push(links[i]); - nbLinks++; - } - if (links[i].typeOfLink === BROADER) { - broader.push(links[i]); - nbLinks++; - } - if (links[i].typeOfLink === REFERENCES) { - references.push(links[i]); - nbLinks++; +const LinksList = ({ links, lang, alone, Dictionnary = D1 }) => { + const labelProperty = lang === 'lg1' ? 'prefLabelLg1' : 'prefLabelLg2'; + return ( + + + + + + + + } - if (links[i].typeOfLink === SUCCEED) { - replaces.push(links[i]); - nbLinks++; - } - if (links[i].typeOfLink === RELATED) { - related.push(links[i]); - nbLinks++; + title={Dictionnary.linksTitle} + lang={lang} + alone={alone} + />); +}; + +function ConceptLinks({ secondLang, links }) { + const linksGroupByType = links.reduce((acc, link) => { + if(!Array.isArray(acc[link.typeOfLink])){ + return acc; } - if (links[i].typeOfLink === CLOSE_MATCH) { - closeMatch.push(links[i]); - nbLinks++; + return { + ...acc, + [link.typeOfLink]: [...acc[[link.typeOfLink]], link] } - } - - const buildLi = (array, label) => - array.map(item => ( -
  • - {item[label]} -
  • - )); - - const buildList = array => ({ - lg1: buildLi(sortByLabelLg1(array), 'prefLabelLg1'), - lg2: buildLi(sortByLabelLg2(array), 'prefLabelLg2'), - }); - - const narrowerList = buildList(narrower); - const broaderList = buildList(broader); - const referencesList = buildList(references); - const replacesList = buildList(replaces); - const relatedList = buildList(related); - - const isEmpty = array => { - if (array.length === 0) return false; - else return true; - }; - - // Don't display links panel if there isn't links - if (nbLinks === 0) return null; - - const content = (lang, alone, Dictionnary = D1) => ( - - {isEmpty(narrower) && ( -
  • - {Dictionnary.narrowerTitle} :
      {narrowerList[lang]}
    -
  • - )} - {isEmpty(broader) && ( -
  • - {Dictionnary.broaderTitle} :
      {broaderList[lang]}
    -
  • - )} - {isEmpty(references) && ( -
  • - {Dictionnary.referencesTitle} :
      {referencesList[lang]}
    -
  • - )} - {isEmpty(replaces) && ( -
  • - {Dictionnary.replacesTitle} :
      {replacesList[lang]}
    -
  • - )} - {isEmpty(related) && ( -
  • - {Dictionnary.relatedTitle} :
      {relatedList[lang]}
    -
  • - )} - - - } - title={Dictionnary.linksTitle} - lang={lang} - alone={alone} - /> - ); + }, { + [NARROWER]: [], + [BROADER]: [], + [REFERENCES]: [], + [SUCCEED]: [], + [RELATED]: [], + [CLOSE_MATCH]: [], + [IS_REPLACED_BY]: [] + }) + const numberOfLinks = Object.values(linksGroupByType).flat().length + if (numberOfLinks === 0) return null; return ( -
    - {content('lg1', !secondLang)} - {secondLang && content('lg2', false, D2)} +
    + + {secondLang && }
    ); } diff --git a/app/src/js/applications/concepts/visualization/links.scss b/app/src/js/applications/concepts/visualization/links.scss new file mode 100644 index 000000000..c7f3536e3 --- /dev/null +++ b/app/src/js/applications/concepts/visualization/links.scss @@ -0,0 +1,3 @@ +.concept-links dd { + margin: revert; +} diff --git a/app/src/js/applications/operations/indicators/search.spec.js b/app/src/js/applications/operations/indicators/search.spec.js index 0e86fadf1..d61cded06 100644 --- a/app/src/js/applications/operations/indicators/search.spec.js +++ b/app/src/js/applications/operations/indicators/search.spec.js @@ -1,6 +1,6 @@ import { SearchFormList } from './search'; import React from 'react'; -import { render, fireEvent, waitForElement } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import { MemoryRouter } from 'react-router'; const data = [ { @@ -351,7 +351,7 @@ describe('', () => { const listOptions = container.querySelector('label[for="creator"] input'); fireEvent.keyDown(listOptions, { key: 'ArrowDown' }); - const option = await waitForElement(() => findByText('DG57-C060')); + const option = await findByText('DG57-C060'); fireEvent.click(option); expect(container.querySelectorAll('li')).toHaveLength(1); }); @@ -369,7 +369,7 @@ describe('', () => { const listOptions = container.querySelector('label[for="publisher"] input'); fireEvent.keyDown(listOptions, { key: 'ArrowDown' }); - const option = await waitForElement(() => findByText('DG75-L002')); + const option = await findByText('DG75-L002'); fireEvent.click(option); expect(container.querySelectorAll('li')).toHaveLength(1); }); diff --git a/app/src/js/applications/operations/msd/pages/sims-creation/index.js b/app/src/js/applications/operations/msd/pages/sims-creation/index.js index 17242b487..44ab0b1f2 100644 --- a/app/src/js/applications/operations/msd/pages/sims-creation/index.js +++ b/app/src/js/applications/operations/msd/pages/sims-creation/index.js @@ -201,7 +201,7 @@ class SimsCreation extends React.Component { label: op.labelLg1, value: op.idSims, }) - ); + ).sort((o1, o2) => o1.label.toLowerCase().localeCompare(o2.label.toLowerCase())); function MSDInformations(msd, handleChange, firstLevel = false) { return ( @@ -312,7 +312,7 @@ class SimsCreation extends React.Component { /> )} - {mode !== DUPLICATE && operationsWithSimsOptions.length > 0 && ( + {mode !== DUPLICATE && ( { }) } }, [seriesId, parentType, familyId]) - return + return } } diff --git a/app/src/js/applications/operations/series/search.spec.js b/app/src/js/applications/operations/series/search.spec.js index e228c214f..5c9a46c61 100644 --- a/app/src/js/applications/operations/series/search.spec.js +++ b/app/src/js/applications/operations/series/search.spec.js @@ -1,6 +1,6 @@ import { SearchFormList } from './search'; import React from 'react'; -import { render, fireEvent, waitForElement } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import { MemoryRouter } from 'react-router'; const data = [ { @@ -179,7 +179,7 @@ describe('', () => { const listOptions = container.querySelector('label[for="creator"] input'); fireEvent.keyDown(listOptions, { key: 'ArrowDown' }); - const option = await waitForElement(() => findByText('DG57-C003')); + const option = await findByText('DG57-C003'); fireEvent.click(option); expect(container.querySelectorAll('li')).toHaveLength(1); }); @@ -198,7 +198,7 @@ describe('', () => { const listOptions = container.querySelector('label[for="publisher"] input'); fireEvent.keyDown(listOptions, { key: 'ArrowDown' }); - const option = await waitForElement(() => findByText('Acoss')); + const option = await findByText('Acoss'); fireEvent.click(option); expect(container.querySelectorAll('li')).toHaveLength(1); }); @@ -219,7 +219,7 @@ describe('', () => { 'label[for="dataCollector"] input' ); fireEvent.keyDown(listOptions, { key: 'ArrowDown' }); - const option = await waitForElement(() => findByText('DG75-A040')); + const option = await findByText('DG75-A040'); fireEvent.click(option); expect(container.querySelectorAll('li')).toHaveLength(1); }); diff --git a/app/src/js/constants/app.js b/app/src/js/constants/app.js index 9a8380066..1232072dc 100644 --- a/app/src/js/constants/app.js +++ b/app/src/js/constants/app.js @@ -27,5 +27,6 @@ export const NARROWER = 'narrower'; export const REFERENCES = 'references'; export const SUCCEED = 'succeed'; export const RELATED = 'related'; +export const IS_REPLACED_BY = 'succeededBy'; export const CLOSE_MATCH = 'closeMatch'; export const NONE = ''; //local only: to ignore concept not linked diff --git a/app/src/js/i18n/dictionary/app.js b/app/src/js/i18n/dictionary/app.js index bcbfe6b15..8f8fd5b66 100644 --- a/app/src/js/i18n/dictionary/app.js +++ b/app/src/js/i18n/dictionary/app.js @@ -220,12 +220,12 @@ const dictionary = { ...btnD, // Links narrowerTitle: { - fr: 'Parent', - en: 'Parent', + fr: 'A pour enfant', + en: 'Has child', }, broaderTitle: { - fr: 'Enfant', - en: 'Child', + fr: 'A pour parent', + en: 'Has parent', }, referencesTitle: { fr: 'Référence', @@ -236,12 +236,12 @@ const dictionary = { en: 'Replaces', }, relatedTitle: { - fr: 'Lié', - en: 'Related', + fr: 'Est lié à', + en: 'Is related to', }, equivalentTitle: { - fr: 'Équivalent', - en: 'Equivalent', + fr: 'Correspond à', + en: 'Matches', }, // Mail mailTitle: { diff --git a/app/src/js/reducers/collections/by-id/general.js b/app/src/js/reducers/collections/by-id/general.js deleted file mode 100644 index 73bf2cfae..000000000 --- a/app/src/js/reducers/collections/by-id/general.js +++ /dev/null @@ -1,42 +0,0 @@ -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; -import * as generalUtils from 'js/utils/collections/general'; - -export default function(state = {}, action) { - const { type, payload } = action; - switch (type) { - case A.UPDATE_COLLECTION_SUCCESS: { - const { id } = payload; - return { - ...state, - [id]: {}, - }; - } - case A.VALIDATE_COLLECTION_LIST_SUCCESS: { - const { ids } = payload; - const newState = { - ...state, - }; - ids.forEach(id => (newState[id] = {})); - return newState; - } - case A.LOAD_COLLECTION_GENERAL_SUCCESS: { - const { id, results } = payload; - return { - ...state, - [id]: { - status: LOADED, - //ensure that all the fields are present (the server - //does not return the fields not defined) - results: Object.assign(generalUtils.empty(), results), - }, - }; - } - default: - return state; - } -} - -export function getGeneral(state, id) { - return state[id] && state[id].results; -} diff --git a/app/src/js/reducers/collections/by-id/general.spec.js b/app/src/js/reducers/collections/by-id/general.spec.js deleted file mode 100644 index 09eac4f36..000000000 --- a/app/src/js/reducers/collections/by-id/general.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -import reducerCollectionsGeneral, { getGeneral } from './general'; -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; -import * as generalUtils from 'js/utils/collections/general'; - -describe('reducerCollectionsGeneral', () => { - test('action UPDATE_COLLECTION_SUCCESS', () => { - const action = { - type: A.UPDATE_COLLECTION_SUCCESS, - payload: { id: 'id1' }, - }; - const result = reducerCollectionsGeneral( - { id1: 'previous', id2: 'previous' }, - action - ); - expect(result).toEqual({ id1: {}, id2: 'previous' }); - }); - test('action VALIDATE_COLLECTION_LIST_SUCCESS', () => { - const action = { - type: A.VALIDATE_COLLECTION_LIST_SUCCESS, - payload: { ids: ['id1', 'id2'] }, - }; - const result = reducerCollectionsGeneral( - { id1: 'previous', id2: 'previous', id3: 'previous' }, - action - ); - expect(result).toEqual({ id1: {}, id2: {}, id3: 'previous' }); - }); - test('action LOAD_COLLECTION_GENERAL_SUCCESS', () => { - const action = { - type: A.LOAD_COLLECTION_GENERAL_SUCCESS, - payload: { id: 'id1', results: { prefLabelLg1: 'My collection' } }, - }; - const result = reducerCollectionsGeneral({}, action); - expect(result).toEqual({ - id1: { - status: LOADED, - results: Object.assign(generalUtils.empty(), { - prefLabelLg1: 'My collection', - }), - }, - }); - }); -}); - -describe('getGeneral', () => { - test('getGeneral selector should extract nothing', () => { - const result = getGeneral({ id1: { results: 'results' } }, 'id2'); - expect(result).toEqual(); - }); - test('getGeneral selector should extract results', () => { - const result = getGeneral({ id1: { results: 'results' } }, 'id1'); - expect(result).toEqual('results'); - }); -}); diff --git a/app/src/js/reducers/collections/by-id/index.js b/app/src/js/reducers/collections/by-id/index.js deleted file mode 100644 index 600d4e513..000000000 --- a/app/src/js/reducers/collections/by-id/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import { getGeneral } from './general'; -import { getMembers } from './members'; - -/** - * Returns the collection with the givend if everything (general, members) has - * been loaded - * - * @export - * @param {object} state - * @param {string} id - * @returns {object} - */ -export function getCollection(state, id) { - const general = getGeneral(state.general, id); - if (!general) return; - const members = getMembers(state.members, id); - if (!members) return; - return { - general, - members, - }; -} diff --git a/app/src/js/reducers/collections/by-id/index.spec.js b/app/src/js/reducers/collections/by-id/index.spec.js deleted file mode 100644 index 1a0d7175c..000000000 --- a/app/src/js/reducers/collections/by-id/index.spec.js +++ /dev/null @@ -1,24 +0,0 @@ -import { getCollection } from './'; - -describe('getCollection', () => { - test('getCollection selector should extract results', () => { - const result = getCollection( - { - general: {}, - members: {}, - }, - 'id1' - ); - expect(result).toEqual(); - }); - test('getCollection selector should extract results', () => { - const result = getCollection( - { - general: { id1: { results: 'general id1' } }, - members: { id1: { results: 'members id1' } }, - }, - 'id1' - ); - expect(result).toEqual({ general: 'general id1', members: 'members id1' }); - }); -}); diff --git a/app/src/js/reducers/collections/by-id/members.js b/app/src/js/reducers/collections/by-id/members.js deleted file mode 100644 index 8865bc4c1..000000000 --- a/app/src/js/reducers/collections/by-id/members.js +++ /dev/null @@ -1,24 +0,0 @@ -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; - -export default function(state = {}, action) { - const { type, payload } = action; - switch (type) { - case A.LOAD_COLLECTION_MEMBERS_SUCCESS: { - const { id, results } = payload; - return { - ...state, - [id]: { - status: LOADED, - results, - }, - }; - } - default: - return state; - } -} - -export function getMembers(state, collectionId) { - return state[collectionId] && state[collectionId].results; -} diff --git a/app/src/js/reducers/collections/by-id/members.spec.js b/app/src/js/reducers/collections/by-id/members.spec.js deleted file mode 100644 index 3318d5ff4..000000000 --- a/app/src/js/reducers/collections/by-id/members.spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import reducerCollectionsMembers, { getMembers } from './members'; -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; - -describe('reducerCollectionsMembers', () => { - test('action LOAD_COLLECTION_MEMBERS_SUCCESS', () => { - const action = { - type: A.LOAD_COLLECTION_MEMBERS_SUCCESS, - payload: { id: 'id1', results: 'members' }, - }; - const result = reducerCollectionsMembers( - { id1: 'previous', id2: 'previous' }, - action - ); - expect(result).toEqual({ - id1: { - status: LOADED, - results: 'members', - }, - id2: 'previous', - }); - }); -}); - -describe('getMembers', () => { - test('getMembers selector should extract nothing', () => { - const result = getMembers({ id1: { results: 'members' } }, 'id2'); - expect(result).toEqual(); - }); - test('getMembers selector should extract results', () => { - const result = getMembers({ id1: { results: 'members' } }, 'id1'); - expect(result).toEqual('members'); - }); -}); diff --git a/app/src/js/reducers/collections/index.js b/app/src/js/reducers/collections/index.js deleted file mode 100644 index 650f31381..000000000 --- a/app/src/js/reducers/collections/index.js +++ /dev/null @@ -1,30 +0,0 @@ -import listReducer from '../utils/list-reducer'; -import collectionGeneral from './by-id/general'; -import collectionMembers from './by-id/members'; -import * as A from 'js/actions/constants'; -import { handleReset } from 'js/reducers/utils/reset-reducer'; - -const collectionList = handleReset( - listReducer([ - A.LOAD_COLLECTION_LIST, - A.LOAD_COLLECTION_LIST_SUCCESS, - A.LOAD_COLLECTION_LIST_FAILURE, - ]), - [A.CREATE_COLLECTION, A.UPDATE_COLLECTION] -); - -const collectionToValidateList = handleReset( - listReducer([ - A.LOAD_COLLECTION_VALIDATE_LIST, - A.LOAD_COLLECTION_VALIDATE_LIST_SUCCESS, - A.LOAD_COLLECTION_VALIDATE_LIST_FAILURE, - ]), - [A.CREATE_COLLECTION, A.UPDATE_COLLECTION, A.VALIDATE_COLLECTION_LIST] -); - -export default { - collectionList, - collectionToValidateList, - collectionGeneral, - collectionMembers, -}; diff --git a/app/src/js/reducers/concepts/by-id/general.js b/app/src/js/reducers/concepts/by-id/general.js deleted file mode 100755 index 81c33601b..000000000 --- a/app/src/js/reducers/concepts/by-id/general.js +++ /dev/null @@ -1,49 +0,0 @@ -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; -import * as generalUtils from 'js/utils/concepts/general'; - -export default function(state = {}, action) { - const { type, payload } = action; - switch (type) { - case A.DELETE_CONCEPT_SUCCESS: { - const { id } = payload; - return { - ...state, - [id]: {}, - }; - } - case A.UPDATE_CONCEPT_SUCCESS: { - const { id } = payload; - return { - ...state, - [id]: {}, - }; - } - case A.VALIDATE_CONCEPT_LIST_SUCCESS: { - const { ids } = payload; - const newState = { - ...state, - }; - ids.forEach(id => (newState[id] = {})); - return newState; - } - case A.LOAD_CONCEPT_GENERAL_SUCCESS: { - const { id, results } = payload; - return { - ...state, - [id]: { - status: LOADED, - //ensure that all the fields are present (the server - //does not return the fields not defined) - results: Object.assign(generalUtils.empty(), results), - }, - }; - } - default: - return state; - } -} - -export function getGeneral(state, id) { - return state[id] && state[id].results; -} diff --git a/app/src/js/reducers/concepts/by-id/general.spec.js b/app/src/js/reducers/concepts/by-id/general.spec.js deleted file mode 100644 index 393fec7e1..000000000 --- a/app/src/js/reducers/concepts/by-id/general.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -import reducerConceptsGeneral, { getGeneral } from './general'; -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; -import * as generalUtils from 'js/utils/concepts/general'; - -describe('reducerConceptsGeneral', () => { - test('action UPDATE_CONCEPT_SUCCESS', () => { - const action = { - type: A.UPDATE_CONCEPT_SUCCESS, - payload: { id: 'id1' }, - }; - const result = reducerConceptsGeneral( - { id1: 'previous', id2: 'previous' }, - action - ); - expect(result).toEqual({ id1: {}, id2: 'previous' }); - }); - test('action VALIDATE_CONCEPT_LIST_SUCCESS', () => { - const action = { - type: A.VALIDATE_CONCEPT_LIST_SUCCESS, - payload: { ids: ['id1', 'id2'] }, - }; - const result = reducerConceptsGeneral( - { id1: 'previous', id2: 'previous', id3: 'previous' }, - action - ); - expect(result).toEqual({ id1: {}, id2: {}, id3: 'previous' }); - }); - test('action LOAD_CONCEPT_GENERAL_SUCCESS', () => { - const action = { - type: A.LOAD_CONCEPT_GENERAL_SUCCESS, - payload: { id: 'id1', results: { prefLabelLg1: 'My concept' } }, - }; - const result = reducerConceptsGeneral({}, action); - expect(result).toEqual({ - id1: { - status: LOADED, - results: Object.assign(generalUtils.empty(), { - prefLabelLg1: 'My concept', - }), - }, - }); - }); -}); - -describe('getGeneral', () => { - test('getGeneral selector should extract nothing', () => { - const result = getGeneral({ id1: { results: 'results' } }, 'id2'); - expect(result).toEqual(); - }); - test('getGeneral selector should extract results', () => { - const result = getGeneral({ id1: { results: 'results' } }, 'id1'); - expect(result).toEqual('results'); - }); -}); diff --git a/app/src/js/reducers/concepts/by-id/index.js b/app/src/js/reducers/concepts/by-id/index.js deleted file mode 100644 index 5fe7ea76c..000000000 --- a/app/src/js/reducers/concepts/by-id/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import { getGeneral } from './general'; -import { getNotes } from './notes'; -import { getLinks } from './links'; - -/** - * Returns the concept with the givend if everything (general, notes, links) has - * been loaded - * - * @export - * @param {object} state - * @param {string} id - * @returns {object} - */ -export function getConcept(state, id) { - const general = getGeneral(state.general, id); - if (!general) return; - const notes = getNotes(state.notes, id, general.conceptVersion); - if (!notes) return; - const links = getLinks(state.links, id); - if (!links) return; - return { - general, - notes, - links, - }; -} diff --git a/app/src/js/reducers/concepts/by-id/index.spec.js b/app/src/js/reducers/concepts/by-id/index.spec.js deleted file mode 100644 index c97ab1020..000000000 --- a/app/src/js/reducers/concepts/by-id/index.spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import { getConcept } from './'; -import { LOADED } from 'js/constants'; - -describe('getConcept', () => { - test('getConcept selector should extract results', () => { - const result = getConcept( - { - general: {}, - }, - 'id1' - ); - expect(result).toEqual(); - }); - test('getConcept selector should extract results', () => { - const result = getConcept( - { - general: { - id1: { results: { prefLabelLg1: 'My concept', conceptVersion: '2' } }, - }, - notes: { - id1: { - 1: { status: LOADED, results: 'id1 notes v1' }, - 2: { status: LOADED, results: 'id1 notes v2' }, - }, - }, - links: { id1: { results: 'links id1' } }, - }, - 'id1' - ); - expect(result).toEqual({ - general: { prefLabelLg1: 'My concept', conceptVersion: '2' }, - notes: 'id1 notes v2', - links: 'links id1', - }); - }); -}); diff --git a/app/src/js/reducers/concepts/by-id/links.js b/app/src/js/reducers/concepts/by-id/links.js deleted file mode 100755 index 9ed085687..000000000 --- a/app/src/js/reducers/concepts/by-id/links.js +++ /dev/null @@ -1,31 +0,0 @@ -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; - -export default function(state = {}, action) { - const { type, payload } = action; - switch (type) { - case A.DELETE_CONCEPT_SUCCESS: { - const { id } = payload; - return { - ...state, - [id]: {}, - }; - } - case A.LOAD_CONCEPT_LINKS_SUCCESS: { - const { id, results } = payload; - return { - ...state, - [id]: { - status: LOADED, - results, - }, - }; - } - default: - return state; - } -} - -export function getLinks(state, conceptId) { - return state[conceptId] && state[conceptId].results; -} diff --git a/app/src/js/reducers/concepts/by-id/links.spec.js b/app/src/js/reducers/concepts/by-id/links.spec.js deleted file mode 100644 index ec149d1cd..000000000 --- a/app/src/js/reducers/concepts/by-id/links.spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import reducerConceptsLinks, { getLinks } from './links'; -import * as A from 'js/actions/constants'; -import { LOADED } from 'js/constants'; - -describe('reducerConceptsLinks', () => { - test('action LOAD_CONCEPT_LINKS_SUCCESS', () => { - const action = { - type: A.LOAD_CONCEPT_LINKS_SUCCESS, - payload: { id: 'id1', results: 'links' }, - }; - const result = reducerConceptsLinks( - { id1: 'previous', id2: 'previous' }, - action - ); - expect(result).toEqual({ - id1: { - status: LOADED, - results: 'links', - }, - id2: 'previous', - }); - }); -}); - -describe('getLinks', () => { - test('getLinks selector should extract nothing', () => { - const result = getLinks({ id1: { results: 'links' } }, 'id2'); - expect(result).toEqual(); - }); - test('getLinks selector should extract results', () => { - const result = getLinks({ id1: { results: 'links' } }, 'id1'); - expect(result).toEqual('links'); - }); -}); diff --git a/app/src/js/reducers/concepts/by-id/notes.js b/app/src/js/reducers/concepts/by-id/notes.js deleted file mode 100755 index 4a5eb0a22..000000000 --- a/app/src/js/reducers/concepts/by-id/notes.js +++ /dev/null @@ -1,69 +0,0 @@ -import * as A from 'js/actions/constants'; -import { LOADING, LOADED } from 'js/constants'; -import { ArrayUtils } from 'bauhaus-utilities'; - -export default function(state = {}, action) { - const { type, payload } = action; - switch (type) { - case A.DELETE_CONCEPT_SUCCESS: { - const { id } = payload; - return { - ...state, - [id]: {}, - }; - } - case A.LOAD_NOTES_VERSION: - const { id, version } = payload; - const otherVersions = state[id]; - return { - ...state, - [id]: { - ...otherVersions, - [version]: { - status: LOADING, - }, - }, - }; - case A.LOAD_NOTES_VERSION_SUCCESS: { - const { id, version, results } = payload; - const otherVersions = state[id]; - return { - ...state, - [id]: { - //on conserve les versions déjà chargées - ...otherVersions, - //on ajoute la nouvelle version - [version]: { - status: LOADED, - results, - }, - }, - }; - } - default: - return state; - } -} - -export const getNotes = (state, conceptId, conceptVersion) => { - const allNotes = state[conceptId]; - if (!allNotes) return null; - const versionNotes = allNotes[conceptVersion]; - return versionNotes && versionNotes.results; -}; - -export const getAllNotes = (state, conceptId, lastVersion) => { - const allNotes = state[conceptId]; - if (!allNotes) return null; - const notes = Object.keys(allNotes).reduce((notes, version) => { - const notesVersion = allNotes[version]; - if (notesVersion && notesVersion.results) - notes[version] = notesVersion.results; - return notes; - }, {}); - const versions = ArrayUtils.range(1, Number(lastVersion) + 1); - //return notes only if each expected version is present - if (versions.every(version => version in notes)) { - return notes; - } -}; diff --git a/app/src/js/reducers/concepts/by-id/notes.spec.js b/app/src/js/reducers/concepts/by-id/notes.spec.js deleted file mode 100644 index 5aa2c1b8c..000000000 --- a/app/src/js/reducers/concepts/by-id/notes.spec.js +++ /dev/null @@ -1,92 +0,0 @@ -import reducerConceptsNotes, { getNotes, getAllNotes } from './notes'; -import * as A from 'js/actions/constants'; -import { LOADING, LOADED } from 'js/constants'; - -describe('reducerConceptsNotes', () => { - test('action LOAD_NOTES_VERSION', () => { - const action = { - type: A.LOAD_NOTES_VERSION, - payload: { id: 'id1', version: 2 }, - }; - const result = reducerConceptsNotes( - { id1: { 1: { status: LOADED, results: 'id1 notes v1' } } }, - action - ); - expect(result).toEqual({ - id1: { - 1: { status: LOADED, results: 'id1 notes v1' }, - 2: { status: LOADING }, - }, - }); - }); - test('action LOAD_NOTES_VERSION_SUCCESS', () => { - const action = { - type: A.LOAD_NOTES_VERSION_SUCCESS, - payload: { id: 'id1', version: 2, results: 'id1 notes v2' }, - }; - const result = reducerConceptsNotes( - { id1: { 1: { status: LOADED, results: 'id1 notes v1' } } }, - action - ); - expect(result).toEqual({ - id1: { - 1: { status: LOADED, results: 'id1 notes v1' }, - 2: { status: LOADED, results: 'id1 notes v2' }, - }, - }); - }); -}); - -describe('getNotes', () => { - test('getNotes selector should extract nothing', () => { - const result = getNotes( - { - id1: { - 1: { status: LOADED, results: 'id1 notes v1' }, - 2: { status: LOADED, results: 'id1 notes v2' }, - }, - }, - 'id1', - 3 - ); - expect(result).toEqual(); - }); - test('getNotes selector should extract results', () => { - const result = getNotes( - { - id1: { - 1: { status: LOADED, results: 'id1 notes v1' }, - 2: { status: LOADED, results: 'id1 notes v2' }, - }, - }, - 'id1', - 2 - ); - expect(result).toEqual('id1 notes v2'); - }); -}); - -describe('getAllNotes', () => { - test('getAllNotes selector should extract nothing', () => { - const result = getAllNotes( - { - id2: {}, - }, - 'id1' - ); - expect(result).toBeNull(); - }); - test('getAllNotes selector should extract results', () => { - const result = getAllNotes( - { - id1: { - 1: { status: LOADED, results: 'id1 notes v1' }, - 2: { status: LOADED, results: 'id1 notes v2' }, - }, - }, - 'id1', - 2 - ); - expect(result).toEqual({ 1: 'id1 notes v1', 2: 'id1 notes v2' }); - }); -}); diff --git a/app/src/js/reducers/concepts/index.js b/app/src/js/reducers/concepts/index.js deleted file mode 100644 index 0788aeb4f..000000000 --- a/app/src/js/reducers/concepts/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import conceptGeneral from './by-id/general'; -import conceptNotes from './by-id/notes'; -import conceptLinks from './by-id/links'; -import listReducer from '../utils/list-reducer'; -import * as A from 'js/actions/constants'; -import { handleReset } from 'js/reducers/utils/reset-reducer'; - -const conceptList = handleReset( - listReducer([ - A.LOAD_CONCEPT_LIST, - A.LOAD_CONCEPT_LIST_SUCCESS, - A.LOAD_CONCEPT_LIST_FAILURE, - ]), - [A.CREATE_CONCEPT, A.UPDATE_CONCEPT, A.DELETE_CONCEPT_SUCCESS] -); - -const conceptToValidateList = handleReset( - listReducer([ - A.LOAD_CONCEPT_VALIDATE_LIST, - A.LOAD_CONCEPT_VALIDATE_LIST_SUCCESS, - A.LOAD_CONCEPT_VALIDATE_LIST_FAILURE, - ]), - [A.CREATE_CONCEPT, A.UPDATE_CONCEPT, A.VALIDATE_CONCEPT_LIST] -); - -const conceptSearchList = handleReset( - listReducer([ - A.LOAD_CONCEPT_SEARCH_LIST, - A.LOAD_CONCEPT_SEARCH_LIST_SUCCESS, - A.LOAD_CONCEPT_SEARCH_LIST_FAILURE, - ]), - [A.CREATE_CONCEPT, A.UPDATE_CONCEPT, A.VALIDATE_CONCEPT_LIST] -); - -export default { - conceptList, - conceptSearchList, - conceptToValidateList, - conceptGeneral, - conceptNotes, - conceptLinks, -}; diff --git a/app/src/js/reducers/dashboard/index.js b/app/src/js/reducers/dashboard/index.js deleted file mode 100644 index 4653f4093..000000000 --- a/app/src/js/reducers/dashboard/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import listReducer from '../utils/list-reducer'; -import * as A from 'js/actions/constants'; - -export const handleReset = (reducer, actions) => (state, action) => { - //we pass the action to the reducer: it should have no effect, we just want - //to reinitialize the reducer but we cannot pas `undefined` as an action - if (actions.indexOf(action.type) !== -1) return reducer(undefined, action); - return reducer(state, action); -}; - -const collectionDashboardList = handleReset( - listReducer([ - A.LOAD_COLLECTION_DASHBOARD_LIST, - A.LOAD_COLLECTION_DASHBOARD_LIST_SUCCESS, - A.LOAD_COLLECTION_DASHBOARD_LIST_FAILURE, - ]), - [A.CREATE_COLLECTION, A.UPDATE_COLLECTION, A.VALIDATE_COLLECTION_LIST] -); - -export default { - collectionDashboardList, -}; diff --git a/app/src/js/reducers/index.js b/app/src/js/reducers/index.js index ae1b3bc43..9a4312cdc 100755 --- a/app/src/js/reducers/index.js +++ b/app/src/js/reducers/index.js @@ -2,14 +2,6 @@ import { getItems } from './utils/list-reducer'; import { combineReducers } from 'redux'; import app from './app'; import sharedReducers from './shared'; -import conceptReducers from './concepts'; -import * as conceptGeneral from './concepts/by-id/general'; -import * as notes from './concepts/by-id/notes'; -import * as links from './concepts/by-id/links'; -import * as collectionGeneral from './collections/by-id/general'; -import * as members from './collections/by-id/members'; -import collectionReducers from './collections'; -import dashboardReducers from './dashboard'; import classificationsReducers from './classifications'; import operationsReducers from './operations'; import codesListReducers from './operations/codesList'; @@ -21,9 +13,6 @@ import remoteCalls from './remote-calls'; export default combineReducers({ app, ...sharedReducers, - ...conceptReducers, - ...collectionReducers, - ...dashboardReducers, ...classificationsReducers, ...operationsReducers, ...codesListReducers, @@ -34,61 +23,6 @@ export default combineReducers({ remoteCalls, }); -export const getConceptList = (state) => getItems(state.conceptList); -export const getConceptSearchList = (state) => - getItems(state.conceptSearchList); -export const getConceptValidateList = (state) => - getItems(state.conceptToValidateList); - -export const getConceptGeneral = (state, id) => - conceptGeneral.getGeneral(state.conceptGeneral, id); -export const getNotes = (state, id, version) => - notes.getNotes(state.conceptNotes, id, version); -export const getLinks = (state, id) => links.getLinks(state.conceptLinks, id); - -export function getAllNotes(state, id, lastVersion) { - return notes.getAllNotes(state.conceptNotes, id, lastVersion); -} - -export function getConcept(state, id) { - const general = getConceptGeneral(state, id); - const links = getLinks(state, id); - let notes; - if (general) { - notes = getNotes(state, id, general.conceptVersion); - } - - if (!(general && notes && links)) return; - - return { - general, - notes, - links, - }; -} - -export const getCollectionList = (state) => getItems(state.collectionList); -export const getCollectionDashboardList = (state) => - getItems(state.collectionDashboardList); -export const getCollectionValidateList = (state) => - getItems(state.collectionToValidateList); - -export const getCollectionGeneral = (state, id) => - collectionGeneral.getGeneral(state.collectionGeneral, id); -export const getMembers = (state, id) => - members.getMembers(state.collectionMembers, id); - -export function getCollection(state, id) { - const general = getCollectionGeneral(state, id); - const members = getMembers(state, id); - - if (!(general && members)) return; - return { - general, - members, - }; -} - export const getRoleList = (state) => getItems(state.roleList); export const getAgentList = (state) => getItems(state.agentList); diff --git a/app/src/js/reducers/remote-calls.js b/app/src/js/reducers/remote-calls.js index 7aef77a18..2207dead8 100644 --- a/app/src/js/reducers/remote-calls.js +++ b/app/src/js/reducers/remote-calls.js @@ -87,23 +87,5 @@ export const trackActionReducer = actions => (state = {}, action) => { * */ export default trackActionReducer([ - [A.CREATE_CONCEPT, A.CREATE_CONCEPT_SUCCESS], - [A.UPDATE_CONCEPT, A.UPDATE_CONCEPT_SUCCESS, A.UPDATE_CONCEPT_FAILURE], - [ - A.DELETE_CONCEPT, - A.DELETE_CONCEPT_SUCCESS, - A.DELETE_CONCEPT_FAILURE, - [A.LOAD_CONCEPT_GENERAL_SUCCESS, A.LOAD_CONCEPT_LIST_SUCCESS], - ], - [A.EXPORT_CONCEPT_LIST, A.EXPORT_CONCEPT_LIST_SUCCESS], - [A.SEND_CONCEPT, A.SEND_CONCEPT_SUCCESS], - [A.VALIDATE_CONCEPT_LIST, A.VALIDATE_CONCEPT_LIST_SUCCESS], - [A.CREATE_COLLECTION, A.CREATE_COLLECTION_SUCCESS], - [A.UPDATE_COLLECTION, A.UPDATE_COLLECTION_SUCCESS], - [A.EXPORT_COLLECTION_LIST, A.EXPORT_COLLECTION_LIST_SUCCESS], - [A.SEND_COLLECTION, A.SEND_COLLECTION_SUCCESS], - [A.VALIDATE_COLLECTION_LIST, A.VALIDATE_COLLECTION_LIST_SUCCESS], - [A.ADD_ROLE, A.ADD_ROLE_SUCCESS], - [A.DELETE_ROLE, A.DELETE_ROLE_SUCCESS], [A.EXPORT_VARBOOK, A.EXPORT_VARBOOK_SUCCESS], ]); diff --git a/app/src/js/utils/concepts/links.js b/app/src/js/utils/concepts/links.js index 0985f9940..967f091e5 100644 --- a/app/src/js/utils/concepts/links.js +++ b/app/src/js/utils/concepts/links.js @@ -6,6 +6,7 @@ import { SUCCEED, RELATED, NONE, CLOSE_MATCH, + IS_REPLACED_BY } from 'js/constants'; const linkTypes = { @@ -15,6 +16,8 @@ const linkTypes = { [SUCCEED]: SUCCEED, [RELATED]: RELATED, [CLOSE_MATCH]: CLOSE_MATCH, + [IS_REPLACED_BY]: IS_REPLACED_BY, + }; const propTypesKindOfLink = PropTypes.oneOf([ @@ -24,6 +27,7 @@ const propTypesKindOfLink = PropTypes.oneOf([ SUCCEED, RELATED, NONE, + IS_REPLACED_BY ]); export const propTypes = PropTypes.arrayOf( diff --git a/package.json b/package.json index bb2c1749a..c8ee39da6 100644 --- a/package.json +++ b/package.json @@ -20,16 +20,16 @@ "@inseefr/wilco": "0.0.5" }, "devDependencies": { - "@babel/core": "7.11.6", - "@babel/preset-env": "7.11.5", + "@babel/core": "^7.16.12", + "@babel/preset-env": "^7.16.11", "@storybook/addon-actions": "5.3.19", "@storybook/addon-knobs": "5.3.19", "@storybook/addon-links": "5.3.19", "@storybook/addons": "5.3.19", "@storybook/react": "5.3.19", - "@testing-library/jest-dom": "5.14.1", - "@testing-library/react": "11.2.7", - "@testing-library/user-event": "13.1.9", + "@testing-library/jest-dom": "^5.16.1", + "@testing-library/react": "^12.1.2", + "@testing-library/user-event": "^13.5.0", "@types/jest": "26.0.16", "babel-eslint": "^10.1.0", "babel-jest": "26.0.1", @@ -39,30 +39,30 @@ "eslint-config-prettier": "6.15.0", "eslint-config-react-app": "6.0.0", "eslint-plugin-flowtype": "5.2.0", - "eslint-plugin-import": "2.22.1", + "eslint-plugin-import": "^2.25.4", "eslint-plugin-jest-dom": "3.2.4", - "eslint-plugin-jsx-a11y": "6.4.1", - "eslint-plugin-react": "7.21.5", - "eslint-plugin-react-hooks": "4.2.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-testing-library": "3.9.2", "husky": "4.3.0", "jest": "26.6.0", "jest-localstorage-mock": "2.4.3", "lcov-result-merger": "3.1.0", - "prettier": "2.3.2", - "webpack": "5.58.1" + "prettier": "^2.5.1", + "webpack": "^5.67.0" }, "dependencies": { "dompurify": "2.2.9", - "@babel/preset-react": "^7.12.13", + "@babel/preset-react": "^7.16.7", "jest-environment-jsdom-sixteen": "^1.0.3", - "prop-types": "15.7.2", + "prop-types": "^15.8.1", "react": "17.0.2", "react-dom": "17.0.2", - "react-redux": "7.2.0", + "react-redux": "^7.2.6", "react-router-dom": "5.2.0", - "redux": "4.0.5", - "rollup": "^2.53.2" + "redux": "4.1.2", + "rollup": "^2.67.0" }, "husky": { "hooks": { diff --git a/packages/codelists/package.json b/packages/codelists/package.json index b346a2f7e..b9e44e7be 100644 --- a/packages/codelists/package.json +++ b/packages/codelists/package.json @@ -14,10 +14,10 @@ "lint": "eslint src" }, "devDependencies": { - "@babel/plugin-proposal-class-properties": "7.10.4", - "@babel/plugin-transform-react-jsx": "7.10.4", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-transform-react-jsx": "^7.16.7", "identity-obj-proxy": "^3.0.0", - "rollup": "2.28.1", + "rollup": "^2.67.0", "rollup-plugin-babel": "^4.4.0", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-builtins": "^2.1.2", diff --git a/packages/codelists/src/components/codelist-detail/edit.js b/packages/codelists/src/components/codelist-detail/edit.js index c677d0762..56d5dee86 100644 --- a/packages/codelists/src/components/codelist-detail/edit.js +++ b/packages/codelists/src/components/codelist-detail/edit.js @@ -26,17 +26,20 @@ export const deleteNodes = (codes, currentNode) => { ); const findParent = (lengthCheck, parentNode) => { - return codes.filter( - (code) => - lengthCheck(code.parents?.length) && - code.parents?.find(({ code }) => code === parentNode.code) - ) || []; - - } - findParent(length => length === 1, currentNode).forEach((child) => deleteNode(child)); + return ( + codes.filter( + (code) => + lengthCheck(code.parents?.length) && + code.parents?.find(({ code }) => code === parentNode.code) + ) || [] + ); + }; + findParent((length) => length === 1, currentNode).forEach((child) => + deleteNode(child) + ); - const childrenToUpdate = findParent(length => length > 1, currentNode); - updatedCodes = updatedCodes.map(( updatedCode ) => { + const childrenToUpdate = findParent((length) => length > 1, currentNode); + updatedCodes = updatedCodes.map((updatedCode) => { const isPresent = !!childrenToUpdate.find( ({ code }) => code === updatedCode.code ); @@ -55,8 +58,8 @@ export const deleteNodes = (codes, currentNode) => { }; deleteNode(currentNode); - return updatedCodes -} + return updatedCodes; +}; const defaultCodelist = { contributor: 'DG75-L201', @@ -115,7 +118,6 @@ const DumbCodelistDetailEdit = ({ const updateCode = useCallback( (codeObject) => { - console.log(codeObject) const existing = codes.find((c) => c.code === codeObject.code); if (!existing) { // Create @@ -203,7 +205,7 @@ const DumbCodelistDetailEdit = ({ name="lastClassUriSegment" onChange={handleChange} value={codelist.lastClassUriSegment || ''} - /* disabled={updateMode} */ + disabled={updateMode} />
    diff --git a/packages/codelists/src/components/codelist-partial-detail/codes-tree-edit.js b/packages/codelists/src/components/codelist-partial-detail/codes-tree-edit.js index 22a28f730..984cce568 100644 --- a/packages/codelists/src/components/codelist-partial-detail/codes-tree-edit.js +++ b/packages/codelists/src/components/codelist-partial-detail/codes-tree-edit.js @@ -1,48 +1,28 @@ -import React, { useCallback, useState, useEffect, useContext } from 'react'; -import PropTypes from 'prop-types'; +import React, { useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; +import PropTypes from 'prop-types'; +import SlidingPanel from 'react-sliding-side-panel'; +import { ActionToolbar, Panel } from '@inseefr/wilco'; import { Stores } from 'bauhaus-utilities'; +import D from '../../i18n/build-dictionary'; +import { CollapsiblePanel } from '../collapsible-panel'; import RmesTree from '../tree'; -import { TreeContext } from '../tree/treeContext'; -import { CodeDetailEdit } from '../code-detail/edit'; -import { treedData } from '../../utils'; -import { emptyCode } from '../code-detail/empty-code'; +import { CodeDetailView } from '../code-detail/view'; +import CodeTitle from '../code-detail/title'; -export const syncNodes = (previousNodes = [], nextNodes = []) => { - if (previousNodes.length !== nextNodes.length) { - return nextNodes; - } - return nextNodes.map((node) => { - const previousNode = previousNodes.find(({ code }) => code === node.code); - - return { - ...node, - expanded: previousNode?.expanded || false, - position: - previousNode?.position || - (previousNodes.position ? Math.max(previousNodes.position) + 1 : 1), - children: syncNodes(previousNode?.children, node.children), - }; - }); -}; - -const CodesTreeEdit = ({ +const PartialCodesTreeEdit = ({ + hidden = false, codes, - deleteCode, - deleteCodeWithChildren, - updateCode, - createCode, + tree, + handleChangeTree, + addClickHandler, + removeClickHandler, + addAllClickHandler, + removeAllClickHandler, }) => { + const [openPanel, setOpenPanel] = useState(false); const secondLang = useSelector(Stores.SecondLang.getSecondLang); - const [selectedCode, setSelectedCode] = useState(emptyCode); - const [tree, setTree] = useContext(TreeContext); - - useEffect(() => { - const currentTree = treedData(Object.values(codes || {})); - setTree(syncNodes(tree, currentTree)); - // needs not to depend on tree to allow react-sortable-tree to update "expanded" - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [codes]); + const [selectedCode, setSelectedCode] = useState(null); const seeClickHandler = useCallback( (e) => { @@ -51,38 +31,98 @@ const CodesTreeEdit = ({ ); if (chosenCode) { setSelectedCode(chosenCode); + setOpenPanel(true); } }, [codes] ); return ( -
    -
    - -
    -
    - -
    -
    +