From b0fdc97f75aec7633c7a6c08cbc8a1f05532e589 Mon Sep 17 00:00:00 2001 From: Pavlov Viacheslav Date: Tue, 25 Sep 2018 13:19:41 +0300 Subject: [PATCH 1/2] Using modular approach for partners, descriptors, descriptorLists and datasets - added header to parent pages via Wrapper - added markdown support for PartnerFilter - removed most MyDataPage work with `tab` - removed '/accessions' link from user menu (+14 squashed commits) - now `editor` actions change both public and dashboard 'current' elements - split DashboardPage into 3 separate pages, now MyDataPage is base page for other dashboard pages - changed 'steps' routes, now steps declare once in 'steps.ts' - Removed "list...ByCode" service methods - migrated 'PageLoader' implementation from genesis-ui - dashboard reducer now don't contain loaded items, only selected UUID-s - moved constants to module folders - added module for vocabulary - put dashboard routes under '/dashboard' URL, put partner edit page under '/admin' URL - removed genesys page and related actions, service and constants - changed 'root' state names to 'public' --- src/actions/dashboard.ts | 223 ++------ src/actions/dataset.ts | 517 ------------------ src/actions/descriptorList.ts | 339 ------------ src/actions/descriptors.ts | 306 ----------- src/actions/genesys.ts | 40 -- src/actions/partner.ts | 141 ----- src/constants/dashboard.ts | 3 - src/constants/genesys.ts | 2 - src/datasets/actions/dashboard.ts | 122 +++++ src/datasets/actions/editor.ts | 421 ++++++++++++++ src/datasets/actions/public.ts | 76 +++ .../datasets.ts => datasets/constants.ts} | 6 + src/datasets/reducers/dashboard.ts | 172 ++++++ src/datasets/reducers/index.ts | 10 + src/datasets/reducers/public.ts | 79 +++ src/datasets/routes.ts | 79 +++ .../dataset => datasets/ui}/BrowsePage.tsx | 22 +- src/datasets/ui/DashboardPage.tsx | 43 ++ .../dataset => datasets/ui}/DisplayPage.tsx | 5 +- .../pages/dataset => datasets/ui}/c/Card.tsx | 0 .../ui}/c/DatasetDisplay.tsx | 0 .../dataset => datasets/ui}/c/Filters.tsx | 2 +- .../dataset => datasets/ui}/c/LocationMap.tsx | 0 .../ui}/dataset-stepper/index.tsx | 16 +- src/datasets/ui/dataset-stepper/steps.ts | 77 +++ .../steps/accessions-list/ListOfAccesion.tsx | 0 .../steps/accessions-list/index.tsx | 6 +- .../steps/basic-info/BasicInfoForm.tsx | 2 +- .../steps/basic-info/BasicInfoRadioGroup.tsx | 0 .../steps/basic-info/RemoteSubmit.ts | 2 +- .../steps/basic-info/index.tsx | 8 +- .../steps/creators/DatasetCreatorForm.tsx | 2 +- .../dataset-stepper/steps/creators/index.tsx | 10 +- .../dataset-stepper/steps/files/FilesForm.tsx | 2 +- .../ui}/dataset-stepper/steps/files/index.tsx | 6 +- .../steps/location/FormMap.tsx | 0 .../steps/location/LocationForm.tsx | 2 +- .../dataset-stepper/steps/location/index.tsx | 8 +- .../steps/pasting-traits/index.tsx | 8 +- .../dataset-stepper/steps/reorder/index.tsx | 6 +- .../dataset-stepper/steps/review/index.tsx | 6 +- .../dataset-stepper/steps/traits/index.tsx | 24 +- .../ui}/search/SuggestionsPage.tsx | 2 +- .../ui}/search/c/SearchHit.tsx | 0 .../ui}/search/c/SuggestionsForm.tsx | 0 .../ui}/search/c/hits/Crop.tsx | 0 .../ui}/search/c/hits/Dataset.tsx | 0 .../ui}/search/c/hits/Descriptor.tsx | 0 .../ui}/search/c/hits/Partner.tsx | 0 .../ui}/search/c/hits/_Generic.tsx | 0 src/descriptorlists/actions/dashboard.ts | 116 ++++ src/descriptorlists/actions/editor.ts | 200 +++++++ src/descriptorlists/actions/public.ts | 113 ++++ src/descriptorlists/reducers/dashboard.ts | 126 +++++ src/descriptorlists/reducers/index.ts | 10 + .../reducers/public.ts} | 32 +- src/descriptorlists/routes.ts | 76 +++ .../ui}/BrowsePage.tsx | 22 +- src/descriptorlists/ui/DashboardPage.tsx | 41 ++ .../ui}/DisplayPage.tsx | 6 +- .../ui}/c/DescriptorListDisplay.tsx | 0 .../ui}/c/DescriptorListForm.tsx | 4 +- .../ui}/c/Extras.tsx | 0 .../ui}/c/Filters.tsx | 2 +- .../ui}/descriptorlist-stepper/index.tsx | 12 +- .../ui/descriptorlist-stepper/steps.ts | 46 ++ .../steps/basic-info/RemoteSubmit.ts | 2 +- .../steps/basic-info/index.tsx | 14 +- .../steps/import/index.tsx | 8 +- .../steps/reorder/index.tsx | 6 +- .../steps/review/index.tsx | 8 +- .../steps/select/index.tsx | 23 +- src/descriptors/actions/dashboard.ts | 118 ++++ src/descriptors/actions/editor.ts | 156 ++++++ src/descriptors/actions/public.ts | 97 ++++ .../constants.ts} | 17 + src/descriptors/reducers/dashboard.ts | 133 +++++ src/descriptors/reducers/index.ts | 10 + .../reducers/public.ts} | 64 +-- src/descriptors/routes.ts | 56 ++ .../ui}/BrowsePage.tsx | 25 +- src/descriptors/ui/DashboardPage.tsx | 43 ++ .../ui}/DisplayPage.tsx | 8 +- .../ui}/EditPage.tsx | 6 +- .../ui}/c/DescriptorForm.tsx | 2 +- .../ui}/c/SelectVocabulary.tsx | 3 +- .../ui}/c/VocabularyForm.tsx | 2 +- src/partners/actions/dashboard.ts | 65 +++ src/partners/actions/editor.ts | 47 ++ src/partners/actions/public.ts | 71 +++ .../partner.ts => partners/constants.ts} | 8 + src/partners/reducers/dashboard.ts | 47 ++ src/partners/reducers/index.ts | 10 + .../reducers/public.ts} | 40 +- src/partners/routes.ts | 46 ++ .../partner => partners/ui}/BrowsePage.tsx | 24 +- .../partner => partners/ui}/DisplayPage.tsx | 8 +- .../partner => partners/ui}/EditPage.tsx | 5 +- .../partner => partners/ui}/c/Filters.tsx | 2 +- .../partner => partners/ui}/c/PartnerCard.tsx | 0 .../partner => partners/ui}/c/PartnerForm.tsx | 2 +- .../partner => partners/ui}/c/SearchMenu.tsx | 0 .../partner => partners/ui}/c/Summary.tsx | 0 src/reducers/dashboard.ts | 57 +- src/reducers/datasets.ts | 146 ----- src/reducers/index.ts | 10 +- src/service/DatasetService.ts | 34 +- src/service/DescriptorListService.ts | 34 +- src/service/DescriptorService.ts | 35 +- src/service/GenesysService.ts | 51 -- src/service/PartnerService.ts | 30 +- src/ui/catalog/Links.tsx | 18 +- src/ui/catalog/dashboard/MyDataPage.tsx | 195 +++++++ .../dashboard/c/DashboardActionsArea.tsx | 0 .../dashboard/c/DashboardActionsButton.tsx | 8 +- .../dashboard/c/DashboardButton.tsx | 0 .../dashboard/c/DashboardTableHeader.tsx | 7 +- .../dashboard/c/DashboardTableRow.tsx | 22 +- .../dashboard/c/Filters.tsx | 1 + .../dashboard/c/MyDataTable.tsx | 32 +- .../dashboard/c/StatusFilter.tsx | 0 .../descriptor/DescriptorListPicker.tsx | 2 +- .../descriptor/DescriptorSearchMenu.tsx | 2 +- src/ui/catalog/partner/SelectPartner.tsx | 12 +- .../vocabulary/VocabularyTermPicker.tsx | 2 +- src/ui/common/PagedLoader.tsx | 73 +-- src/ui/common/stepper/StepNavigation.tsx | 2 +- src/ui/common/stepper/progress-menu/index.tsx | 2 +- src/ui/layout/Header/UserMenuComponent.tsx | 1 - src/ui/pages/dashboard/DashboardPage.tsx | 114 ---- src/ui/pages/dashboard/MyDataPage.tsx | 303 ---------- src/ui/pages/dataset/dataset-stepper/steps.ts | 49 -- .../descriptorlist-stepper/steps.ts | 30 - src/ui/pages/genesys/BrowsePage.tsx | 408 -------------- src/ui/pages/genesys/DisplayPage.tsx | 217 -------- src/ui/pages/genesys/c/Filters.tsx | 34 -- src/ui/routes.tsx | 369 +------------ src/vocabulary/actions/admin.ts | 47 ++ .../actions/public.ts} | 34 +- .../vocabulary.ts => vocabulary/constants.ts} | 0 src/vocabulary/reducers/admin.ts | 32 ++ src/vocabulary/reducers/index.ts | 10 + .../reducers/public.ts} | 6 +- src/vocabulary/routes.ts | 47 ++ .../ui}/BrowsePage.tsx | 4 +- .../ui}/DisplayPage.tsx | 5 +- .../vocabulary => vocabulary/ui}/EditPage.tsx | 9 +- .../ui}/c/VocabularyCard.tsx | 0 .../ui}/c/VocabularyForm.tsx | 2 +- 149 files changed, 3511 insertions(+), 3762 deletions(-) delete mode 100644 src/actions/dataset.ts delete mode 100644 src/actions/descriptorList.ts delete mode 100644 src/actions/descriptors.ts delete mode 100644 src/actions/genesys.ts delete mode 100644 src/actions/partner.ts delete mode 100644 src/constants/genesys.ts create mode 100644 src/datasets/actions/dashboard.ts create mode 100644 src/datasets/actions/editor.ts create mode 100644 src/datasets/actions/public.ts rename src/{constants/datasets.ts => datasets/constants.ts} (76%) create mode 100644 src/datasets/reducers/dashboard.ts create mode 100644 src/datasets/reducers/index.ts create mode 100644 src/datasets/reducers/public.ts create mode 100644 src/datasets/routes.ts rename src/{ui/pages/dataset => datasets/ui}/BrowsePage.tsx (86%) create mode 100644 src/datasets/ui/DashboardPage.tsx rename src/{ui/pages/dataset => datasets/ui}/DisplayPage.tsx (94%) rename src/{ui/pages/dataset => datasets/ui}/c/Card.tsx (100%) rename src/{ui/pages/dataset => datasets/ui}/c/DatasetDisplay.tsx (100%) rename src/{ui/pages/dataset => datasets/ui}/c/Filters.tsx (97%) rename src/{ui/pages/dataset => datasets/ui}/c/LocationMap.tsx (100%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/index.tsx (88%) create mode 100644 src/datasets/ui/dataset-stepper/steps.ts rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/accessions-list/ListOfAccesion.tsx (100%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/accessions-list/index.tsx (92%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/basic-info/BasicInfoForm.tsx (98%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/basic-info/BasicInfoRadioGroup.tsx (100%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/basic-info/RemoteSubmit.ts (73%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/basic-info/index.tsx (91%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/creators/DatasetCreatorForm.tsx (99%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/creators/index.tsx (93%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/files/FilesForm.tsx (98%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/files/index.tsx (93%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/location/FormMap.tsx (100%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/location/LocationForm.tsx (99%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/location/index.tsx (94%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/pasting-traits/index.tsx (95%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/reorder/index.tsx (93%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/review/index.tsx (88%) rename src/{ui/pages/dataset => datasets/ui}/dataset-stepper/steps/traits/index.tsx (83%) rename src/{ui/pages => datasets/ui}/search/SuggestionsPage.tsx (98%) rename src/{ui/pages => datasets/ui}/search/c/SearchHit.tsx (100%) rename src/{ui/pages => datasets/ui}/search/c/SuggestionsForm.tsx (100%) rename src/{ui/pages => datasets/ui}/search/c/hits/Crop.tsx (100%) rename src/{ui/pages => datasets/ui}/search/c/hits/Dataset.tsx (100%) rename src/{ui/pages => datasets/ui}/search/c/hits/Descriptor.tsx (100%) rename src/{ui/pages => datasets/ui}/search/c/hits/Partner.tsx (100%) rename src/{ui/pages => datasets/ui}/search/c/hits/_Generic.tsx (100%) create mode 100644 src/descriptorlists/actions/dashboard.ts create mode 100644 src/descriptorlists/actions/editor.ts create mode 100644 src/descriptorlists/actions/public.ts create mode 100644 src/descriptorlists/reducers/dashboard.ts create mode 100644 src/descriptorlists/reducers/index.ts rename src/{reducers/descriptorList.ts => descriptorlists/reducers/public.ts} (74%) create mode 100644 src/descriptorlists/routes.ts rename src/{ui/pages/descriptorlist => descriptorlists/ui}/BrowsePage.tsx (86%) create mode 100644 src/descriptorlists/ui/DashboardPage.tsx rename src/{ui/pages/descriptorlist => descriptorlists/ui}/DisplayPage.tsx (95%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/c/DescriptorListDisplay.tsx (100%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/c/DescriptorListForm.tsx (96%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/c/Extras.tsx (100%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/c/Filters.tsx (96%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/index.tsx (91%) create mode 100644 src/descriptorlists/ui/descriptorlist-stepper/steps.ts rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts (72%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/steps/basic-info/index.tsx (84%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/steps/import/index.tsx (95%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/steps/reorder/index.tsx (93%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/steps/review/index.tsx (86%) rename src/{ui/pages/descriptorlist => descriptorlists/ui}/descriptorlist-stepper/steps/select/index.tsx (84%) create mode 100644 src/descriptors/actions/dashboard.ts create mode 100644 src/descriptors/actions/editor.ts create mode 100644 src/descriptors/actions/public.ts rename src/{constants/descriptors.ts => descriptors/constants.ts} (58%) create mode 100644 src/descriptors/reducers/dashboard.ts create mode 100644 src/descriptors/reducers/index.ts rename src/{reducers/descriptors.ts => descriptors/reducers/public.ts} (56%) create mode 100644 src/descriptors/routes.ts rename src/{ui/pages/descriptor => descriptors/ui}/BrowsePage.tsx (86%) create mode 100644 src/descriptors/ui/DashboardPage.tsx rename src/{ui/pages/descriptor => descriptors/ui}/DisplayPage.tsx (98%) rename src/{ui/pages/descriptor => descriptors/ui}/EditPage.tsx (95%) rename src/{ui/pages/descriptor => descriptors/ui}/c/DescriptorForm.tsx (99%) rename src/{ui/pages/descriptor => descriptors/ui}/c/SelectVocabulary.tsx (96%) rename src/{ui/pages/descriptor => descriptors/ui}/c/VocabularyForm.tsx (98%) create mode 100644 src/partners/actions/dashboard.ts create mode 100644 src/partners/actions/editor.ts create mode 100644 src/partners/actions/public.ts rename src/{constants/partner.ts => partners/constants.ts} (64%) create mode 100644 src/partners/reducers/dashboard.ts create mode 100644 src/partners/reducers/index.ts rename src/{reducers/partner.ts => partners/reducers/public.ts} (65%) create mode 100644 src/partners/routes.ts rename src/{ui/pages/partner => partners/ui}/BrowsePage.tsx (87%) rename src/{ui/pages/partner => partners/ui}/DisplayPage.tsx (96%) rename src/{ui/pages/partner => partners/ui}/EditPage.tsx (91%) rename src/{ui/pages/partner => partners/ui}/c/Filters.tsx (94%) rename src/{ui/pages/partner => partners/ui}/c/PartnerCard.tsx (100%) rename src/{ui/pages/partner => partners/ui}/c/PartnerForm.tsx (98%) rename src/{ui/pages/partner => partners/ui}/c/SearchMenu.tsx (100%) rename src/{ui/pages/partner => partners/ui}/c/Summary.tsx (100%) delete mode 100644 src/reducers/datasets.ts delete mode 100644 src/service/GenesysService.ts create mode 100644 src/ui/catalog/dashboard/MyDataPage.tsx rename src/ui/{pages => catalog}/dashboard/c/DashboardActionsArea.tsx (100%) rename src/ui/{pages => catalog}/dashboard/c/DashboardActionsButton.tsx (94%) rename src/ui/{pages => catalog}/dashboard/c/DashboardButton.tsx (100%) rename src/ui/{pages => catalog}/dashboard/c/DashboardTableHeader.tsx (92%) rename src/ui/{pages => catalog}/dashboard/c/DashboardTableRow.tsx (76%) rename src/ui/{pages => catalog}/dashboard/c/Filters.tsx (97%) rename src/ui/{pages => catalog}/dashboard/c/MyDataTable.tsx (86%) rename src/ui/{pages => catalog}/dashboard/c/StatusFilter.tsx (100%) delete mode 100644 src/ui/pages/dashboard/DashboardPage.tsx delete mode 100644 src/ui/pages/dashboard/MyDataPage.tsx delete mode 100644 src/ui/pages/dataset/dataset-stepper/steps.ts delete mode 100644 src/ui/pages/descriptorlist/descriptorlist-stepper/steps.ts delete mode 100644 src/ui/pages/genesys/BrowsePage.tsx delete mode 100644 src/ui/pages/genesys/DisplayPage.tsx delete mode 100644 src/ui/pages/genesys/c/Filters.tsx create mode 100644 src/vocabulary/actions/admin.ts rename src/{actions/vocabulary.ts => vocabulary/actions/public.ts} (76%) rename src/{constants/vocabulary.ts => vocabulary/constants.ts} (100%) create mode 100644 src/vocabulary/reducers/admin.ts create mode 100644 src/vocabulary/reducers/index.ts rename src/{reducers/vocabulary.ts => vocabulary/reducers/public.ts} (76%) create mode 100644 src/vocabulary/routes.ts rename src/{ui/pages/vocabulary => vocabulary/ui}/BrowsePage.tsx (98%) rename src/{ui/pages/vocabulary => vocabulary/ui}/DisplayPage.tsx (97%) rename src/{ui/pages/vocabulary => vocabulary/ui}/EditPage.tsx (91%) rename src/{ui/pages/vocabulary => vocabulary/ui}/c/VocabularyCard.tsx (100%) rename src/{ui/pages/vocabulary => vocabulary/ui}/c/VocabularyForm.tsx (98%) diff --git a/src/actions/dashboard.ts b/src/actions/dashboard.ts index b970320..99536f3 100644 --- a/src/actions/dashboard.ts +++ b/src/actions/dashboard.ts @@ -1,52 +1,34 @@ -// utilities -import {dereferenceReferences} from 'utilities'; -import {log} from 'utilities/debug'; - // constants -import {ADD_TO_EDIT_LIST, RECEIVE_DASHBOARD_PAGE, REMOVE_FROM_EDIT_LIST, RECEIVE_IS_EDIT_MODE, REMOVE_ITEM, REFRESH_ITEM, SELECT_ALL, UNSELECT_ALL} from 'constants/dashboard'; +import {ADD_TO_EDIT_LIST, REMOVE_FROM_EDIT_LIST, RECEIVE_IS_EDIT_MODE, SELECT_ALL, UNSELECT_ALL} from 'constants/dashboard'; // Models -import {Dataset, IDatasetFilter} from 'model/dataset.model'; -import {Descriptor, DescriptorList, IDescriptorFilter, IDescriptorListFilter} from 'model/descriptor.model'; -import {Page, PublishState} from 'model/common.model'; -import {Partner} from 'model/partner.model'; - -// service -import {DatasetService} from 'service/DatasetService'; -import {DescriptorService} from 'service/DescriptorService'; -import {DescriptorListService} from 'service/DescriptorListService'; - -// actions -import {addFilterCode} from 'actions/filterCode'; -import {loadDescriptorListTitles} from 'actions/uuidDecoder'; +import {Dataset} from 'model/dataset.model'; +import {Descriptor, DescriptorList} from 'model/descriptor.model'; export const setEditMode = (payload: boolean) => (dispatch) => { dispatch({type: RECEIVE_IS_EDIT_MODE, payload}); }; -export const refreshDashboardPageItem = (item: any) => ({ - type: REFRESH_ITEM, - payload: item, -}); - -export const removeDashboardPageItem = (item: any) => ({ - type: REMOVE_ITEM, - payload: item, -}); +export const selectAll = (tab: string) => (dispatch, getState) => { + let payload; + switch (tab) { + case 'descriptorlists': payload = getState().descriptorList.dashboard.paged.content.map((item) => item.uuid); break; + case 'descriptors': payload = getState().descriptors.dashboard.paged.content.map((item) => item.uuid); break; + case 'datasets': + default: payload = getState().datasets.dashboard.paged.content.map((item) => item.uuid); + } -export const selectAll = () => ({ - type: SELECT_ALL, -}); + return dispatch({ + type: SELECT_ALL, + payload, + }); +}; export const unselectAll = () => ({ type: UNSELECT_ALL, }); -const receivePaged = (paged: Page | Page | Page) => (dispatch) => { - dispatch({type: RECEIVE_DASHBOARD_PAGE, payload: !paged ? paged : {...paged}}); -}; - const addToList = (payload: Dataset | Descriptor | DescriptorList) => (dispatch) => { dispatch({type: ADD_TO_EDIT_LIST, payload: payload.uuid}); }; @@ -58,12 +40,6 @@ const removeFromList = (payload: Dataset | Descriptor | DescriptorList) => (disp export const onPageChange = () => (dispatch) => { dispatch(setEditMode(false)); dispatch(unselectAll()); - dispatch(receivePaged(null)); -}; - -const receiveAndPushDashboardPage = (paged: any) => (dispatch, getState) => { - const oldContent = getState().dashboard.paged && getState().dashboard.paged.content || []; - dispatch(receivePaged({...paged, content: [...oldContent, ...paged.content]})); }; export const addToEditList = (item: Dataset | Descriptor | DescriptorList) => (dispatch, getState) => { @@ -80,167 +56,58 @@ export const removeFromEditList = (item: Dataset | Descriptor | DescriptorList) } }; +/** + * Publish all items that are in dashboard.toEditList + * @param publishOne: (uuid: string) => Promise action to publish one item + */ export const publishAll = (publishOne) => (dispatch, getState) => { - const toEditList = getState().dashboard.selected; - const pagedContent = getState().dashboard.paged.content; - const toPublishItems = pagedContent.filter((pagedItem) => toEditList.indexOf(pagedItem.uuid) !== -1); + const toPublishItems = getState().dashboard.selected; toPublishItems.map((item) => { - if (item.state === PublishState.DRAFT) { - dispatch(publishOne(item)) - .then((published) => { - dispatch(removeFromList(published)); - dispatch(refreshDashboardPageItem(published)); - }); - } else { - dispatch(removeFromList(item)); - } + publishOne(item); + dispatch(removeFromList(item)); }); dispatch(unselectAll()); }; +/** + * Approve all items that are in dashboard.toEditList + * @param approveOne: (uuid: string) => Promise action to approve one item + */ export const approveAll = (approveOne) => (dispatch, getState) => { - const toEditList = getState().dashboard.selected; - const pagedContent = getState().dashboard.paged.content; - const toApproveItems = pagedContent.filter((pagedItem) => toEditList.indexOf(pagedItem.uuid) !== -1); + const toApproveItems = getState().dashboard.selected; toApproveItems.map((item) => { - if (item.state === PublishState.REVIEWING) { - dispatch(approveOne(item)) - .then((approved) => { - dispatch(removeFromList(approved)); - dispatch(refreshDashboardPageItem(approved)); - }); - } else { - dispatch(removeFromList(item)); - } + approveOne(item); + dispatch(removeFromList(item)); }); dispatch(unselectAll()); }; -export const unpublishAll = (publishOne) => (dispatch, getState) => { - const toEditList = getState().dashboard.selected; - const pagedContent = getState().dashboard.paged.content; - const toUnpublishItems = pagedContent.filter((pagedItem) => toEditList.indexOf(pagedItem.uuid) !== -1); +/** + * Unpublish all items that are in dashboard.toEditList + * @param unPublishOne: (uuid: string) => Promise action to unpublish one item + */ +export const unpublishAll = (unPublishOne) => (dispatch, getState) => { + const toUnpublishItems = getState().dashboard.selected; toUnpublishItems.map((item) => { - if (item.state !== PublishState.DRAFT) { - dispatch(publishOne(item)) - .then((unpublished) => { - dispatch(removeFromList(unpublished)); - dispatch(refreshDashboardPageItem(unpublished)); - }); - } else { - dispatch(removeFromList(item)); - } + unPublishOne(item); + dispatch(removeFromList(item)); }); dispatch(unselectAll()); }; +/** + * Delete all items that are in dashboard.toEditList + * @param deleteOne: (uuid: string) => Promise action to delete one item + */ export const deleteAll = (deleteOne) => (dispatch, getState) => { - const toEditList = getState().dashboard.selected; - const pagedContent = getState().dashboard.paged.content; - const toDeleteItems = pagedContent.filter((pagedItem) => toEditList.indexOf(pagedItem.uuid) !== -1); + const toDeleteItems = getState().dashboard.selected; toDeleteItems.map((item) => { - dispatch(deleteOne(item)) - .then((deleted) => { - dispatch(removeFromList(deleted)); - dispatch(removeDashboardPageItem(deleted)); - }); + deleteOne(item); + dispatch(removeFromList(item)); }); dispatch(unselectAll()); }; - -export const listMyDatasets = (page?, results?, sortBy?, filter?: string | IDatasetFilter, order?) => { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.listMyDatasets(token, page, results, sortBy, filter, order) - .then((paged) => { - dispatch(onPageChange()); - dispatch(receiveAndPushDashboardPage(paged)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -}; - -export const listMyDescriptors = (page?, results?, sortBy?, filter?: string | IDescriptorFilter, order?) => { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.listMyDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - dispatch(receiveAndPushDashboardPage(paged)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -}; - -export const listMyDescriptorLists = (page?, results?, sortBy?, filter?: string | IDescriptorListFilter, order?) => { - - return (dispatch, getState) => { - log('Loading my descriptor lists'); - - const token = getState().login.access_token; - - return DescriptorListService.listMyDescriptorLists(token, page, results, sortBy, filter, order) - // receive the current descriptor list - .then((descriptorLists) => { - dispatch(receiveAndPushDashboardPage(descriptorLists)); - return dispatch(addFilterCode(descriptorLists.filterCode, descriptorLists.filter)); - }).catch((error) => { - log(`Error loading my descriptor lists`, error); - }); - }; -}; - -export const promiseListMyDatasets = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.listMyDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - dispatch(receiveAndPushDashboardPage(paged)); - return {...paged, content: []}; - }) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -export const promiseListMyDescriptors = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.listMyDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - dispatch(receiveAndPushDashboardPage(paged)); - return {...paged, content: []}; - }) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -export const promiseListMyDescriptorLists = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.listDescriptorLists(token, page, results, sortBy, filter, order) - .then((paged) => { - dispatch(loadDescriptorListTitles(paged.content)); - return {...paged, content: []}; - }).catch((error) => { - log('Error', error); - return error; - }); -}; diff --git a/src/actions/dataset.ts b/src/actions/dataset.ts deleted file mode 100644 index fec72a1..0000000 --- a/src/actions/dataset.ts +++ /dev/null @@ -1,517 +0,0 @@ -import { push } from 'react-router-redux'; - -import { Page, PublishState } from 'model/common.model'; -import { Dataset, IDatasetFilter, AccessionIdentifier } from 'model/dataset.model'; -import { Creator } from 'model/creator.model'; -import { Location } from 'model/location.model'; -import { RepositoryFile } from 'model/repositoryFile.model'; -import { DatasetService } from 'service/DatasetService'; -import { CreatorService } from 'service/CreatorService'; -import { LocationService } from 'service/LocationService'; -import { RepositoryFileService } from 'service/RepositoryFileService'; -import { log } from 'utilities/debug'; - -import {CREATE_DATASET, RECEIVE_DATASET, RECEIVE_DATASET_PAGE, ADD_CREATOR_TO_DATASET, REMOVE_CREATOR_FROM_DATASET, UPDATE_DATASET_CREATOR, ADD_LOCATION, RECEIVE_LOCATION, REMOVE_LOCATION, REMOVE_DATASET} from 'constants/datasets'; -import {addFilterCode} from 'actions/filterCode'; -import steps from 'ui/pages/dataset/dataset-stepper/steps'; -import { navigateTo } from 'actions/navigation'; -import * as _ from 'lodash'; - -const receiveDataset = (dataset: Dataset) => ({ - type: RECEIVE_DATASET, payload: dataset, -}); - -const removeDataset = (dataset: Dataset) => ({ - type: REMOVE_DATASET, payload: dataset, -}); - -const receiveDatasetPage = (paged: Page, page, results, sortBy, filter: IDatasetFilter, order) => ({ - type: RECEIVE_DATASET_PAGE, - payload: { paged, query: { page, results, sortBy, filter, order } }, -}); - -function showDataset(uuid: string) { - return (dispatch) => { - dispatch(push(`/datasets/${uuid}`)); - }; -} - -function editDataset(uuid: string) { - return (dispatch) => { - dispatch(push(`/datasets/${uuid}/edit`)); - }; -} - -export const promiseListMyDatasets = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.listMyDatasets(token, page, results, sortBy, filter, order) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -function listMyDatasets(page?, results?, sortBy?, filter?: string | IDatasetFilter, order?) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.listMyDatasets(token, page, results, sortBy, filter, order) - .then((paged) => { - dispatch(receiveDatasetPage(paged, page, results, sortBy, paged.filter, order)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -export const promiselistDatasets = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.listDatasets(token, page, results, sortBy, filter, order) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -function listDatasetsRequest(page?, results?, sortBy?, filter?, order?) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.listDatasets(token, page, results, sortBy, filter, order) - .then((paged) => { - dispatch(receiveDatasetPage(paged, page, results, sortBy, filter, order)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -function listDatasetsByCodeRequest(page?, results?, sortBy?, filterCode?, order?) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.listDatasetsByCode(token, page, results, sortBy, filterCode, order) - .then((paged) => { - dispatch(receiveDatasetPage(paged, page, results, sortBy, paged.filter, order)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -function loadDataset(uuid: string) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.getDataset(token, uuid) - .then((dataset) => { - dispatch(receiveDataset(dataset)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -// Create a new descriptor -const createDataset = () => (dispatch) => { - dispatch({ type: CREATE_DATASET }); - return dispatch(push(`/datasets/edit`)); -}; - -const saveDataset = (dataset: Dataset) => (dispatch, getState) => { - - const needToRedirect: boolean = !(dataset.version && dataset.uuid); - - if (_.isEqual({...getState().datasets.currentDataset}, {...dataset})) { - return; - } - - // remove normalized data here - const data = new Dataset({ - repositoryFiles: [], - creators: [], - locations: [], - descriptors: [], - ...dataset, - }); - - const token = getState().login.access_token; - - return DatasetService.saveDataset(token, data) - .then((saved) => { - dispatch(receiveDataset(saved)); - if (needToRedirect) { - dispatch(gotoNextStep(saved)); - } - }).catch((error) => { - log('Save error', error); - }); -}; - -function gotoNextStep(dataset: Dataset) { - return (dispatch, getState) => { - const link = window.location.pathname.split('/').pop(); - const stepId = steps.find((e) => e.link.endsWith(link)).id; - const path = steps.find((e) => e.id === (stepId + 1)).link; - dispatch(navigateTo(`/datasets/${dataset.uuid}/${path}`)); - }; -} - -function approveDataset(dataset: Dataset) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.updatePublishState(token, dataset, PublishState.PUBLISHED) - .then((saved) => { - dispatch(receiveDataset(saved)); - }).catch((error) => { - log('Error', error); - }); - }; -} - -function rejectDataset(dataset: Dataset, needToRedirect: boolean = true) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.updatePublishState(token, dataset, PublishState.DRAFT) - .then((saved) => { - dispatch(receiveDataset(saved)); - if (needToRedirect) { - dispatch(navigateTo(`/datasets/${saved.uuid}/edit`)); - } - }).catch((error) => { - log('Error', error); - }); - }; -} - -function publishDataset(dataset: Dataset, needToRedirect: boolean = false) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.updatePublishState(token, dataset, PublishState.REVIEWING) - .then((saved) => { - dispatch(receiveDataset(saved)); - if (needToRedirect) { - dispatch(showDataset(saved.uuid)); - } - }).catch((error) => { - log('Error', error); - }); - }; -} - -function publishDatasetPromise(dataset: Dataset) { - return (dispatch, getState) => { - return DatasetService.updatePublishState(getState().login.access_token, dataset, PublishState.REVIEWING) - .catch((error) => { - log('Error', error); - }); - }; -} - -function unpublishDatasetPromise(dataset: Dataset) { - return (dispatch, getState) => { - return DatasetService.updatePublishState(getState().login.access_token, dataset, PublishState.DRAFT) - .catch((error) => { - log('Error', error); - }); - }; -} - -function approveDatasetPromise(dataset: Dataset) { - return (dispatch, getState) => { - return DatasetService.updatePublishState(getState().login.access_token, dataset, PublishState.PUBLISHED) - .catch((error) => { - log('Error', error); - }); - }; -} - -function deleteDatasetPromise(dataset: Dataset) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.deleteDataset(token, dataset) - .then((deleted) => { - dispatch(removeDataset(deleted)); - return deleted; - }) - .catch((error) => { - log('Delete error', error); - }); - }; -} - -function deleteDataset(dataset: Dataset) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.deleteDataset(token, dataset) - .then((deleted) => { - dispatch(removeDataset(deleted)); - // dispatch(showDataset(saved.uuid)); - }).catch((error) => { - log('Delete error', error); - }); - }; -} - -function updateDatasetAccessionIdentifiers(dataset: Dataset, accessionIdentifiers: AccessionIdentifier[]) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.updateAccessionIdentifiers(token, dataset, accessionIdentifiers) - .then((saved) => { - dispatch(receiveDataset(saved)); - }).catch((error) => { - log('Publish error', error); - }); - }; -} - -function addDescriptorsToDataset(dataset: Dataset, descriptorUuids: string[]) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.addDescriptorsToDataset(token, dataset, descriptorUuids) - .then((saved) => { - dispatch(receiveDataset(saved)); - }).catch((error) => { - log('Add error', error); - }); - }; -} - -export const setDescriptorsToDatasetRequest = (dataset: Dataset, descriptorUuids: string[]) => (dispatch, getState) => { - return DatasetService.setDescriptorsToDataset(getState().login.access_token, dataset, descriptorUuids) - .then((saved) => { - dispatch(receiveDataset(saved)); - }).catch((error) => { - log('Add error', error); - }); -}; - -function removeDescriptorsFromDataset(dataset: Dataset, descriptorUuids: string[]) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DatasetService.removeDescriptorsFromDataset(token, dataset, descriptorUuids) - .then((saved) => { - dispatch(receiveDataset(saved)); - }).catch((error) => { - log('Delete error', error); - }); - }; -} - -export { - listMyDatasets, listDatasetsRequest, loadDataset, createDataset, saveDataset, deleteDataset, - publishDataset, receiveDataset, editDataset, showDataset, updateDatasetAccessionIdentifiers, - removeDescriptorsFromDataset, addDescriptorsToDataset, deleteDatasetPromise, approveDataset, rejectDataset, - publishDatasetPromise, unpublishDatasetPromise, approveDatasetPromise, -}; - -export const uploadRepositoryFileRequest = (datasetUUID: string, file: File) => (dispatch, getState) => { - const token = getState().login.access_token; - - return RepositoryFileService.uploadRepositoryFile(token, datasetUUID, file) - .then((dataset) => { - dispatch(receiveDataset(dataset)); - }).catch((error) => { - log('Save error', error); - }); -}; - -export const updateRepositoryFileRequest = (datasetUUID: string, repositoryfile: RepositoryFile) => (dispatch, getState) => { - const token = getState().login.access_token; - - return RepositoryFileService.updateRepositoryFile(token, datasetUUID, repositoryfile) - .then((dataset) => { - dispatch(receiveDataset(dataset)); - }).catch((error) => { - log('Save error', error); - }); -}; - -export const deleteRepositoryFileRequest = (datasetUUID: string, uuid: string) => (dispatch, getState) => { - const token = getState().login.access_token; - - return RepositoryFileService.deleteRepositoryFile(token, datasetUUID, uuid) - .then((dataset) => { - dispatch(receiveDataset(dataset)); - }).catch((error) => { - log('Delete error', error); - }); -}; - -function addCreatorToDataset(creator: Creator, uuid: string) { - return { - type: ADD_CREATOR_TO_DATASET, - payload: { - creator, - datasetUUID: uuid, - }, - }; -} - -// FIXME No uuid param required, currentDataset is available in state -function createDatasetCreator(uuid: string) { - return (dispatch, getState) => { - log('createCreator'); - return CreatorService.createCreator(getState().login.access_token, uuid) - .then((obj) => { - dispatch(addCreatorToDataset(obj, uuid)); - }).catch((error) => { - log('Create creator error', error); - }); - }; -} - -function updateCreator(creator: Creator) { - return { - type: UPDATE_DATASET_CREATOR, - payload : { - creator, - }, - }; -} - -function updateCreatorRequest(uuid: string, creator: Creator) { - return (dispatch, getState) => { - const token = getState().login.access_token; - return CreatorService.updateCreator(token, uuid, creator) - .then((obj) => { - dispatch(updateCreator(obj)); - }).catch((error) => { - log('Update creator error', error); - }); - }; -} - -function removeCreator(creator: Creator, uuid: string) { - return { - type: REMOVE_CREATOR_FROM_DATASET, - payload : { - creator, - datasetUUID: uuid, - }, - }; -} - -function deleteCreatorRequest(uuid: string, creator: Creator) { - return (dispatch, getState) => { - const token = getState().login.access_token; - return CreatorService.deleteCreator(token, uuid, creator) - .then((obj) => { - dispatch(removeCreator(obj, uuid)); - }).catch((error) => { - log('Delete creator error', error); - }); - }; -} - -export { createDatasetCreator, deleteCreatorRequest, updateCreatorRequest, listDatasetsByCodeRequest }; - -// -// Dataset: Timing and Location - -function addLocation(datasetUUID: string, location: Location) { - return { - type: ADD_LOCATION, - payload: { - datasetUUID, - location, - }, - }; -} - -function createLocationRequest(datasetUUID: string) { - const location = new Location({}); - - return (dispatch, getState) => { - const token = getState().login.access_token; - - return LocationService.saveLocation(token, datasetUUID, location) - .then((saved) => { - dispatch(addLocation(datasetUUID, saved)); - }).catch((error) => { - log('Save error', error); - }); - }; -} - -function receiveLocation(location: Location) { - return { - type: RECEIVE_LOCATION, - payload: { - location, - }, - }; -} - -function updateLocationRequest(datasetUUID: string, location: Location) { - - return (dispatch, getState) => { - const token = getState().login.access_token; - - return LocationService.saveLocation(token, datasetUUID, location) - .then((saved) => { - dispatch(receiveLocation(saved)); - dispatch(receiveDataset(refreshStartEndDates(getState().datasets.currentDataset))); - }).catch((error) => { - log('Save error', error); - }); - }; -} - -function deleteLocation(datasetUUID: string, location: Location) { - return { - type: REMOVE_LOCATION, - payload: { - datasetUUID, - location, - }, - }; -} - -function deleteLocationRequest(datasetUUID: string, location: Location) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return LocationService.deleteLocation(token, datasetUUID, location) - .then((saved) => { - dispatch(deleteLocation(datasetUUID, saved)); - dispatch(receiveDataset(refreshStartEndDates(getState().datasets.currentDataset))); - }).catch((error) => { - log('Delete error', error); - }); - }; -} - -function refreshStartEndDates(dataset) { - const res = {...dataset}; - res.startDate = null; - res.endDate = null; - res.locations.forEach((location) => { - if (!res.startDate || (location.startDate && res.startDate.localeCompare(location.startDate) > 0)) { - res.startDate = location.startDate; - } - if (!res.endDate || (location.endDate && res.endDate.localeCompare(location.endDate) < 0)) { - res.endDate = location.endDate; - } - }); - return res; -} - -export { createLocationRequest, updateLocationRequest, deleteLocationRequest, receiveLocation }; diff --git a/src/actions/descriptorList.ts b/src/actions/descriptorList.ts deleted file mode 100644 index 2e2f827..0000000 --- a/src/actions/descriptorList.ts +++ /dev/null @@ -1,339 +0,0 @@ -import { push } from 'react-router-redux'; - -import { DescriptorListService } from 'service/DescriptorListService'; -import { DescriptorList, Descriptor, IDescriptorListFilter } from 'model/descriptor.model'; -import { Page, PublishState } from 'model/common.model'; -import {log} from 'utilities/debug'; -import { addFilterCode } from 'actions/filterCode'; -import {loadDescriptorListTitles} from 'actions/uuidDecoder'; -import {cleanFilters} from 'utilities'; -import * as _ from 'lodash'; - -import { - GET_DESCRIPTORLIST, RECEIVE_DESCRIPTORLIST, - CREATE_DESCRIPTORLIST, - LIST_DESCRIPTORLISTS, RECEIVE_DESCRIPTORLISTS, REMOVE_DESCRIPTORLIST, -} from 'constants/descriptors'; -import {navigateTo} from './navigation'; -import steps from 'ui/pages/descriptorlist/descriptorlist-stepper/steps'; - -const receiveDescriptorList = (descriptorList: DescriptorList) => ({ - type: RECEIVE_DESCRIPTORLIST, - payload: descriptorList, -}); - -const removeDescriptorList = (descriptorList: DescriptorList) => ({ - type: REMOVE_DESCRIPTORLIST, - payload: descriptorList, -}); - -const receiveDescriptorLists = (paged: Page, page, results, sortBy, filter: IDescriptorListFilter, order) => ({ - type: RECEIVE_DESCRIPTORLISTS, - payload: { paged, query: { page, results, sortBy, filter, order } }, -}); - -const loadingDescriptorLists = (page, results, sortBy, filter, order) => ({ - type: LIST_DESCRIPTORLISTS, - payload: { page, results, sortBy, filter, order }, -}); - -// go to the published descriptor list page -function showDescriptorList(uuid: string) { - return (dispatch) => { - dispatch(push(`/descriptorlists/${uuid}`)); - }; -} - -// Just load a descriptor list -export const loadDescriptorList = (uuid: string, success?: (d) => any, fail?: (error) => any) => (dispatch, getState) => { - log('Loading descriptor list', uuid); - const token = getState().login.access_token; - - dispatch({ type: GET_DESCRIPTORLIST, payload: uuid }); - - return DescriptorListService.loadDescriptorList(token, uuid) - // receive the current descriptor list - // // Demo long load - // .then((descriptorList) => { - // await setTimeout(() => dispatch(receiveDescriptorList(descriptorList)), 10000); - .then((descriptorList) => { - if (success) { - return success(descriptorList); - } - dispatch(receiveDescriptorList(descriptorList)); - }).catch((error) => { - log(`No descriptor list with uuid ${uuid}`, error); - if (fail) { - return fail(error); - } - }); -}; - -export const promiseListMyDescriptorLists = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.listMyDescriptorLists(token, page, results, sortBy, filter, order) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -// List current user's descriptor lists -export const listMyDescriptorLists = (page?, results?, sortBy?, filter?: string | IDescriptorListFilter, order?) => (dispatch, getState) => { - log('Loading my descriptor lists'); - const token = getState().login.access_token; - - dispatch(loadingDescriptorLists(page, results, sortBy, filter, order)); - - return DescriptorListService.listMyDescriptorLists(token, page, results, sortBy, filter, order) - // receive the current descriptor list - .then((descriptorLists) => { - dispatch(receiveDescriptorLists(descriptorLists, page, results, sortBy, descriptorLists.filter, order)); - dispatch(loadDescriptorListTitles(descriptorLists.content)); - return dispatch(addFilterCode(descriptorLists.filterCode, descriptorLists.filter)); - }).catch((error) => { - log(`Error loading my descriptor lists`, error); - }); -}; - -export const promiseListDescriptorLists = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.listDescriptorLists(token, page, results, sortBy, filter, order) - .then((page) => { - dispatch(loadDescriptorListTitles(page.content)); - return page; - }).catch((error) => { - log('Error', error); - return error; - }); -}; - -export const promiseDescriptorList = (uuid) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.loadDescriptorList(token, uuid) - .then((list) => { - dispatch(loadDescriptorListTitles([list])); - return list; - }) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -export const autocomplete = (term: string = '') => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.autocomplete(token, term) - .then((lists) => { - dispatch(loadDescriptorListTitles(lists)); - return lists; - }) - .catch((error) => { - log('Error', error); - }); -}; - -// List published descriptor lists -export const listDescriptorLists = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - log('Loading published descriptor lists'); - const token = getState().login.access_token; - - dispatch(loadingDescriptorLists(page, results, sortBy, filter, order)); - - return DescriptorListService.listDescriptorLists(token, page, results, sortBy, filter, order) - // receive the current descriptor list - .then((paged) => { - dispatch(receiveDescriptorLists(paged, page, results, sortBy, filter, order)); - dispatch(loadDescriptorListTitles(paged.content)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }).catch((error) => { - log(`Error loading published descriptor lists`, error); - }); -}; - -// List published descriptor lists by code -export const listDescriptorListsByCode = (page?, results?, sortBy?, filterCode?, order?) => (dispatch, getState) => { - log('Loading published descriptor lists by code'); - const token = getState().login.access_token; - - return DescriptorListService.listDescriptorListsByCode(token, page, results, sortBy, filterCode, order) - // receive the current descriptor list - .then((paged) => { - const filter = cleanFilters(paged.filter, ['published']); - dispatch(receiveDescriptorLists(paged, page, results, sortBy, filter as IDescriptorListFilter, order)); - dispatch(loadDescriptorListTitles(paged.content)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }).catch((error) => { - log(`Error loading published descriptor lists`, error); - }); -}; - -// Create a new descriptor list -export const createDescriptorList = () => (dispatch) => { - dispatch({ type: CREATE_DESCRIPTORLIST }); - return dispatch(push(`/descriptorlists/edit`)); -}; - -// Edit an existing descriptor list -export const editDescriptorList = (uuid: string) => (dispatch, getState) => { - return dispatch(loadDescriptorList(uuid)) - .then((descriptorList) => dispatch(push(`/descriptorlists/${descriptorList.uuid}/edit`))); -}; - -// Save the descriptor list -export const saveDescriptorList = (descriptorList: DescriptorList) => (dispatch, getState) => { - - const needToRedirect: boolean = !(descriptorList.version && descriptorList.uuid); - - if (_.isEqual({...getState().descriptorList.currentDescriptorList}, {...descriptorList})) { - return; - } - - log('Saving descriptor list', descriptorList); - const createOrSave = descriptorList.version ? DescriptorListService.updateDescriptorList : DescriptorListService.createDescriptorList; - - return createOrSave(getState().login.access_token, descriptorList) - // when response is back - .then((saved) => { - // receive the updated descriptor list - dispatch(receiveDescriptorList(saved)); - if (needToRedirect) { - const path = steps.find((e) => e.id === 2).link; - dispatch(navigateTo(`/descriptorlists/${saved.uuid}/${path}`)); - } - }).catch((error) => { - log(`Error saving descriptor list`, error, descriptorList); - }); -}; - -export const deleteDescriptorListPromise = (descriptorList: DescriptorList) => (dispatch, getState) => { - return DescriptorListService.deleteDescriptorList(getState().login.access_token, descriptorList) - .then((descriptorList) => { - dispatch(removeDescriptorList(descriptorList)); - return descriptorList; - }); -}; - -// Publish the descriptor list -export const deleteDescriptorList = (descriptorList: DescriptorList) => (dispatch, getState) => { - return DescriptorListService.deleteDescriptorList(getState().login.access_token, descriptorList) - .then((descriptorList) => { - // receive updates - dispatch(removeDescriptorList(descriptorList)); - }); -}; - -export function approveDescriptorList(descriptorList: DescriptorList) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.updatePublishState(token, descriptorList, PublishState.PUBLISHED) - .then((saved) => { - dispatch(receiveDescriptorList(saved)); - }).catch((error) => { - log('Error', error); - }); - }; -} - -export function rejectDescriptorList(descriptorList: DescriptorList, needToRedirect: boolean = true) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.updatePublishState(token, descriptorList, PublishState.DRAFT) - .then((saved) => { - dispatch(receiveDescriptorList(saved)); - if (needToRedirect) { - dispatch(navigateTo(`/descriptorlists/${saved.uuid}/edit`)); - } - }).catch((error) => { - log('Error', error); - }); - }; -} - -export function publishDescriptorList(descriptorList: DescriptorList, needToRedirect: boolean = false) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorListService.updatePublishState(token, descriptorList, PublishState.REVIEWING) - .then((saved) => { - dispatch(receiveDescriptorList(saved)); - if (needToRedirect) { - dispatch(showDescriptorList(saved.uuid)); - } - }).catch((error) => { - log('Error', error); - }); - }; -} - -export const publishDescriptorListPromise = (descriptorList: DescriptorList) => (dispatch, getState) => { - return DescriptorListService.updatePublishState(getState().login.access_token, descriptorList, PublishState.REVIEWING) - .catch((error) => { - log('Error', error); - }); -}; - -export const unpublishDescriptorListPromise = (descriptorList: DescriptorList) => (dispatch, getState) => { - return DescriptorListService.updatePublishState(getState().login.access_token, descriptorList, PublishState.DRAFT) - .catch((error) => { - log('Error', error); - }); -}; - -export const approveDescriptorListPromise = (descriptorList: DescriptorList) => (dispatch, getState) => { - return DescriptorListService.updatePublishState(getState().login.access_token, descriptorList, PublishState.PUBLISHED) - .catch((error) => { - log('Error', error); - }); -}; - -// Add a descriptor to the descriptor list -export const addDescriptorToDescriptorList = (descriptorList: DescriptorList, descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorListService.addDescriptor(getState().login.access_token, descriptorList, [ descriptor.uuid ]) - .then((descriptorList) => { - // receive updates - dispatch(receiveDescriptorList(descriptorList)); - }); -}; - -// Add a descriptor to the descriptor list -export const addDescriptorsToDescriptorList = (descriptorList: DescriptorList, descriptorUuids: string[]) => (dispatch, getState) => { - return DescriptorListService.addDescriptor(getState().login.access_token, descriptorList, descriptorUuids) - .then((descriptorList) => { - // receive updates - dispatch(receiveDescriptorList(descriptorList)); - }); -}; - -// Add a descriptor to the descriptor list -export const setDescriptorsToDescriptorList = (descriptorList: DescriptorList, descriptorUuids: string[]) => (dispatch, getState) => { - return DescriptorListService.setDescriptors(getState().login.access_token, descriptorList, descriptorUuids) - .then((descriptorList) => { - // receive updates - dispatch(receiveDescriptorList(descriptorList)); - }); -}; - -// Remove a descriptor to the descriptor list -export const removeDescriptorFromDescriptorList = (descriptorList: DescriptorList, descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorListService.removeDescriptor(getState().login.access_token, descriptorList, [ descriptor.uuid ]) - .then((descriptorList) => { - // receive updates - dispatch(receiveDescriptorList(descriptorList)); - }); -}; - -// Remove a list of descriptors from the descriptor list -export const removeDescriptorsFromDescriptorList = (descriptorList: DescriptorList, descriptorUuids: string[]) => (dispatch, getState) => { - return DescriptorListService.removeDescriptor(getState().login.access_token, descriptorList, descriptorUuids) - .then((descriptorList) => { - // receive updates - dispatch(receiveDescriptorList(descriptorList)); - }); -}; diff --git a/src/actions/descriptors.ts b/src/actions/descriptors.ts deleted file mode 100644 index 56466b2..0000000 --- a/src/actions/descriptors.ts +++ /dev/null @@ -1,306 +0,0 @@ -import {push} from 'react-router-redux'; -import {SubmissionError} from 'redux-form'; - -import {cleanFilters, dereferenceReferences} from 'utilities'; -import {DescriptorService} from 'service/DescriptorService'; -import {CREATE_DESCRIPTOR, RECEIVE_DESCRIPTOR, RECEIVE_DESCRIPTOR_EXTRA, RECEIVE_DESCRIPTOR_PAGE, GET_DESCRIPTOR, LIST_DESCRIPTORS, REMOVE_DESCRIPTOR} from 'constants/descriptors'; -import {Descriptor, IDescriptorFilter} from 'model/descriptor.model'; -import {Partner} from 'model/partner.model'; -import {Page, PublishState} from 'model/common.model'; -import {log} from 'utilities/debug'; -import {addFilterCode} from './filterCode'; -import { navigateTo } from 'actions/navigation'; - -const receiveDescriptor = (descriptor: Descriptor) => ({ - type: RECEIVE_DESCRIPTOR, - payload: descriptor, -}); - -const removeDescriptor = (descriptor: Descriptor) => ({ - type: REMOVE_DESCRIPTOR, - payload: descriptor, -}); - -const receiveDescriptorExtra = (descriptor: Descriptor, extra: any) => ({ - type: RECEIVE_DESCRIPTOR_EXTRA, - payload: { descriptor, extra }, -}); - -const receiveDescriptorPage = (paged: Page, page, results, sortBy, filter: IDescriptorFilter, order) => ({ - type: RECEIVE_DESCRIPTOR_PAGE, - payload: { paged, query: { page, results, sortBy, filter, order } }, -}); - -const loadingDescriptors = (page, results, sortBy, filter, order) => ({ - type: LIST_DESCRIPTORS, - payload: { page, results, sortBy, filter, order }, -}); - -export function showDescriptors() { - return (dispatch) => { - dispatch(push(`/descriptors`)); - }; -} - -export function showDescriptorsDashboard() { - return (dispatch) => { - dispatch(push(`/dashboard`)); - }; -} - -function showDescriptor(uuid: string) { - return (dispatch) => { - dispatch(push(`/descriptors/${uuid}`)); - }; -} - -export function loadDescriptor(uuid: string, success?: (d) => any, fail?: (error) => any) { - log('Loading descriptor', uuid); - return (dispatch, getState) => { - const token = getState().login.access_token; - - dispatch({ type: GET_DESCRIPTOR, payload: uuid }); - - return DescriptorService.loadDescriptor(token, uuid) - .then((loaded) => { - if (success) { - return success(loaded); - } - return DescriptorService.loadDescriptorExtra(token, uuid) - .then((extra) => { - dispatch(receiveDescriptorExtra(loaded, extra)); - return { loaded, extra }; - }); - }).catch((error) => { - log(`No descriptor with uuid ${uuid}`, error); - if (fail) { - return fail(error); - } - throw new SubmissionError({ title: 'Title already used', _error: error.error }); - }); - }; -} - -// Create a new descriptor -export const createDescriptor = () => (dispatch) => { - dispatch({ type: CREATE_DESCRIPTOR }); - return dispatch(push(`/descriptors/edit`)); -}; - -// Edit an existing descriptor list -export const editDescriptor = (uuid: string) => (dispatch, getState) => { - return dispatch(loadDescriptor(uuid)) - .then((descriptor) => dispatch(push(`/descriptors/${descriptor.uuid}/edit`))); -}; - -// This method only saves the descriptor -export const importDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { - log('Importing descriptor', descriptor); - const createOrSave = descriptor.version && descriptor.uuid ? DescriptorService.updateDescriptor : DescriptorService.createDescriptor; - - return createOrSave(getState().login.access_token, descriptor); -}; - -export const searchMatchingDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.searchMatchingDescriptor(token, descriptor) - .catch((error) => { - log('Error', error); - }); -}; - -export const saveDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { - log('Saving descriptor', descriptor); - const createOrSave = descriptor.version && descriptor.uuid ? DescriptorService.updateDescriptor : DescriptorService.createDescriptor; - - return createOrSave(getState().login.access_token, descriptor) - .then((descriptor) => { - // receive the updated descriptor - dispatch(receiveDescriptor(descriptor)); - // and redirect to proper edit page - return dispatch(push(`/descriptors/${descriptor.uuid}/edit`)); - }).catch((error) => { - log('Save error', error); - throw new SubmissionError({ title: 'Could not save descriptor', _error: error.error }); - }); -}; - -export const copyDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorService.copyDescriptor(getState().login.access_token, descriptor) - .catch((error) => { - log('Save error', error); - throw new SubmissionError({ title: 'Could not save descriptor', _error: error.error }); - }); -}; - - -export const deleteDescriptorPromise = (descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorService.deleteDescriptor(getState().login.access_token, descriptor) - .then((descriptor) => { - dispatch(removeDescriptor(descriptor)); - return descriptor; - }) - .catch((error) => { - log('Error', error); - }); -}; - -// Delete a record -export const deleteDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorService.deleteDescriptor(getState().login.access_token, descriptor) - .then((descriptor) => { - dispatch(removeDescriptor(descriptor)); - dispatch(push(`/descriptors`)); - }) - .catch((error) => { - log('Error', error); - }); -}; - -export const promiseListMyDescriptors = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.listMyDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - return paged; - }) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -export function listMyDescriptors(page?, results?, sortBy?, filter?: string | IDescriptorFilter, order?) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - dispatch(loadingDescriptors(page, results, sortBy, filter, order)); - - return DescriptorService.listMyDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - dispatch(receiveDescriptorPage(paged, page, results, sortBy, paged.filter, order)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -export const promiseLoadDescriptors = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.listDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - return paged; - }) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -export function loadDescriptors(page?, results?, sortBy?, filter?, order?) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - dispatch(loadingDescriptors(page, results, sortBy, filter, order)); - - return DescriptorService.listDescriptors(token, page, results, sortBy, filter, order) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - dispatch(receiveDescriptorPage(paged, page, results, sortBy, filter, order)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -export function loadDescriptorsByCode(page?, results?, sortBy?, filter?, order?) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.listDescriptorsByCode(token, page, results, sortBy, filter, order) - .then((paged) => { - const filter = cleanFilters(paged.filter, ['published']); - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - dispatch(receiveDescriptorPage(paged, page, results, sortBy, filter as IDescriptorFilter, order)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); - }; -} - -export function approveDescriptor(descriptor: Descriptor) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.updatePublishState(token, descriptor, PublishState.PUBLISHED) - .then((saved) => { - dispatch(receiveDescriptor(saved)); - }).catch((error) => { - log('Error', error); - }); - }; -} - -export function rejectDescriptor(descriptor: Descriptor, needToRedirect: boolean = true) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.updatePublishState(token, descriptor, PublishState.DRAFT) - .then((saved) => { - dispatch(receiveDescriptor(saved)); - if (needToRedirect) { - dispatch(navigateTo(`/descriptors/${saved.uuid}/edit`)); - } - }).catch((error) => { - log('Error', error); - }); - }; -} - -export function publishDescriptor(descriptor: Descriptor, needToRedirect: boolean = false) { - return (dispatch, getState) => { - const token = getState().login.access_token; - - return DescriptorService.updatePublishState(token, descriptor, PublishState.REVIEWING) - .then((saved) => { - dispatch(receiveDescriptor(saved)); - if (needToRedirect) { - dispatch(showDescriptor(saved.uuid)); - } - }).catch((error) => { - log('Error', error); - }); - }; -} - -export const publishDescriptorPromise = (descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorService.updatePublishState(getState().login.access_token, descriptor, PublishState.REVIEWING) - .catch((error) => { - log('Error', error); - }); -}; - -export const unpublishDescriptorPromise = (descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorService.updatePublishState(getState().login.access_token, descriptor, PublishState.DRAFT) - .catch((error) => { - log('Error', error); - }); -}; - -export const approveDescriptorPromise = (descriptor: Descriptor) => (dispatch, getState) => { - return DescriptorService.updatePublishState(getState().login.access_token, descriptor, PublishState.PUBLISHED) - .catch((error) => { - log('Error', error); - }); -}; diff --git a/src/actions/genesys.ts b/src/actions/genesys.ts deleted file mode 100644 index 1ed1858..0000000 --- a/src/actions/genesys.ts +++ /dev/null @@ -1,40 +0,0 @@ -// import {push} from 'react-router-redux'; -import { GenesysService } from 'service/GenesysService'; -import { Descriptor, DataType, DescriptorList, DescriptorListExtra } from 'model/descriptor.model'; -import { loadDescriptorList } from 'actions/descriptorList'; -import { loadDescriptor } from 'actions/descriptors'; - -import { log } from 'utilities/debug'; - -export const listAccessions = (filters: object, page: number = 0, results: number = 50) => (dispatch, getState) => { - - return GenesysService.listAccessions(getState().login.access_token, filters, page, results) - .then((data) => { - return data; - }).catch((error) => { - log(`Genesys error`, error); - }); -}; - -export const loadGenesysDescriptors = () => (dispatch, getState) => { - log('Loading Genesys descriptor list', 'dc1d4e81-a6dd-4f03-b682-53a3a1383988'); - return dispatch(loadDescriptorList('dc1d4e81-a6dd-4f03-b682-53a3a1383988', - // TODO this can go to a state reducer - async (descriptorList: DescriptorList) => { - if (descriptorList.extras[DescriptorListExtra.JSON_MAPPING]) { - descriptorList.extras[DescriptorListExtra.JSON_MAPPING] = JSON.parse(descriptorList.extras[DescriptorListExtra.JSON_MAPPING]); - - for (const descriptor of descriptorList.descriptors.filter((d) => d.dataType === DataType.SCALE || d.dataType === DataType.CODED)) { - await dispatch(loadDescriptor(descriptor.uuid, (d: Descriptor) => { - console.log(`Loaded details for ${d.uuid}`, d); - descriptor.terms = d.terms; - })); - } - } - return descriptorList; - }, - (error) => { - log(`No Genesys PGR descriptor list`, error); - return error; - })); -}; diff --git a/src/actions/partner.ts b/src/actions/partner.ts deleted file mode 100644 index 6662ecb..0000000 --- a/src/actions/partner.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { push } from 'react-router-redux'; -import { SubmissionError } from 'redux-form'; -import { PartnerService } from 'service/PartnerService'; - -import { - CREATE_PARTNER, GET_PARTNER, RECEIVE_PARTNER, RECEIVE_PARTNERS, RECEIVE_MY_PARTNERLIST, -} from 'constants/partner'; - -import { IReducerAction, Page } from 'model/common.model'; -import { Partner } from 'model/partner.model'; -import { IPartnerFilter } from 'model/filter.model'; -import {log} from 'utilities/debug'; -import {addFilterCode} from 'actions/filterCode'; -import {loadPartnerNames} from 'actions/uuidDecoder'; -import {cleanFilters} from 'utilities'; - -const receiveMyPartnerList = (partners: Partner[]): IReducerAction => ({ - type: RECEIVE_MY_PARTNERLIST, payload: partners, -}); - -const receivePartnerPage = (paged: Page, page, results, sortBy, filter: IPartnerFilter, order): IReducerAction => ({ - type: RECEIVE_PARTNERS, - payload: { paged, query: { page, results, sortBy, filter, order } }, -}); - -const receivePartner = (partner: Partner): IReducerAction => ({ - type: RECEIVE_PARTNER, payload: partner, -}); - -// Create a new record -export const createPartner = () => (dispatch) => { - log('Create new partner'); - dispatch({ type: CREATE_PARTNER }); - return dispatch(push(`/partners/edit`)); -}; - -// Delete a record -export const deletePartner = (partner: Partner) => (dispatch, getState) => { - return PartnerService.deletePartner(getState().login.access_token, partner) - .then((partner) => { - dispatch(push(`/partners`)); - }) - .catch((error) => { - log('Error', error); - }); -}; - -// Just load a record -export const loadPartner = (uuid: string) => (dispatch, getState) => { - log('Loading partner', uuid); - const token = getState().login.access_token; - - dispatch({ type: GET_PARTNER, payload: uuid }); - - return PartnerService.getPartner(token, uuid) - // receive the current partner - .then((partner) => { - return dispatch(receivePartner(partner)); - }).catch((error) => { - log(`No partner with uuid ${uuid}`, error); - }); -}; - -// Edit an existing partner -export const editPartner = (uuid: string) => (dispatch, getState) => { - dispatch(loadPartner(uuid)); - dispatch(push(`/partners/${uuid}/edit`)); -}; - -const showPartner = (uuid: string) => (dispatch) => { - log('Navigating to Partner details'); - dispatch(push(`/partners/${uuid}`)); -}; - -// List user's partners -const loadMyPartners = () => (dispatch, getState) => { - return PartnerService.listMyPartners(getState().login.access_token, 0, 50) - .then((paged) => { - dispatch(receiveMyPartnerList(paged.content)); - dispatch(loadPartnerNames(paged.content)); - }) - .catch((error) => { - log('Error', error); - }); -}; - -export const promiseLoadPartners = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { - const token = getState().login.access_token; - - return PartnerService.listPartners(token, page, results, sortBy, filter, order) - .catch((error) => { - log('Error', error); - return error; - }); -}; - -// Load them -const loadPartners = (page: number, results: number = 100, sortBy?: string, filter?: IPartnerFilter, order?: string) => (dispatch, getState) => { - - return PartnerService.listPartners(getState().login.access_token, page, results, sortBy, order, filter) - .then((paged) => { - dispatch(receivePartnerPage(paged, page, results, sortBy, filter, order)); - dispatch(loadPartnerNames(paged.content)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); -}; - -// Load partners by filter code -const loadPartnersByCode = (page: number, results: number, sortBy?: string, filterCode?: string, order?: string) => (dispatch, getState) => { - - return PartnerService.listPartnersByCode(getState().login.access_token, page, results, sortBy, order, filterCode) - .then((paged) => { - const filter = cleanFilters(paged.filter, ['published']); - dispatch(receivePartnerPage(paged, page, results, sortBy, filter as IPartnerFilter, order)); - dispatch(loadPartnerNames(paged.content)); - return dispatch(addFilterCode(paged.filterCode, paged.filter)); - }) - .catch((error) => { - log('Error', error); - }); -}; - -const savePartner = (partner: Partner) => (dispatch, getState) => { - - return PartnerService.savePartner(getState().login.access_token, partner) - .then((saved) => { - dispatch(receivePartner(saved)); - dispatch(showPartner(saved.uuid)); - }).catch((error) => { - log('Save error', error); - throw new SubmissionError({ name: 'Name already used', _error: error.error }); - }); -}; - -export { - loadMyPartners, loadPartners, receivePartner, loadPartnersByCode, - savePartner, showPartner, -}; diff --git a/src/constants/dashboard.ts b/src/constants/dashboard.ts index 055e398..ef3a9e4 100644 --- a/src/constants/dashboard.ts +++ b/src/constants/dashboard.ts @@ -5,10 +5,7 @@ export const RECEIVE_IS_EDIT_MODE = 'dashboard/RECEIVE_IS_EDIT_MODE'; export const ADD_TO_EDIT_LIST = 'dashboard/ADD_TO_EDIT_LIST'; export const REMOVE_FROM_EDIT_LIST = 'dashboard/REMOVE_FROM_EDIT_LIST'; -export const REFRESH_ITEM = 'dashboard/REFRESH_ITEM'; -export const REMOVE_ITEM = 'dashboard/REMOVE_ITEM'; export const SELECT_ALL = 'dashboard/SELECT_ALL'; export const UNSELECT_ALL = 'dashboard/UNSELECT_ALL'; -export const RECEIVE_DASHBOARD_PAGE = 'dashboard/RECEIVE_DASHBOARD_PAGE'; diff --git a/src/constants/genesys.ts b/src/constants/genesys.ts deleted file mode 100644 index a1bfb02..0000000 --- a/src/constants/genesys.ts +++ /dev/null @@ -1,2 +0,0 @@ - -export const GENESYSBROWSE_FILTERFORM = 'Form/Genesys/BROWSE'; diff --git a/src/datasets/actions/dashboard.ts b/src/datasets/actions/dashboard.ts new file mode 100644 index 0000000..62ddfa3 --- /dev/null +++ b/src/datasets/actions/dashboard.ts @@ -0,0 +1,122 @@ +import { push } from 'react-router-redux'; + +// Actions +import {addFilterCode} from 'actions/filterCode'; + +// Constants +import {DASHBOARD_REMOVE_DATASET, DASHBOARD_RECEIVE_DATASET_PAGE, CREATE_DATASET, DASHBOARD_APPEND_DATASET_PAGE, RECEIVE_DATASET} from 'datasets/constants'; + +// Models +import {Dataset, IDatasetFilter} from 'model/dataset.model'; +import {Page, PublishState} from 'model/common.model'; + +// Service +import {DatasetService} from 'service/DatasetService'; + +// Utility +import {log} from 'utilities/debug'; + +const removeDataset = (dataset: Dataset) => ({ + type: DASHBOARD_REMOVE_DATASET, payload: dataset, +}); +const receiveDataset = (dataset: Dataset) => ({ + type: RECEIVE_DATASET, payload: dataset, +}); + +const appendDatasetPage = (paged: Page, page, results, sortBy, filter: string | IDatasetFilter, order) => ({ + type: DASHBOARD_APPEND_DATASET_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const receiveDatasetPage = (paged: Page, page, results, sortBy, filter: string | IDatasetFilter, order) => ({ + type: DASHBOARD_RECEIVE_DATASET_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + + +const createDataset = () => (dispatch) => { + dispatch({ type: CREATE_DATASET }); + return dispatch(push(`/dashboard/datasets/edit`)); +}; + +export {createDataset}; + +function listMyDatasets(page?, results?, sortBy?, filter?: string | IDatasetFilter, order?) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.listMyDatasets(token, page, results, sortBy, filter, order) + .then((paged) => { + if (paged.number === 0) { + dispatch(receiveDatasetPage(paged, page, results, sortBy, filter, order)); + } else { + dispatch(appendDatasetPage(paged, page, results, sortBy, filter, order)); + } + return dispatch(addFilterCode(paged.filterCode, paged.filter)); + }) + .catch((error) => { + log('Error', error); + }); + }; +} + +export {listMyDatasets}; + +const getOneFromStateByUUID = (uuid: string) => (dispatch, getState) => { + return getState().datasets.dashboard.paged.content.find((dataset) => dataset.uuid === uuid); +}; + +function publishDataset(datasetUuid: string) { + return (dispatch, getState) => { + const dataset = dispatch(getOneFromStateByUUID(datasetUuid)); + return dataset.state === PublishState.DRAFT && + DatasetService.updatePublishState(getState().login.access_token, dataset, PublishState.REVIEWING) + .then((dataset) => dispatch(receiveDataset(dataset))) + .catch((error) => { + log('Error', error); + }); + }; +} + +function unpublishDataset(datasetUuid: string) { + return (dispatch, getState) => { + const dataset = dispatch(getOneFromStateByUUID(datasetUuid)); + return dataset.state !== PublishState.DRAFT && + DatasetService.updatePublishState(getState().login.access_token, dataset, PublishState.DRAFT) + .then((dataset) => dispatch(receiveDataset(dataset))) + .catch((error) => { + log('Error', error); + }); + }; +} + +function approveDataset(datasetUuid: string) { + return (dispatch, getState) => { + const dataset = dispatch(getOneFromStateByUUID(datasetUuid)); + return dataset.state === PublishState.REVIEWING && + DatasetService.updatePublishState(getState().login.access_token, dataset, PublishState.PUBLISHED) + .then((dataset) => dispatch(receiveDataset(dataset))) + .catch((error) => { + log('Error', error); + }); + }; +} + +function deleteDataset(datasetUuid: string) { + return (dispatch, getState) => { + const dataset = dispatch(getOneFromStateByUUID(datasetUuid)); + const token = getState().login.access_token; + + return DatasetService.deleteDataset(token, dataset) + .then((deleted) => { + dispatch(removeDataset(deleted)); + return deleted; + }) + .catch((error) => { + log('Delete error', error); + }); + }; +} + +// Dashboard action section exports +export {publishDataset, approveDataset, unpublishDataset, deleteDataset}; diff --git a/src/datasets/actions/editor.ts b/src/datasets/actions/editor.ts new file mode 100644 index 0000000..9098df6 --- /dev/null +++ b/src/datasets/actions/editor.ts @@ -0,0 +1,421 @@ +import { push } from 'react-router-redux'; +import * as _ from 'lodash'; + +// Actions +import {navigateTo} from 'actions/navigation'; + +// Constants +import {ADD_CREATOR_TO_DATASET, ADD_LOCATION, RECEIVE_LOCATION, REMOVE_CREATOR_FROM_DATASET, REMOVE_LOCATION, UPDATE_DATASET_CREATOR, RECEIVE_DATASET, DASHBOARD_REMOVE_DATASET} from 'datasets/constants'; + +// Models +import {AccessionIdentifier, Dataset} from 'model/dataset.model'; +import {RepositoryFile} from 'model/repositoryFile.model'; +import {Creator} from 'model/creator.model'; +import {Location} from 'model/location.model'; +import {PublishState} from 'model/common.model'; + +// Service +import {DatasetService} from 'service/DatasetService'; +import {RepositoryFileService} from 'service/RepositoryFileService'; +import {CreatorService} from 'service/CreatorService'; +import {LocationService} from 'service/LocationService'; + +// Utility +import {log} from 'utilities/debug'; + +// UI +import steps from 'datasets/ui/dataset-stepper/steps'; + +const removeDataset = (dataset: Dataset) => ({ + type: DASHBOARD_REMOVE_DATASET, payload: dataset, +}); + +const receiveDataset = (dataset: Dataset) => ({ + type: RECEIVE_DATASET, payload: dataset, +}); + +function showDataset(uuid: string) { + return (dispatch) => { + dispatch(push(`/datasets/${uuid}`)); + }; +} + +// Review step +function rejectDataset(dataset: Dataset, needToRedirect: boolean = true) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.updatePublishState(token, dataset, PublishState.DRAFT) + .then((saved) => { + dispatch(receiveDataset(saved)); + if (needToRedirect) { + dispatch(navigateTo(`/dashboard/datasets/${saved.uuid}/edit`)); + } + }).catch((error) => { + log('Error', error); + }); + }; +} + +function approveDataset(dataset: Dataset) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.updatePublishState(token, dataset, PublishState.PUBLISHED) + .then((saved) => { + dispatch(receiveDataset(saved)); + }).catch((error) => { + log('Error', error); + }); + }; +} + +function publishDataset(dataset: Dataset, needToRedirect: boolean = false) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.updatePublishState(token, dataset, PublishState.REVIEWING) + .then((saved) => { + dispatch(receiveDataset(saved)); + if (needToRedirect) { + dispatch(showDataset(saved.uuid)); + } + }).catch((error) => { + log('Error', error); + }); + }; +} + +function deleteDataset(dataset: Dataset) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.deleteDataset(token, dataset) + .then((deleted) => { + dispatch(removeDataset(deleted)); + // dispatch(showDataset(saved.uuid)); + }).catch((error) => { + log('Delete error', error); + }); + }; +} + +// Review step exports +export {rejectDataset, approveDataset, publishDataset, deleteDataset}; + + +// Accession identifiers step +function updateDatasetAccessionIdentifiers(dataset: Dataset, accessionIdentifiers: AccessionIdentifier[]) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.updateAccessionIdentifiers(token, dataset, accessionIdentifiers) + .then((saved) => { + dispatch(receiveDataset(saved)); + }).catch((error) => { + log('Publish error', error); + }); + }; +} + +// Accession identifiers step exports +export {updateDatasetAccessionIdentifiers}; + + +// Descriptors step +function addDescriptorsToDataset(dataset: Dataset, descriptorUuids: string[]) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.addDescriptorsToDataset(token, dataset, descriptorUuids) + .then((saved) => { + dispatch(receiveDataset(saved)); + }).catch((error) => { + log('Add error', error); + }); + }; +} + +const setDescriptorsToDatasetRequest = (dataset: Dataset, descriptorUuids: string[]) => (dispatch, getState) => { + return DatasetService.setDescriptorsToDataset(getState().login.access_token, dataset, descriptorUuids) + .then((saved) => { + dispatch(receiveDataset(saved)); + }).catch((error) => { + log('Add error', error); + }); +}; + +function removeDescriptorsFromDataset(dataset: Dataset, descriptorUuids: string[]) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.removeDescriptorsFromDataset(token, dataset, descriptorUuids) + .then((saved) => { + dispatch(receiveDataset(saved)); + }).catch((error) => { + log('Delete error', error); + }); + }; +} + +// Descriptors step exports +export {addDescriptorsToDataset, setDescriptorsToDatasetRequest, removeDescriptorsFromDataset}; + + +// Repository File step +const uploadRepositoryFileRequest = (datasetUUID: string, file: File) => (dispatch, getState) => { + const token = getState().login.access_token; + + return RepositoryFileService.uploadRepositoryFile(token, datasetUUID, file) + .then((dataset) => { + dispatch(receiveDataset(dataset)); + }).catch((error) => { + log('Save error', error); + }); +}; + +const updateRepositoryFileRequest = (datasetUUID: string, repositoryfile: RepositoryFile) => (dispatch, getState) => { + const token = getState().login.access_token; + + return RepositoryFileService.updateRepositoryFile(token, datasetUUID, repositoryfile) + .then((dataset) => { + dispatch(receiveDataset(dataset)); + }).catch((error) => { + log('Save error', error); + }); +}; + +const deleteRepositoryFileRequest = (datasetUUID: string, uuid: string) => (dispatch, getState) => { + const token = getState().login.access_token; + + return RepositoryFileService.deleteRepositoryFile(token, datasetUUID, uuid) + .then((dataset) => { + dispatch(receiveDataset(dataset)); + }).catch((error) => { + log('Delete error', error); + }); +}; + +// Repository File step exports +export {uploadRepositoryFileRequest, updateRepositoryFileRequest, deleteRepositoryFileRequest}; + +// Creators step +function addCreatorToDataset(creator: Creator, uuid: string) { + return { + type: ADD_CREATOR_TO_DATASET, + payload: { + creator, + datasetUUID: uuid, + }, + }; +} + +function updateCreator(creator: Creator) { + return { + type: UPDATE_DATASET_CREATOR, + payload : { + creator, + }, + }; +} + +function removeCreator(creator: Creator, uuid: string) { + return { + type: REMOVE_CREATOR_FROM_DATASET, + payload : { + creator, + datasetUUID: uuid, + }, + }; +} + +// FIXME No uuid param required, currentDataset is available in state +function createDatasetCreator(uuid: string) { + return (dispatch, getState) => { + log('createCreator'); + return CreatorService.createCreator(getState().login.access_token, uuid) + .then((obj) => { + dispatch(addCreatorToDataset(obj, uuid)); + }).catch((error) => { + log('Create creator error', error); + }); + }; +} + +function updateCreatorRequest(uuid: string, creator: Creator) { + return (dispatch, getState) => { + const token = getState().login.access_token; + return CreatorService.updateCreator(token, uuid, creator) + .then((obj) => { + dispatch(updateCreator(obj)); + }).catch((error) => { + log('Update creator error', error); + }); + }; +} + +function deleteCreatorRequest(uuid: string, creator: Creator) { + return (dispatch, getState) => { + const token = getState().login.access_token; + return CreatorService.deleteCreator(token, uuid, creator) + .then((obj) => { + dispatch(removeCreator(obj, uuid)); + }).catch((error) => { + log('Delete creator error', error); + }); + }; +} + +// Creators step exports +export {createDatasetCreator, updateCreatorRequest, deleteCreatorRequest }; + + +// Timing and Location step +function addLocation(datasetUUID: string, location: Location) { + return { + type: ADD_LOCATION, + payload: { + datasetUUID, + location, + }, + }; +} + +function receiveLocation(location: Location) { + return { + type: RECEIVE_LOCATION, + payload: { + location, + }, + }; +} + +function deleteLocation(datasetUUID: string, location: Location) { + return { + type: REMOVE_LOCATION, + payload: { + datasetUUID, + location, + }, + }; +} + +function createLocationRequest(datasetUUID: string) { + const location = new Location({}); + + return (dispatch, getState) => { + const token = getState().login.access_token; + + return LocationService.saveLocation(token, datasetUUID, location) + .then((saved) => { + dispatch(addLocation(datasetUUID, saved)); + }).catch((error) => { + log('Save error', error); + }); + }; +} + +function updateLocationRequest(datasetUUID: string, location: Location) { + + return (dispatch, getState) => { + const token = getState().login.access_token; + + return LocationService.saveLocation(token, datasetUUID, location) + .then((saved) => { + dispatch(receiveLocation(saved)); + dispatch(receiveDataset(refreshStartEndDates(getState().datasets.dashboard.dataset))); + }).catch((error) => { + log('Save error', error); + }); + }; +} + +function deleteLocationRequest(datasetUUID: string, location: Location) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return LocationService.deleteLocation(token, datasetUUID, location) + .then((saved) => { + dispatch(deleteLocation(datasetUUID, saved)); + dispatch(receiveDataset(refreshStartEndDates(getState().datasets.dashboard.dataset))); + }).catch((error) => { + log('Delete error', error); + }); + }; +} + +// Timing and Location step exports +export {createLocationRequest, updateLocationRequest, deleteLocationRequest, receiveLocation}; + + +// Common actions +function loadDataset(uuid: string) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.getDataset(token, uuid) + .then((dataset) => { + dispatch(receiveDataset(dataset)); + }) + .catch((error) => { + log('Error', error); + }); + }; +} + +const saveDataset = (dataset: Dataset) => (dispatch, getState) => { + + const needToRedirect: boolean = !(dataset.version && dataset.uuid); + + if (_.isEqual({...getState().datasets.dashboard.dataset}, {...dataset})) { + return; + } + + // remove normalized data here + const data = new Dataset({ + repositoryFiles: [], + creators: [], + locations: [], + descriptors: [], + ...dataset, + }); + + const token = getState().login.access_token; + + return DatasetService.saveDataset(token, data) + .then((saved) => { + dispatch(receiveDataset(saved)); + if (needToRedirect) { + dispatch(gotoNextStep(saved)); + } + }).catch((error) => { + log('Save error', error); + }); +}; + +function gotoNextStep(dataset: Dataset) { + return (dispatch, getState) => { + const link = window.location.pathname.split('/').pop(); + const stepId = steps.find((e) => e.path.endsWith(link)).id; + const path = steps.find((e) => e.id === (stepId + 1)).path; + dispatch(navigateTo(`/dashboard/datasets/${dataset.uuid}/${path}`)); + }; +} + +function refreshStartEndDates(dataset) { + const res = {...dataset}; + res.startDate = null; + res.endDate = null; + res.locations.forEach((location) => { + if (!res.startDate || (location.startDate && res.startDate.localeCompare(location.startDate) > 0)) { + res.startDate = location.startDate; + } + if (!res.endDate || (location.endDate && res.endDate.localeCompare(location.endDate) < 0)) { + res.endDate = location.endDate; + } + }); + return res; +} + +// Common actions exports +export {loadDataset, saveDataset}; diff --git a/src/datasets/actions/public.ts b/src/datasets/actions/public.ts new file mode 100644 index 0000000..1d7c22b --- /dev/null +++ b/src/datasets/actions/public.ts @@ -0,0 +1,76 @@ +// Actions +import {addFilterCode} from 'actions/filterCode'; + +// Constants +import {RECEIVE_DATASET, RECEIVE_DATASET_PAGE, APPEND_DATASET_PAGE} from 'datasets/constants'; + +// Model +import {Dataset, IDatasetFilter} from 'model/dataset.model'; +import {Page} from 'model/common.model'; + +// Service +import {DatasetService} from 'service/DatasetService'; + +// Util +import {log} from 'utilities/debug'; + + +const appendDatasetPage = (paged: Page, page, results, sortBy, filter: IDatasetFilter, order) => ({ + type: APPEND_DATASET_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const receiveDatasetPage = (paged: Page, page, results, sortBy, filter: IDatasetFilter, order) => ({ + type: RECEIVE_DATASET_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + + +const receiveDataset = (dataset: Dataset) => ({ + type: RECEIVE_DATASET, payload: dataset, +}); + +function loadDataset(uuid: string) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.getDataset(token, uuid) + .then((dataset) => { + dispatch(receiveDataset(dataset)); + }) + .catch((error) => { + log('Error', error); + }); + }; +} + +function listDatasetsRequest(page?, results?, sortBy?, filter?, order?) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.listDatasets(token, page, results, sortBy, filter, order) + .then((paged) => { + if (paged.number === 0) { + dispatch(receiveDatasetPage(paged, page, results, sortBy, filter, order)); + } else { + dispatch(appendDatasetPage(paged, page, results, sortBy, filter, order)); + } + return dispatch(addFilterCode(paged.filterCode, paged.filter)); + }) + .catch((error) => { + log('Error', error); + }); + }; +} + +const promiselistDatasets = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.listDatasets(token, page, results, sortBy, filter, order) + .catch((error) => { + log('Error', error); + return error; + }); +}; + +export {listDatasetsRequest, promiselistDatasets, loadDataset}; diff --git a/src/constants/datasets.ts b/src/datasets/constants.ts similarity index 76% rename from src/constants/datasets.ts rename to src/datasets/constants.ts index 14853f6..c3177e1 100644 --- a/src/constants/datasets.ts +++ b/src/datasets/constants.ts @@ -5,6 +5,12 @@ export const CREATE_DATASET = 'App/Dataset/RECEIVE_DATASET'; export const RECEIVE_DATASET = 'App/RECEIVE_DATASET'; export const REMOVE_DATASET = 'App/DELETE_DATASET'; export const RECEIVE_DATASET_PAGE = 'App/RECEIVE_DATASET_PAGE'; +export const APPEND_DATASET_PAGE = 'App/APPEND_DATASET_PAGE'; + +// dashboard +export const DASHBOARD_REMOVE_DATASET = 'dataset/dashboard/REMOVE_DATASET'; +export const DASHBOARD_RECEIVE_DATASET_PAGE = 'dataset/dashboard/RECEIVE_DATASET_PAGE'; +export const DASHBOARD_APPEND_DATASET_PAGE = 'dataset/dashboard/APPEND_DATASET_PAGE'; // creators const params export const RECEIVE_CREATOR = 'App/RECEIVE_CREATOR'; diff --git a/src/datasets/reducers/dashboard.ts b/src/datasets/reducers/dashboard.ts new file mode 100644 index 0000000..503e3de --- /dev/null +++ b/src/datasets/reducers/dashboard.ts @@ -0,0 +1,172 @@ +import update from 'immutability-helper'; +import {log} from 'utilities/debug'; +import * as _ from 'lodash'; + +import { + CREATE_DATASET, + ADD_CREATOR_TO_DATASET, + REMOVE_CREATOR_FROM_DATASET, + UPDATE_DATASET_CREATOR, + ADD_LOCATION, + RECEIVE_LOCATION, + REMOVE_LOCATION, + DASHBOARD_REMOVE_DATASET, + DASHBOARD_RECEIVE_DATASET_PAGE, + RECEIVE_DATASET, + DASHBOARD_APPEND_DATASET_PAGE, +} from 'datasets/constants'; + +import { Dataset } from 'model/dataset.model'; +import {Page} from 'model/common.model'; + +const INITIAL_STATE: { + dataset: Dataset, + paged: Page, + pagedQuery: any, +} = { + dataset: null, + paged: null, + pagedQuery: null, +}; + +function datasetsDashboard(state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) { + + switch (action.type) { + case CREATE_DATASET: { + return update(state, { + dataset: { $set: new Dataset() }, + }); + } + case RECEIVE_DATASET: { + const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; + + if (receivedIndex !== -1) { + return update(state, { + dataset: { $set: action.payload }, + paged: { + content: { + [receivedIndex]: {$set: action.payload}, + }, + }, + }); + } else { + return update(state, { + dataset: { $set: action.payload }, + paged: {$set: null}, + }); + } + } + + case DASHBOARD_REMOVE_DATASET: { + if (state.paged) { + const removeIndex = _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid); + return removeIndex === -1 ? state + : update(state, { + paged: { + content: {$splice: [[removeIndex, 1]]}, + numberOfElements: {$set: state.paged.numberOfElements - 1}, + totalElements: {$set: state.paged.totalElements - 1}, + }, + }); + } + return state; + } + case DASHBOARD_RECEIVE_DATASET_PAGE: { + return update(state, { + paged: { $set: action.payload.paged }, + pagedQuery: { $set: action.payload.query }, + }); + } + case DASHBOARD_APPEND_DATASET_PAGE: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } + + // Creators step + case ADD_CREATOR_TO_DATASET: { + log('Payload ADD_CREATOR_TO_DATASET', action); + if (state.dataset) { // && action.payload.datasetUUID === state.dataset.uuid) { + return update(state, { + dataset: { creators: { $push: [ action.payload.creator ] } }, + }); + } else { + return state; + } + } + + case REMOVE_CREATOR_FROM_DATASET: { + log('Payload REMOVE_CREATOR_FROM_DATASET', action); + if (state.dataset) { // && action.payload.datasetUUID === state.dataset.uuid) { + return update(state, { + dataset: { creators: { $apply: (creators) => creators.filter((creator) => creator.uuid !== action.payload.creator.uuid) } }, + }); + } else { + return state; + } + } + + case UPDATE_DATASET_CREATOR: { + log('Payload UPDATE_DATASET_CREATOR', action); + if (state.dataset) { // && action.payload.datasetUUID === state.dataset.uuid) { + const index = state.dataset.creators.findIndex((creator) => creator.uuid === action.payload.creator.uuid); + return update(state, { + dataset: { creators: { [index]: { $set: action.payload.creator } } }, + }); + } else { + return state; + } + } + + // Location step + case ADD_LOCATION: { + log('Payload ADD_LOCATION', action); + if (state.dataset) { // && action.payload.datasetUUID === state.dataset.uuid) { + return update(state, { + dataset: { locations: { $push: [ action.payload.location ] } }, + }); + } else { + return state; + } + } + + case REMOVE_LOCATION: { + log('Payload REMOVE_LOCATION', action); + if (state.dataset) { // && action.payload.datasetUUID === state.dataset.uuid) { + return update(state, { + dataset: { locations: { $apply: (locations) => locations.filter((location) => location.uuid !== action.payload.location.uuid) } }, + }); + } else { + return state; + } + } + + case RECEIVE_LOCATION: { + log('Payload RECEIVE_LOCATION', action); + if (state.dataset) { // && action.payload.datasetUUID === state.dataset.uuid) { + const index = state.dataset.locations.findIndex((location) => location.uuid === action.payload.location.uuid); + return update(state, { + dataset: { locations: { [index]: { $set: action.payload.location } } }, + }); + } else { + return state; + } + } + + default: + return state; + } +} + +export default datasetsDashboard; diff --git a/src/datasets/reducers/index.ts b/src/datasets/reducers/index.ts new file mode 100644 index 0000000..2fc8e18 --- /dev/null +++ b/src/datasets/reducers/index.ts @@ -0,0 +1,10 @@ +import { combineReducers } from 'redux'; +import dashboard from './dashboard'; +import datasetsPublic from './public'; + +const rootReducer = combineReducers({ + dashboard, + public: datasetsPublic, +}); + +export default rootReducer; diff --git a/src/datasets/reducers/public.ts b/src/datasets/reducers/public.ts new file mode 100644 index 0000000..4504d7c --- /dev/null +++ b/src/datasets/reducers/public.ts @@ -0,0 +1,79 @@ +import update from 'immutability-helper'; +import * as _ from 'lodash'; + +import {APPEND_DATASET_PAGE, RECEIVE_DATASET, RECEIVE_DATASET_PAGE} from 'datasets/constants'; +import {LOGIN_APP, LOGIN_USER, LOGOUT} from 'constants/login'; + +import {Dataset} from 'model/dataset.model'; +import {Page} from 'model/common.model'; + +const INITIAL_STATE: { + dataset: Dataset, + paged: Page, + pagedQuery: any, +} = { + dataset: null, + paged: null, + pagedQuery: null, +}; + +function datasetsPublic(state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) { + + switch (action.type) { + // TODO is it has to be here + case LOGIN_USER: + case LOGIN_APP: + case LOGOUT: { + return update(state, { $set: INITIAL_STATE }); + } + + case RECEIVE_DATASET: { + const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; + + if (receivedIndex !== -1) { + return update(state, { + dataset: { $set: action.payload }, + paged: { + content: { + [receivedIndex]: {$set: action.payload}, + }, + }, + }); + } else { + return update(state, { + dataset: { $set: action.payload }, + paged: {$set: null}, + }); + } + } + + case RECEIVE_DATASET_PAGE: { + return update(state, { + paged: { $set: action.payload.paged }, + pagedQuery: { $set: action.payload.query }, + }); + } + + case APPEND_DATASET_PAGE: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } + + default: + return state; + } +} + +export default datasetsPublic; diff --git a/src/datasets/routes.ts b/src/datasets/routes.ts new file mode 100644 index 0000000..a7f4d2f --- /dev/null +++ b/src/datasets/routes.ts @@ -0,0 +1,79 @@ +import DatasetSuggestionsPage from 'datasets/ui/search/SuggestionsPage'; +import DatasetBrowsePage from 'datasets/ui/BrowsePage'; +import DatasetDisplayPage from 'datasets/ui/DisplayPage'; +import DatasetStepper from 'datasets/ui/dataset-stepper'; +import DatasetDashboardPage from 'datasets/ui/DashboardPage'; + +import datasetSteps from 'datasets/ui/dataset-stepper/steps'; +import BasicInfoStep from 'datasets/ui/dataset-stepper/steps/basic-info'; + +import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import Wrapper from 'ui/catalog/Wrapper'; + +const publicRoutes = [ + { + path: '/datasets', + component: Wrapper, + extraProps: { + title: 'p.datasets.title', + subtitle: 'p.datasets.subtitle', + }, + routes: [ + { + path: '/suggest', + component: DatasetSuggestionsPage, + exact: true, + }, + { + path: '/:uuid', + component: DatasetDisplayPage, + exact: true, + }, + { + path: '/', + component: DatasetBrowsePage, + exact: true, + }, + ], + }, +]; + +const dashboardRoutes = [ + { + path: '/datasets/edit', + component: DatasetStepper, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + extraProps: { + title: 'Phenotypic dataset publisher', + }, + routes: [ + { + path: '/', + component: BasicInfoStep, + exact: true, + }, + ], + }, + { + path: '/datasets/:uuid/', + component: DatasetStepper, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + extraProps: { + title: 'Phenotypic dataset publisher', + }, + routes: [ + ...datasetSteps, + ], + }, + { + path: '/datasets', + component: DatasetDashboardPage, + auth: [ROLE_USER], + extraProps: { + title: 'My Dashboard', + }, + }, +]; + + +export {publicRoutes as datasetPublicRoutes, dashboardRoutes as datasetDashboardRoutes}; diff --git a/src/ui/pages/dataset/BrowsePage.tsx b/src/datasets/ui/BrowsePage.tsx similarity index 86% rename from src/ui/pages/dataset/BrowsePage.tsx rename to src/datasets/ui/BrowsePage.tsx index 97d88e0..6a5efde 100644 --- a/src/ui/pages/dataset/BrowsePage.tsx +++ b/src/datasets/ui/BrowsePage.tsx @@ -8,7 +8,7 @@ import { parse } from 'query-string'; import { filterCodeToUrl } from 'actions/filterCode'; import { listCrops } from 'actions/crop'; -import { listDatasetsRequest, promiselistDatasets, listDatasetsByCodeRequest } from 'actions/dataset'; +import { listDatasetsRequest } from 'datasets/actions/public'; import { Dataset, IDatasetFilter } from 'model/dataset.model'; import { Page, Pagination } from 'model/common.model'; @@ -34,8 +34,6 @@ interface IDatasetsProps extends React.ClassAttributes { paged: Page; filterCodeToUrl: any; listDatasetsRequest: any; - listDatasetsByCodeRequest: any; - promiselistDatasets: any; listCrops: () => any; history: any; location: any; @@ -44,19 +42,15 @@ interface IDatasetsProps extends React.ClassAttributes { class BrowsePage extends React.Component { public static needs = [ - ({ search }) => listDatasetsByCodeRequest(parse(search).p, parse(search).l, parse(search).s, parse(search).filter, parse(search).d), + ({ search }) => listDatasetsRequest(parse(search).p, parse(search).l, parse(search).s, parse(search).filter, parse(search).d), ]; public componentWillMount() { - const {paged, pagination, listDatasetsRequest, listDatasetsByCodeRequest, listCrops} = this.props; + const {paged, pagination, listDatasetsRequest, listCrops} = this.props; if (! paged || paged.filterCode !== pagination.filterCode) { log('Loading datasets'); - if (pagination.filterCode) { - listDatasetsByCodeRequest(pagination.page, pagination.size, pagination.sort, pagination.filterCode, pagination.dir); - } else { - listDatasetsRequest(pagination.page, pagination.size, pagination.sort, {}, pagination.dir); - } + listDatasetsRequest(pagination.page, pagination.size, pagination.sort, pagination.filter || pagination.filterCode, pagination.dir); } listCrops(); } @@ -106,8 +100,8 @@ class BrowsePage extends React.Component { } protected loadNextPage = (page: number, pageSize: number) => { - const {promiselistDatasets, pagination} = this.props; - return promiselistDatasets(page, pageSize, pagination.sort, pagination.filter, pagination.dir); + const {listDatasetsRequest, pagination} = this.props; + return listDatasetsRequest(page, pageSize, pagination.sort, pagination.filter, pagination.dir); } protected renderDataset = (d: Dataset) => ; @@ -182,13 +176,11 @@ const mapStateToProps = (state, ownProps) => ({ filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, filterCode: parse(ownProps.location.search).filter, }), - paged: state.datasets.paged, + paged: state.datasets.public.paged, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ listDatasetsRequest, - promiselistDatasets, - listDatasetsByCodeRequest, listCrops, filterCodeToUrl, }, dispatch); diff --git a/src/datasets/ui/DashboardPage.tsx b/src/datasets/ui/DashboardPage.tsx new file mode 100644 index 0000000..c01429c --- /dev/null +++ b/src/datasets/ui/DashboardPage.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import { parse } from 'query-string'; + +import BaseMyDataPage from 'ui/catalog/dashboard/MyDataPage'; +import {approveDataset, deleteDataset, listMyDatasets, unpublishDataset, publishDataset} from 'datasets/actions/dashboard'; +import {Dataset} from 'model/dataset.model'; +import {DatasetLink} from 'ui/catalog/Links'; +import {PublishState} from 'model/common.model'; + +const renderDataLink = ({row, children}) => ({ children }); + + +class DashboardPage extends BaseMyDataPage { + protected static needs = [ + ({ search }) => { + const pageCurrent = parse(search).p || 0; + const pageSize = parse(search).l || 100; + const pageSort = parse(search).s; + const pageDir = parse(search).d; + const filterCode = parse(search).filter; + + return listMyDatasets(pageCurrent, pageSize, pageSort, filterCode || {}, pageDir); + }, + ]; +} + +const mapStateToProps = (state, ownProps) => ({ + paged: state.datasets.dashboard.paged, + tab: 'datasets', +}); + +const mapDispatchToProps = (dispatch) => bindActionCreators({ + listMyData: listMyDatasets, + deleteOne: deleteDataset, + publishOne: publishDataset, + approveOne: approveDataset, + unpublishOne: unpublishDataset, + renderDataLink, +}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage); diff --git a/src/ui/pages/dataset/DisplayPage.tsx b/src/datasets/ui/DisplayPage.tsx similarity index 94% rename from src/ui/pages/dataset/DisplayPage.tsx rename to src/datasets/ui/DisplayPage.tsx index 73a92eb..3e939d8 100644 --- a/src/ui/pages/dataset/DisplayPage.tsx +++ b/src/datasets/ui/DisplayPage.tsx @@ -4,7 +4,8 @@ import { connect } from 'react-redux'; import { withStyles } from '@material-ui/core/styles'; import { translate } from 'react-i18next'; -import { loadDataset, deleteDataset, publishDataset, rejectDataset, approveDataset } from 'actions/dataset'; +import { deleteDataset, publishDataset, rejectDataset, approveDataset } from 'datasets/actions/editor'; +import { loadDataset } from 'datasets/actions/public'; import { Dataset } from 'model/dataset.model'; import BackButton from 'ui/common/buttons/BackButton'; @@ -85,7 +86,7 @@ class DatasetDetail extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.public.dataset, uuid: ownProps.match.params.uuid, }); diff --git a/src/ui/pages/dataset/c/Card.tsx b/src/datasets/ui/c/Card.tsx similarity index 100% rename from src/ui/pages/dataset/c/Card.tsx rename to src/datasets/ui/c/Card.tsx diff --git a/src/ui/pages/dataset/c/DatasetDisplay.tsx b/src/datasets/ui/c/DatasetDisplay.tsx similarity index 100% rename from src/ui/pages/dataset/c/DatasetDisplay.tsx rename to src/datasets/ui/c/DatasetDisplay.tsx diff --git a/src/ui/pages/dataset/c/Filters.tsx b/src/datasets/ui/c/Filters.tsx similarity index 97% rename from src/ui/pages/dataset/c/Filters.tsx rename to src/datasets/ui/c/Filters.tsx index e90d146..91f640f 100644 --- a/src/ui/pages/dataset/c/Filters.tsx +++ b/src/datasets/ui/c/Filters.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { reduxForm } from 'redux-form'; -import { DATASET_FILTERFORM } from 'constants/datasets'; +import { DATASET_FILTERFORM } from 'datasets/constants'; import FiltersBlock from 'ui/common/filter/FiltersBlock'; import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; diff --git a/src/ui/pages/dataset/c/LocationMap.tsx b/src/datasets/ui/c/LocationMap.tsx similarity index 100% rename from src/ui/pages/dataset/c/LocationMap.tsx rename to src/datasets/ui/c/LocationMap.tsx diff --git a/src/ui/pages/dataset/dataset-stepper/index.tsx b/src/datasets/ui/dataset-stepper/index.tsx similarity index 88% rename from src/ui/pages/dataset/dataset-stepper/index.tsx rename to src/datasets/ui/dataset-stepper/index.tsx index e5a275a..741f35b 100644 --- a/src/ui/pages/dataset/dataset-stepper/index.tsx +++ b/src/datasets/ui/dataset-stepper/index.tsx @@ -6,14 +6,14 @@ import Grid from '@material-ui/core/Grid'; import { log } from 'utilities/debug'; import confirm from 'utilities/confirmAlert'; -import TopSection from 'ui/common/stepper/TopSection'; import BottomSection from 'ui/common/stepper/BottomSection'; import { navigateTo } from 'actions/navigation'; import { setPageTitle } from 'actions/pageTitle'; -import { loadDataset, publishDataset, deleteDataset } from 'actions/dataset'; +import { loadDataset, publishDataset, deleteDataset } from 'datasets/actions/editor'; import { Dataset } from 'model/dataset.model'; import renderRoutes from 'ui/renderRoutes'; import steps from './steps'; +import TopSection from 'ui/common/stepper/TopSection'; interface IDatasetProps extends React.ClassAttributes { classes: any; @@ -40,8 +40,8 @@ class DatasetStepper extends React.Component { public constructor(props: any) { super(props); - const {pageTitle, setPageTitle} = this.props; - setPageTitle(pageTitle); + // const {pageTitle, setPageTitle} = this.props; + // setPageTitle(pageTitle); } public componentDidMount() { @@ -54,10 +54,10 @@ class DatasetStepper extends React.Component { protected gotoStep = (id) => { const {dataset, uuid, navigateTo} = this.props; - const path = steps.find((e) => e.id === id).link; + const path = steps.find((e) => e.id === id).path; log('Go to step', path); if (uuid || (dataset && dataset.uuid)) { - navigateTo(`/datasets/${dataset ? dataset.uuid : uuid}/${path}`); + navigateTo(`/dashboard/datasets/${dataset ? dataset.uuid : uuid}/${path}`); } else { // no navigation! } @@ -100,7 +100,7 @@ class DatasetStepper extends React.Component { return ( - + { renderRoutes(route.routes, match.path, { stillLoading, onGotoStep: this.gotoStep, onDelete: this.onDelete, onPublish: this.onPublish }) } @@ -115,7 +115,7 @@ const mapStateToProps = (state, ownProps) => ({ pageTitle: ownProps.route.extraProps.title, // route-configured location: ownProps.location, uuid: ownProps.match.params.uuid, - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/datasets/ui/dataset-stepper/steps.ts b/src/datasets/ui/dataset-stepper/steps.ts new file mode 100644 index 0000000..e56910d --- /dev/null +++ b/src/datasets/ui/dataset-stepper/steps.ts @@ -0,0 +1,77 @@ +import BasicInfoStep from 'datasets/ui/dataset-stepper/steps/basic-info'; +import ReviewAndPublishStep from 'datasets/ui/dataset-stepper/steps/review'; +import ReorderTraitsStep from 'datasets/ui/dataset-stepper/steps/reorder'; +import Traits from 'datasets/ui/dataset-stepper/steps/traits'; +import PastingTraitsStep from 'datasets/ui/dataset-stepper/steps/pasting-traits'; +import AccessionsListStep from 'datasets/ui/dataset-stepper/steps/accessions-list'; +import LocationStep from 'datasets/ui/dataset-stepper/steps/location'; +import FilesStep from 'datasets/ui/dataset-stepper/steps/files'; +import Creators from 'datasets/ui/dataset-stepper/steps/creators'; + +const steps = [ + { + id: 1, + name: 'Basic information', + path: 'edit', + component: BasicInfoStep, + exact: true, + }, + { + id: 2, + name: 'Dataset attachments', + path: 'edit/files', + component: FilesStep, + exact: true, + }, + { + id: 3, + name: 'Dataset creators', + path: 'edit/dataset-creator', + component: Creators, + exact: true, + }, + { + id: 4, + name: 'Location and timing', + path: 'edit/location', + component: LocationStep, + exact: true, + }, + { + id: 5, + name: 'List of accessions', + path: 'edit/list-of-accessions', + component: AccessionsListStep, + exact: true, + }, + { + id: 6, + name: 'Select descriptors in batch', + path: 'edit/pasting-traits', + component: PastingTraitsStep, + exact: true, + }, + { + id: 7, + name: 'Browse and select descriptors', + path: 'edit/traits-observed', + component: Traits, + exact: true, + }, + { + id: 8, + name: 'Reorder descriptors', + path: 'edit/reorder-descriptors', + component: ReorderTraitsStep, + exact: true, + }, + { + id: 9, + name: 'Review and publish', + path: 'edit/review-and-publish', + component: ReviewAndPublishStep, + exact: true, + }, +]; + +export default steps; diff --git a/src/ui/pages/dataset/dataset-stepper/steps/accessions-list/ListOfAccesion.tsx b/src/datasets/ui/dataset-stepper/steps/accessions-list/ListOfAccesion.tsx similarity index 100% rename from src/ui/pages/dataset/dataset-stepper/steps/accessions-list/ListOfAccesion.tsx rename to src/datasets/ui/dataset-stepper/steps/accessions-list/ListOfAccesion.tsx diff --git a/src/ui/pages/dataset/dataset-stepper/steps/accessions-list/index.tsx b/src/datasets/ui/dataset-stepper/steps/accessions-list/index.tsx similarity index 92% rename from src/ui/pages/dataset/dataset-stepper/steps/accessions-list/index.tsx rename to src/datasets/ui/dataset-stepper/steps/accessions-list/index.tsx index b6b8c76..e8dfc99 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/accessions-list/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/accessions-list/index.tsx @@ -3,9 +3,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {Dataset, AccessionIdentifier} from 'model/dataset.model'; -import {updateDatasetAccessionIdentifiers} from 'actions/dataset'; +import {updateDatasetAccessionIdentifiers} from 'datasets/actions/editor'; import ListOfAccesion from './ListOfAccesion'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; interface IAccessionsListStep extends React.ClassAttributes { @@ -50,7 +50,7 @@ class AccessionsListStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/BasicInfoForm.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx similarity index 98% rename from src/ui/pages/dataset/dataset-stepper/steps/basic-info/BasicInfoForm.tsx rename to src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx index ece95b1..c530ca8 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/BasicInfoForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import {Field, reduxForm, FieldArray} from 'redux-form'; -import {DATASET_BASIC_INFO_FORM} from 'constants/datasets'; +import {DATASET_BASIC_INFO_FORM} from 'datasets/constants'; import {TextField} from 'ui/common/text-field'; import {MarkdownField} from 'ui/catalog/markdown'; diff --git a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/BasicInfoRadioGroup.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoRadioGroup.tsx similarity index 100% rename from src/ui/pages/dataset/dataset-stepper/steps/basic-info/BasicInfoRadioGroup.tsx rename to src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoRadioGroup.tsx diff --git a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/RemoteSubmit.ts b/src/datasets/ui/dataset-stepper/steps/basic-info/RemoteSubmit.ts similarity index 73% rename from src/ui/pages/dataset/dataset-stepper/steps/basic-info/RemoteSubmit.ts rename to src/datasets/ui/dataset-stepper/steps/basic-info/RemoteSubmit.ts index 305fc6b..d1b2d68 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/RemoteSubmit.ts +++ b/src/datasets/ui/dataset-stepper/steps/basic-info/RemoteSubmit.ts @@ -1,5 +1,5 @@ import {Dataset} from 'model/dataset.model'; -import { saveDataset } from 'actions/dataset'; +import { saveDataset } from 'datasets/actions/editor'; export default function remoteSubmit(values: Dataset, dispatch) { dispatch(saveDataset(values)); diff --git a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/index.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx similarity index 91% rename from src/ui/pages/dataset/dataset-stepper/steps/basic-info/index.tsx rename to src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx index 816b13a..fd9bdd7 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/basic-info/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx @@ -6,13 +6,13 @@ import {log} from 'utilities/debug'; import BasicInfoForm from './BasicInfoForm'; import {Dataset} from 'model/dataset.model'; -import {loadMyPartners} from 'actions/partner'; +import {loadMyPartners} from 'partners/actions/dashboard'; import {Partner} from 'model/partner.model'; import {Crop} from 'model/crop.model'; import {submit, isInvalid} from 'redux-form'; -import {DATASET_BASIC_INFO_FORM} from 'constants/datasets'; +import {DATASET_BASIC_INFO_FORM} from 'datasets/constants'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; interface IDatasetProps extends React.ClassAttributes { uuid: string; @@ -67,7 +67,7 @@ class BasicInfoStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/creators/DatasetCreatorForm.tsx b/src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx similarity index 99% rename from src/ui/pages/dataset/dataset-stepper/steps/creators/DatasetCreatorForm.tsx rename to src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx index 821db7f..a924db4 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/creators/DatasetCreatorForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx @@ -17,7 +17,7 @@ import Validators from 'utilities/Validators'; import {log} from 'utilities/debug'; import {TextField} from 'ui/common/text-field'; -import {DATASET_CREATOR_FORM} from 'constants/datasets'; +import {DATASET_CREATOR_FORM} from 'datasets/constants'; import {Dataset} from 'model/dataset.model'; import {Creator, CreatorRole} from 'model/creator.model'; diff --git a/src/ui/pages/dataset/dataset-stepper/steps/creators/index.tsx b/src/datasets/ui/dataset-stepper/steps/creators/index.tsx similarity index 93% rename from src/ui/pages/dataset/dataset-stepper/steps/creators/index.tsx rename to src/datasets/ui/dataset-stepper/steps/creators/index.tsx index 2f9a72c..60aa181 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/creators/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/creators/index.tsx @@ -1,16 +1,16 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; +import * as _ from 'lodash'; import DatasetCreatorForm from './DatasetCreatorForm'; -import { createDatasetCreator, deleteCreatorRequest, updateCreatorRequest } from 'actions/dataset'; +import { createDatasetCreator, deleteCreatorRequest, updateCreatorRequest } from 'datasets/actions/editor'; import { Creator } from 'model/creator.model'; import { Dataset } from 'model/dataset.model'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; import {getFormValues} from 'redux-form'; -import { DATASET_CREATOR_FORM} from 'constants/datasets'; -import * as _ from 'lodash'; +import { DATASET_CREATOR_FORM} from 'datasets/constants'; interface ICreatorsStepProps extends React.ClassAttributes { dataset: Dataset; @@ -69,7 +69,7 @@ class CreatorsStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/files/FilesForm.tsx b/src/datasets/ui/dataset-stepper/steps/files/FilesForm.tsx similarity index 98% rename from src/ui/pages/dataset/dataset-stepper/steps/files/FilesForm.tsx rename to src/datasets/ui/dataset-stepper/steps/files/FilesForm.tsx index 16945c0..37c0ed6 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/files/FilesForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/files/FilesForm.tsx @@ -5,7 +5,7 @@ import * as _ from 'lodash'; import Grid from '@material-ui/core/Grid'; import Button from '@material-ui/core/Button'; -import {FILES_FORM} from 'constants/datasets'; +import {FILES_FORM} from 'datasets/constants'; import ItemsEditor from 'ui/common/ItemsEditor'; import {TextField} from 'ui/common/text-field'; diff --git a/src/ui/pages/dataset/dataset-stepper/steps/files/index.tsx b/src/datasets/ui/dataset-stepper/steps/files/index.tsx similarity index 93% rename from src/ui/pages/dataset/dataset-stepper/steps/files/index.tsx rename to src/datasets/ui/dataset-stepper/steps/files/index.tsx index 4531bb2..5c60502 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/files/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/files/index.tsx @@ -4,11 +4,11 @@ import {connect} from 'react-redux'; import {Dataset} from 'model/dataset.model'; -import {uploadRepositoryFileRequest, updateRepositoryFileRequest, deleteRepositoryFileRequest} from 'actions/dataset'; +import {uploadRepositoryFileRequest, updateRepositoryFileRequest, deleteRepositoryFileRequest} from 'datasets/actions/editor'; import FilesForm from './FilesForm'; import {RepositoryFile} from 'model/repositoryFile.model'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; interface IFilesStepProps extends React.ClassAttributes { @@ -50,7 +50,7 @@ class FilesStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/location/FormMap.tsx b/src/datasets/ui/dataset-stepper/steps/location/FormMap.tsx similarity index 100% rename from src/ui/pages/dataset/dataset-stepper/steps/location/FormMap.tsx rename to src/datasets/ui/dataset-stepper/steps/location/FormMap.tsx diff --git a/src/ui/pages/dataset/dataset-stepper/steps/location/LocationForm.tsx b/src/datasets/ui/dataset-stepper/steps/location/LocationForm.tsx similarity index 99% rename from src/ui/pages/dataset/dataset-stepper/steps/location/LocationForm.tsx rename to src/datasets/ui/dataset-stepper/steps/location/LocationForm.tsx index f532cc0..11a60c3 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/location/LocationForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/location/LocationForm.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import {Field, Fields, FieldArray, reduxForm} from 'redux-form'; import Button from '@material-ui/core/Button'; -import {LOCATION_FORM} from 'constants/datasets'; +import {LOCATION_FORM} from 'datasets/constants'; import MaterialAutosuggest from 'ui/common/material-autosuggest'; import {TextField} from 'ui/common/text-field'; diff --git a/src/ui/pages/dataset/dataset-stepper/steps/location/index.tsx b/src/datasets/ui/dataset-stepper/steps/location/index.tsx similarity index 94% rename from src/ui/pages/dataset/dataset-stepper/steps/location/index.tsx rename to src/datasets/ui/dataset-stepper/steps/location/index.tsx index de4bc26..f5a1633 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/location/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/location/index.tsx @@ -5,13 +5,13 @@ import {connect} from 'react-redux'; import {Location} from 'model/location.model'; import {Dataset} from 'model/dataset.model'; -import {createLocationRequest, deleteLocationRequest, updateLocationRequest} from 'actions/dataset'; +import {createLocationRequest, deleteLocationRequest, updateLocationRequest} from 'datasets/actions/editor'; import LocationForm from './LocationForm'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; import {getFormValues, change} from 'redux-form'; -import {LOCATION_FORM} from 'constants/datasets'; +import {LOCATION_FORM} from 'datasets/constants'; import * as _ from 'lodash'; interface ILocationStepProps extends React.ClassAttributes { @@ -76,7 +76,7 @@ class LocationStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/pasting-traits/index.tsx b/src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx similarity index 95% rename from src/ui/pages/dataset/dataset-stepper/steps/pasting-traits/index.tsx rename to src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx index 66321ae..74e5457 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/pasting-traits/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx @@ -6,10 +6,10 @@ import {Descriptor} from 'model/descriptor.model'; import Grid from '@material-ui/core/Grid'; import {log} from 'utilities/debug'; -import {addDescriptorsToDataset} from 'actions/dataset'; -import {searchMatchingDescriptor} from 'actions/descriptors'; +import {addDescriptorsToDataset} from 'datasets/actions/editor'; +import {searchMatchingDescriptor} from 'descriptors/actions/editor'; import DescriptorParser from 'ui/catalog/descriptor/DescriptorParser'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; import {Dataset} from 'model/dataset.model'; @@ -110,7 +110,7 @@ class PastingDescriptorsStep extends React.Component ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/reorder/index.tsx b/src/datasets/ui/dataset-stepper/steps/reorder/index.tsx similarity index 93% rename from src/ui/pages/dataset/dataset-stepper/steps/reorder/index.tsx rename to src/datasets/ui/dataset-stepper/steps/reorder/index.tsx index 3afc109..6fe571b 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/reorder/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/reorder/index.tsx @@ -4,10 +4,10 @@ import {connect} from 'react-redux'; import * as _ from 'lodash'; import {log} from 'utilities/debug'; -import {setDescriptorsToDatasetRequest} from 'actions/dataset'; +import {setDescriptorsToDatasetRequest} from 'datasets/actions/editor'; import DescriptorOrder from 'ui/common/reorderable/DescriptorOrder'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; import {Dataset} from 'model/dataset.model'; @@ -58,7 +58,7 @@ class ReorderTraitsStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/review/index.tsx b/src/datasets/ui/dataset-stepper/steps/review/index.tsx similarity index 88% rename from src/ui/pages/dataset/dataset-stepper/steps/review/index.tsx rename to src/datasets/ui/dataset-stepper/steps/review/index.tsx index a26c9ff..1c15f9c 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/review/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/review/index.tsx @@ -2,8 +2,8 @@ import * as React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import DatasetDisplay from 'ui/pages/dataset/c/DatasetDisplay'; -import steps from '../../steps'; +import DatasetDisplay from 'datasets/ui/c/DatasetDisplay'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; class ReviewAndPublishStep extends React.Component { @@ -27,7 +27,7 @@ class ReviewAndPublishStep extends React.Component { } } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, + dataset: state.datasets.dashboard.dataset, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/dataset/dataset-stepper/steps/traits/index.tsx b/src/datasets/ui/dataset-stepper/steps/traits/index.tsx similarity index 83% rename from src/ui/pages/dataset/dataset-stepper/steps/traits/index.tsx rename to src/datasets/ui/dataset-stepper/steps/traits/index.tsx index ca5d9cc..32932cf 100644 --- a/src/ui/pages/dataset/dataset-stepper/steps/traits/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/traits/index.tsx @@ -5,26 +5,26 @@ import {bindActionCreators} from 'redux'; import {log} from 'utilities/debug'; import { parse } from 'query-string'; -import {loadDescriptors} from 'actions/descriptors'; -import {addDescriptorsToDataset, removeDescriptorsFromDataset} from 'actions/dataset'; +import {listMyDescriptors as listMatchingDescriptors} from 'descriptors/actions/dashboard'; +import {addDescriptorsToDataset, removeDescriptorsFromDataset} from 'datasets/actions/editor'; import {Descriptor, IDescriptorFilter} from 'model/descriptor.model'; import DescriptorPicker from 'ui/catalog/descriptor/DescriptorPicker'; import {listCrops} from 'actions/crop'; import {Pagination} from 'model/common.model'; -import steps from '../../steps'; +import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; class Traits extends React.Component { protected static needs = [ - ({ search }) => loadDescriptors(parse(search).p, parse(search).l, parse(search).s, {}, parse(search).d), + ({ search }) => listMatchingDescriptors(parse(search).p, parse(search).l, parse(search).s, {}, parse(search).d), ]; public componentDidMount() { - const { appMounted, loadDescriptors } = this.props; + const { appMounted, listMatchingDescriptors } = this.props; if (appMounted) { - loadDescriptors(); + listMatchingDescriptors(); } } @@ -80,7 +80,7 @@ class Traits extends React.Component { } public render() { - const { matchingDescriptors, loadDescriptors, dataset, history, location, listCrops, pagination} = this.props; + const { matchingDescriptors, listMatchingDescriptors, dataset, history, location, listCrops, pagination} = this.props; const { stillLoading, onDelete, onPublish } = this.props; return ( @@ -88,7 +88,7 @@ class Traits extends React.Component { disabled={ false } steps={ steps } gotoStep={ this.gotoStep } onDelete={ onDelete } onPublish={ onPublish }> { } const mapStateToProps = (state, ownProps) => ({ - dataset: state.datasets.currentDataset, - matchingDescriptors: state.descriptors.paged, + dataset: state.datasets.dashboard.dataset, + matchingDescriptors: state.descriptors.dashboard.paged, pagination: new Pagination({ page: +parse(ownProps.location.search).p || 0, // current page size: +parse(ownProps.location.search).l || 20, // page size sort: parse(ownProps.location.search).s, // page sorts dir: parse(ownProps.location.search).d, // page sort directions - filter: state.descriptors.pagedQuery && state.descriptors.pagedQuery.filter || null, + filter: state.descriptors.dashboard.pagedQuery && state.descriptors.dashboard.pagedQuery.filter || null, }), stillLoading: ownProps.stillLoading, location: ownProps.location, @@ -124,7 +124,7 @@ const mapStateToProps = (state, ownProps) => ({ }); const mapDispatchToProps = (dispatch) => bindActionCreators({ - loadDescriptors, + listMatchingDescriptors, addDescriptorsToDataset, removeDescriptorsFromDataset, listCrops, diff --git a/src/ui/pages/search/SuggestionsPage.tsx b/src/datasets/ui/search/SuggestionsPage.tsx similarity index 98% rename from src/ui/pages/search/SuggestionsPage.tsx rename to src/datasets/ui/search/SuggestionsPage.tsx index ed857ae..9093ceb 100644 --- a/src/ui/pages/search/SuggestionsPage.tsx +++ b/src/datasets/ui/search/SuggestionsPage.tsx @@ -7,7 +7,7 @@ import { withStyles } from '@material-ui/core/styles'; import { parse } from 'query-string'; import { navigateTo } from 'actions/navigation'; import { datasetSuggestions } from 'actions/search'; -import { promiselistDatasets } from 'actions/dataset'; +import { promiselistDatasets } from 'datasets/actions/public'; import { IDatasetFilter } from 'model/dataset.model'; // import {Page} from 'model/common.model'; diff --git a/src/ui/pages/search/c/SearchHit.tsx b/src/datasets/ui/search/c/SearchHit.tsx similarity index 100% rename from src/ui/pages/search/c/SearchHit.tsx rename to src/datasets/ui/search/c/SearchHit.tsx diff --git a/src/ui/pages/search/c/SuggestionsForm.tsx b/src/datasets/ui/search/c/SuggestionsForm.tsx similarity index 100% rename from src/ui/pages/search/c/SuggestionsForm.tsx rename to src/datasets/ui/search/c/SuggestionsForm.tsx diff --git a/src/ui/pages/search/c/hits/Crop.tsx b/src/datasets/ui/search/c/hits/Crop.tsx similarity index 100% rename from src/ui/pages/search/c/hits/Crop.tsx rename to src/datasets/ui/search/c/hits/Crop.tsx diff --git a/src/ui/pages/search/c/hits/Dataset.tsx b/src/datasets/ui/search/c/hits/Dataset.tsx similarity index 100% rename from src/ui/pages/search/c/hits/Dataset.tsx rename to src/datasets/ui/search/c/hits/Dataset.tsx diff --git a/src/ui/pages/search/c/hits/Descriptor.tsx b/src/datasets/ui/search/c/hits/Descriptor.tsx similarity index 100% rename from src/ui/pages/search/c/hits/Descriptor.tsx rename to src/datasets/ui/search/c/hits/Descriptor.tsx diff --git a/src/ui/pages/search/c/hits/Partner.tsx b/src/datasets/ui/search/c/hits/Partner.tsx similarity index 100% rename from src/ui/pages/search/c/hits/Partner.tsx rename to src/datasets/ui/search/c/hits/Partner.tsx diff --git a/src/ui/pages/search/c/hits/_Generic.tsx b/src/datasets/ui/search/c/hits/_Generic.tsx similarity index 100% rename from src/ui/pages/search/c/hits/_Generic.tsx rename to src/datasets/ui/search/c/hits/_Generic.tsx diff --git a/src/descriptorlists/actions/dashboard.ts b/src/descriptorlists/actions/dashboard.ts new file mode 100644 index 0000000..59b97ea --- /dev/null +++ b/src/descriptorlists/actions/dashboard.ts @@ -0,0 +1,116 @@ +import { push } from 'react-router-redux'; + +// Actions +import {loadDescriptorListTitles} from 'actions/uuidDecoder'; +import {addFilterCode} from 'actions/filterCode'; + +// Constants +import {CREATE_DESCRIPTORLIST, DASHBOARD_APPEND_DESCRIPTORLISTS, DASHBOARD_LIST_DESCRIPTORLISTS, RECEIVE_DESCRIPTORLIST, DASHBOARD_RECEIVE_DESCRIPTORLISTS, DASHBOARD_REMOVE_DESCRIPTORLIST} from 'descriptors/constants'; + +// Model +import {PublishState, Page} from 'model/common.model'; +import {DescriptorList, IDescriptorListFilter} from 'model/descriptor.model'; + +// Service +import {DescriptorListService} from 'service/DescriptorListService'; + +// Util +import {log} from 'utilities/debug'; + + +const receiveDescriptorLists = (paged: Page, page, results, sortBy, filter: string | IDescriptorListFilter, order) => ({ + type: DASHBOARD_RECEIVE_DESCRIPTORLISTS, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const appendDescriptorLists = (paged: Page, page, results, sortBy, filter: string | IDescriptorListFilter, order) => ({ + type: DASHBOARD_APPEND_DESCRIPTORLISTS, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const loadingDescriptorLists = (page, results, sortBy, filter, order) => ({ + type: DASHBOARD_LIST_DESCRIPTORLISTS, + payload: { page, results, sortBy, filter, order }, +}); + +const removeDescriptorList = (descriptorList: DescriptorList) => ({ + type: DASHBOARD_REMOVE_DESCRIPTORLIST, + payload: descriptorList, +}); + +const receiveDescriptorList = (descriptorList: DescriptorList) => ({ + type: RECEIVE_DESCRIPTORLIST, + payload: descriptorList, +}); + +export const listMyDescriptorLists = (page?, results?, sortBy?, filter?: string | IDescriptorListFilter, order?) => (dispatch, getState) => { + log('Loading my descriptor lists'); + const token = getState().login.access_token; + + dispatch(loadingDescriptorLists(page, results, sortBy, filter, order)); + + return DescriptorListService.listMyDescriptorLists(token, page, results, sortBy, filter, order) + // receive the current descriptor list + .then((descriptorLists) => { + if (descriptorLists.number === 0) { + dispatch(receiveDescriptorLists(descriptorLists, page, results, sortBy, descriptorLists.filter, order)); + } else { + dispatch(appendDescriptorLists(descriptorLists, page, results, sortBy, descriptorLists.filter, order)); + } + dispatch(loadDescriptorListTitles(descriptorLists.content)); + return dispatch(addFilterCode(descriptorLists.filterCode, descriptorLists.filter)); + }).catch((error) => { + log(`Error loading my descriptor lists`, error); + }); +}; + +// Create a new descriptor list +export const createDescriptorList = () => (dispatch) => { + dispatch({ type: CREATE_DESCRIPTORLIST }); + return dispatch(push(`/dashboard/descriptorlists/edit`)); +}; + + +const getOneFromStateByUUID = (uuid: string, state) => { + return state.descriptorList.dashboard.paged.content.find((descriptorList) => descriptorList.uuid === uuid); +}; + +export const deleteDescriptorList = (descriptorListUUID: string) => (dispatch, getState) => { + const descriptorList = getOneFromStateByUUID(descriptorListUUID, getState()); + return DescriptorListService.deleteDescriptorList(getState().login.access_token, descriptorList) + .then((descriptorList) => { + dispatch(removeDescriptorList(descriptorList)); + return descriptorList; + }); +}; + + +export const publishDescriptorList = (descriptorListUUID: string) => (dispatch, getState) => { + const descriptorList = getOneFromStateByUUID(descriptorListUUID, getState()); + return descriptorList.state === PublishState.DRAFT && + DescriptorListService.updatePublishState(getState().login.access_token, descriptorList, PublishState.REVIEWING) + .then((descriptorList) => dispatch(receiveDescriptorList(descriptorList))) + .catch((error) => { + log('Error', error); + }); +}; + +export const unpublishDescriptorList = (descriptorListUUID: string) => (dispatch, getState) => { + const descriptorList = getOneFromStateByUUID(descriptorListUUID, getState()); + return descriptorList.state !== PublishState.DRAFT && + DescriptorListService.updatePublishState(getState().login.access_token, descriptorList, PublishState.DRAFT) + .then((descriptorList) => dispatch(receiveDescriptorList(descriptorList))) + .catch((error) => { + log('Error', error); + }); +}; + +export const approveDescriptorList = (descriptorListUUID: string) => (dispatch, getState) => { + const descriptorList = getOneFromStateByUUID(descriptorListUUID, getState()); + return descriptorList.state === PublishState.REVIEWING && + DescriptorListService.updatePublishState(getState().login.access_token, descriptorList, PublishState.PUBLISHED) + .then((descriptorList) => dispatch(receiveDescriptorList(descriptorList))) + .catch((error) => { + log('Error', error); + }); +}; diff --git a/src/descriptorlists/actions/editor.ts b/src/descriptorlists/actions/editor.ts new file mode 100644 index 0000000..ea6d58d --- /dev/null +++ b/src/descriptorlists/actions/editor.ts @@ -0,0 +1,200 @@ +import { push } from 'react-router-redux'; +import * as _ from 'lodash'; + +// Actions +import {navigateTo} from 'actions/navigation'; + +// Constants +import {RECEIVE_DESCRIPTORLIST, DASHBOARD_REMOVE_DESCRIPTORLIST, DASHBOARD_GET_DESCRIPTORLIST} from 'descriptors/constants'; + +// Model +import {Descriptor, DescriptorList} from 'model/descriptor.model'; +import {PublishState} from 'model/common.model'; + +// Service +import {DescriptorListService} from 'service/DescriptorListService'; + +// Util +import {log} from 'utilities/debug'; + +// UI +import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; + + +const receiveDescriptorList = (descriptorList: DescriptorList) => ({ + type: RECEIVE_DESCRIPTORLIST, + payload: descriptorList, +}); + +// go to the published descriptor list page +function showDescriptorList(uuid: string) { + return (dispatch) => { + dispatch(push(`/descriptorlists/${uuid}`)); + }; +} + +const removeDescriptorList = (descriptorList: DescriptorList) => ({ + type: DASHBOARD_REMOVE_DESCRIPTORLIST, + payload: descriptorList, +}); + +// Review step +const deleteDescriptorList = (descriptorList: DescriptorList) => (dispatch, getState) => { + return DescriptorListService.deleteDescriptorList(getState().login.access_token, descriptorList) + .then((descriptorList) => { + // receive updates + dispatch(removeDescriptorList(descriptorList)); + }); +}; + +function rejectDescriptorList(descriptorList: DescriptorList, needToRedirect: boolean = true) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorListService.updatePublishState(token, descriptorList, PublishState.DRAFT) + .then((saved) => { + dispatch(receiveDescriptorList(saved)); + if (needToRedirect) { + dispatch(navigateTo(`/dashboard/descriptorlists/${saved.uuid}/edit`)); + } + }).catch((error) => { + log('Error', error); + }); + }; +} + +function publishDescriptorList(descriptorList: DescriptorList, needToRedirect: boolean = false) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorListService.updatePublishState(token, descriptorList, PublishState.REVIEWING) + .then((saved) => { + dispatch(receiveDescriptorList(saved)); + if (needToRedirect) { + dispatch(showDescriptorList(saved.uuid)); + } + }).catch((error) => { + log('Error', error); + }); + }; +} + +function approveDescriptorList(descriptorList: DescriptorList) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorListService.updatePublishState(token, descriptorList, PublishState.PUBLISHED) + .then((saved) => { + dispatch(receiveDescriptorList(saved)); + }).catch((error) => { + log('Error', error); + }); + }; +} + +// Review step exports +export {deleteDescriptorList, rejectDescriptorList, publishDescriptorList, approveDescriptorList}; + + +// Descriptors step +// Add a descriptor to the descriptor list +const addDescriptorToDescriptorList = (descriptorList: DescriptorList, descriptor: Descriptor) => (dispatch, getState) => { + return DescriptorListService.addDescriptor(getState().login.access_token, descriptorList, [ descriptor.uuid ]) + .then((descriptorList) => { + // receive updates + dispatch(receiveDescriptorList(descriptorList)); + }); +}; + +// Add a descriptor to the descriptor list +const addDescriptorsToDescriptorList = (descriptorList: DescriptorList, descriptorUuids: string[]) => (dispatch, getState) => { + return DescriptorListService.addDescriptor(getState().login.access_token, descriptorList, descriptorUuids) + .then((descriptorList) => { + // receive updates + dispatch(receiveDescriptorList(descriptorList)); + }); +}; + +// Add a descriptor to the descriptor list +const setDescriptorsToDescriptorList = (descriptorList: DescriptorList, descriptorUuids: string[]) => (dispatch, getState) => { + return DescriptorListService.setDescriptors(getState().login.access_token, descriptorList, descriptorUuids) + .then((descriptorList) => { + // receive updates + dispatch(receiveDescriptorList(descriptorList)); + }); +}; + +// Remove a descriptor to the descriptor list +const removeDescriptorFromDescriptorList = (descriptorList: DescriptorList, descriptor: Descriptor) => (dispatch, getState) => { + return DescriptorListService.removeDescriptor(getState().login.access_token, descriptorList, [ descriptor.uuid ]) + .then((descriptorList) => { + // receive updates + dispatch(receiveDescriptorList(descriptorList)); + }); +}; + +// Remove a list of descriptors from the descriptor list +const removeDescriptorsFromDescriptorList = (descriptorList: DescriptorList, descriptorUuids: string[]) => (dispatch, getState) => { + return DescriptorListService.removeDescriptor(getState().login.access_token, descriptorList, descriptorUuids) + .then((descriptorList) => { + // receive updates + dispatch(receiveDescriptorList(descriptorList)); + }); +}; + +// Descriptors step exports +export {addDescriptorsToDescriptorList, addDescriptorToDescriptorList, setDescriptorsToDescriptorList, removeDescriptorFromDescriptorList, removeDescriptorsFromDescriptorList}; + +// Common actions +// Just load a descriptor list +const loadDescriptorList = (uuid: string, success?: (d) => any, fail?: (error) => any) => (dispatch, getState) => { + log('Loading descriptor list', uuid); + const token = getState().login.access_token; + + dispatch({ type: DASHBOARD_GET_DESCRIPTORLIST, payload: uuid }); + + return DescriptorListService.loadDescriptorList(token, uuid) + // receive the current descriptor list + // // Demo long load + // .then((descriptorList) => { + // await setTimeout(() => dispatch(receiveDescriptorList(descriptorList)), 10000); + .then((descriptorList) => { + if (success) { + return success(descriptorList); + } + dispatch(receiveDescriptorList(descriptorList)); + }).catch((error) => { + log(`No descriptor list with uuid ${uuid}`, error); + if (fail) { + return fail(error); + } + }); +}; + +const saveDescriptorList = (descriptorList: DescriptorList) => (dispatch, getState) => { + + const needToRedirect: boolean = !(descriptorList.version && descriptorList.uuid); + + if (_.isEqual({...getState().descriptorList.descriptorList}, {...descriptorList})) { + return; + } + + log('Saving descriptor list', descriptorList); + const createOrSave = descriptorList.version ? DescriptorListService.updateDescriptorList : DescriptorListService.createDescriptorList; + + return createOrSave(getState().login.access_token, descriptorList) + // when response is back + .then((saved) => { + // receive the updated descriptor list + dispatch(receiveDescriptorList(saved)); + if (needToRedirect) { + const path = steps.find((e) => e.id === 2).path; + dispatch(navigateTo(`/dashboard/descriptorlists/${saved.uuid}/${path}`)); + } + }).catch((error) => { + log(`Error saving descriptor list`, error, descriptorList); + }); +}; + +// Common actions exports +export {saveDescriptorList, loadDescriptorList}; diff --git a/src/descriptorlists/actions/public.ts b/src/descriptorlists/actions/public.ts new file mode 100644 index 0000000..4bc7e5b --- /dev/null +++ b/src/descriptorlists/actions/public.ts @@ -0,0 +1,113 @@ +// Actions +import { addFilterCode } from 'actions/filterCode'; +import {loadDescriptorListTitles} from 'actions/uuidDecoder'; + +// Constants +import { + GET_DESCRIPTORLIST, RECEIVE_DESCRIPTORLIST, + LIST_DESCRIPTORLISTS, RECEIVE_DESCRIPTORLISTS, APPEND_DESCRIPTORLISTS, +} from 'descriptors/constants'; + +// Model +import { DescriptorList, IDescriptorListFilter } from 'model/descriptor.model'; +import { Page } from 'model/common.model'; + +// Service +import { DescriptorListService } from 'service/DescriptorListService'; + +// Util +import {log} from 'utilities/debug'; + + +const receiveDescriptorList = (descriptorList: DescriptorList) => ({ + type: RECEIVE_DESCRIPTORLIST, + payload: descriptorList, +}); + + +const receiveDescriptorLists = (paged: Page, page, results, sortBy, filter: string | IDescriptorListFilter, order) => ({ + type: RECEIVE_DESCRIPTORLISTS, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const appendDescriptorLists = (paged: Page, page, results, sortBy, filter: string | IDescriptorListFilter, order) => ({ + type: APPEND_DESCRIPTORLISTS, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const loadingDescriptorLists = (page, results, sortBy, filter, order) => ({ + type: LIST_DESCRIPTORLISTS, + payload: { page, results, sortBy, filter, order }, +}); + + +// Just load a descriptor list +export const loadDescriptorList = (uuid: string, success?: (d) => any, fail?: (error) => any) => (dispatch, getState) => { + log('Loading descriptor list', uuid); + const token = getState().login.access_token; + + dispatch({ type: GET_DESCRIPTORLIST, payload: uuid }); + + return DescriptorListService.loadDescriptorList(token, uuid) + .then((descriptorList) => { + if (success) { + return success(descriptorList); + } + dispatch(receiveDescriptorList(descriptorList)); + }).catch((error) => { + log(`No descriptor list with uuid ${uuid}`, error); + if (fail) { + return fail(error); + } + }); +}; + +export const promiseDescriptorList = (uuid) => (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorListService.loadDescriptorList(token, uuid) + .then((list) => { + dispatch(loadDescriptorListTitles([list])); + return list; + }) + .catch((error) => { + log('Error', error); + return error; + }); +}; + +export const autocomplete = (term: string = '') => (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorListService.autocomplete(token, term) + .then((lists) => { + dispatch(loadDescriptorListTitles(lists)); + return lists; + }) + .catch((error) => { + log('Error', error); + }); +}; + +// List published descriptor lists +export const listDescriptorLists = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { + log('Loading published descriptor lists'); + const token = getState().login.access_token; + + dispatch(loadingDescriptorLists(page, results, sortBy, filter, order)); + + return DescriptorListService.listDescriptorLists(token, page, results, sortBy, filter, order) + // receive the current descriptor list + .then((paged) => { + if (paged.number === 0) { + dispatch(receiveDescriptorLists(paged, page, results, sortBy, paged.filter, order)); + } else { + dispatch(appendDescriptorLists(paged, page, results, sortBy, paged.filter, order)); + } + dispatch(loadDescriptorListTitles(paged.content)); + return dispatch(addFilterCode(paged.filterCode, paged.filter)); + }).catch((error) => { + log(`Error loading published descriptor lists`, error); + }); +}; + diff --git a/src/descriptorlists/reducers/dashboard.ts b/src/descriptorlists/reducers/dashboard.ts new file mode 100644 index 0000000..4222d88 --- /dev/null +++ b/src/descriptorlists/reducers/dashboard.ts @@ -0,0 +1,126 @@ +import update from 'immutability-helper'; +import * as _ from 'lodash'; + +import { DescriptorList } from 'model/descriptor.model'; +import { Page } from 'model/common.model'; + +import { + DASHBOARD_GET_DESCRIPTORLIST, + CREATE_DESCRIPTORLIST, + DASHBOARD_REMOVE_DESCRIPTORLIST, + RECEIVE_DESCRIPTORLIST, + DASHBOARD_RECEIVE_DESCRIPTORLISTS, + DASHBOARD_LIST_DESCRIPTORLISTS, + DASHBOARD_APPEND_DESCRIPTORLISTS, +} from 'descriptors/constants'; +import { LOGIN_USER, LOGIN_APP, LOGOUT } from 'constants/login'; + +const INITIAL_STATE: { + descriptorList: DescriptorList; + paged: Page; + pagedQuery: any; + loading: boolean; +} = { + descriptorList: null, + paged: null, + pagedQuery: null, + loading: null, +}; + +function descriptorListsDashboard(state = INITIAL_STATE, action: { type: string, payload?: any } = { type: '' }) { + + switch (action.type) { + case LOGIN_USER: + case LOGIN_APP: + case LOGOUT: { + return update(state, { $set: INITIAL_STATE }); + } + + case DASHBOARD_GET_DESCRIPTORLIST: { + return update(state, { + loading: { $set: { uuid: action.payload } }, + }); + } + + case DASHBOARD_LIST_DESCRIPTORLISTS: { + return update(state, { + loading: { $set: { uuid: null, ...action.payload } }, + }); + } + + // set the currentDescriptorList to whatever came in + case RECEIVE_DESCRIPTORLIST: { + const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; + + if (receivedIndex !== -1) { + return update(state, { + descriptorList: { $set: action.payload }, + loading: { $set: null }, + paged: { + content: { + [receivedIndex]: {$set: action.payload}, + }, + }, + }); + } else { + return update(state, { + descriptorList: { $set: action.payload }, + loading: { $set: null }, + paged: {$set: null}, + }); + } + } + case DASHBOARD_REMOVE_DESCRIPTORLIST: { + if (state.paged) { + const removeIndex = _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid); + return removeIndex === -1 ? state + : update(state, { + paged: { + content: {$splice: [[removeIndex, 1]]}, + numberOfElements: {$set: state.paged.numberOfElements - 1}, + totalElements: {$set: state.paged.totalElements - 1}, + }, + }); + } + return state; + } + + // set the currentDescriptorList to a blank new object + case CREATE_DESCRIPTORLIST: { + return update(state, { + descriptorList: { $set: new DescriptorList() }, + }); + } + + // set the paged to whatever came in + case DASHBOARD_RECEIVE_DESCRIPTORLISTS: { + return update(state, { + loading: { $set: null }, + paged: { $set: action.payload.paged }, + pagedQuery: { $set: action.payload.query }, + }); + } + + case DASHBOARD_APPEND_DESCRIPTORLISTS: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } + + default: + return state; + } +} + +export default descriptorListsDashboard; diff --git a/src/descriptorlists/reducers/index.ts b/src/descriptorlists/reducers/index.ts new file mode 100644 index 0000000..f199df7 --- /dev/null +++ b/src/descriptorlists/reducers/index.ts @@ -0,0 +1,10 @@ +import { combineReducers } from 'redux'; +import dashboard from './dashboard'; +import descriptorListPublic from './public'; + +const rootReducer = combineReducers({ + dashboard, + public: descriptorListPublic, +}); + +export default rootReducer; diff --git a/src/reducers/descriptorList.ts b/src/descriptorlists/reducers/public.ts similarity index 74% rename from src/reducers/descriptorList.ts rename to src/descriptorlists/reducers/public.ts index 07229d1..7c8e2a8 100644 --- a/src/reducers/descriptorList.ts +++ b/src/descriptorlists/reducers/public.ts @@ -4,22 +4,22 @@ import * as _ from 'lodash'; import { DescriptorList } from 'model/descriptor.model'; import { Page } from 'model/common.model'; -import {GET_DESCRIPTORLIST, RECEIVE_DESCRIPTORLIST, CREATE_DESCRIPTORLIST, LIST_DESCRIPTORLISTS, RECEIVE_DESCRIPTORLISTS, REMOVE_DESCRIPTORLIST} from 'constants/descriptors'; +import {GET_DESCRIPTORLIST, RECEIVE_DESCRIPTORLIST, CREATE_DESCRIPTORLIST, LIST_DESCRIPTORLISTS, RECEIVE_DESCRIPTORLISTS, REMOVE_DESCRIPTORLIST, APPEND_DESCRIPTORLISTS} from 'descriptors/constants'; import { LOGIN_USER, LOGIN_APP, LOGOUT } from 'constants/login'; const INITIAL_STATE: { - currentDescriptorList: DescriptorList; + descriptorList: DescriptorList; paged: Page; pagedQuery: any; loading: boolean; } = { - currentDescriptorList: null, + descriptorList: null, paged: null, pagedQuery: null, loading: null, }; -function descriptorList(state = INITIAL_STATE, action: { type: string, payload?: any } = { type: '' }) { +function descriptorListsPublic(state = INITIAL_STATE, action: { type: string, payload?: any } = { type: '' }) { switch (action.type) { case LOGIN_USER: @@ -46,7 +46,7 @@ function descriptorList(state = INITIAL_STATE, action: { type: string, payload?: if (receivedIndex !== -1) { return update(state, { - currentDescriptorList: { $set: action.payload }, + descriptorList: { $set: action.payload }, loading: { $set: null }, paged: { content: { @@ -56,7 +56,7 @@ function descriptorList(state = INITIAL_STATE, action: { type: string, payload?: }); } else { return update(state, { - currentDescriptorList: { $set: action.payload }, + descriptorList: { $set: action.payload }, loading: { $set: null }, paged: {$set: null}, }); @@ -80,7 +80,7 @@ function descriptorList(state = INITIAL_STATE, action: { type: string, payload?: // set the currentDescriptorList to a blank new object case CREATE_DESCRIPTORLIST: { return update(state, { - currentDescriptorList: { $set: new DescriptorList() }, + descriptorList: { $set: new DescriptorList() }, }); } @@ -92,10 +92,26 @@ function descriptorList(state = INITIAL_STATE, action: { type: string, payload?: pagedQuery: { $set: action.payload.query }, }); } + case APPEND_DESCRIPTORLISTS: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } default: return state; } } -export default descriptorList; +export default descriptorListsPublic; diff --git a/src/descriptorlists/routes.ts b/src/descriptorlists/routes.ts new file mode 100644 index 0000000..728df52 --- /dev/null +++ b/src/descriptorlists/routes.ts @@ -0,0 +1,76 @@ + +import DescriptorListDisplayPage from 'descriptorlists/ui/DisplayPage'; +import DescriptorListBrowsePage from 'descriptorlists/ui/BrowsePage'; +import DescriptorListDashboardPage from 'descriptorlists/ui/DashboardPage'; + +import DescriptorListStepper from 'descriptorlists/ui/descriptorlist-stepper'; +import DescriptorListBasicStep from 'descriptorlists/ui/descriptorlist-stepper/steps/basic-info'; +import descriptorListSteps from 'descriptorlists/ui/descriptorlist-stepper/steps'; + +import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import Wrapper from 'ui/catalog/Wrapper'; + + + +const publicRoutes = [ + { + path: '/descriptorlists', + component: Wrapper, + extraProps: { + title: 'p.descriptorlists.title', + subtitle: 'p.descriptorlists.subtitle', + }, + routes: [ + { + path: '/:uuid', + component: DescriptorListDisplayPage, + exact: true, + }, + { + path: '/', + component: DescriptorListBrowsePage, + exact: true, + }, + ], + }, +]; + +const dashboardRoutes = [ + { + path: '/descriptorlists/edit', + component: DescriptorListStepper, + exact: true, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + extraProps: { + title: 'Descriptor list publisher', + }, + routes: [ + { + path: '/', + component: DescriptorListBasicStep, + exact: true, + }, + ], + }, + { + path: '/descriptorlists/:uuid/', + component: DescriptorListStepper, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + extraProps: { + title: 'Descriptor list publisher', + }, + routes: [ + ...descriptorListSteps, + ], + }, + { + path: '/descriptorlists', + component: DescriptorListDashboardPage, + auth: [ROLE_USER], + extraProps: { + title: 'My Dashboard', + }, + }, +]; + +export {publicRoutes as descriptorListPublicRoutes, dashboardRoutes as descriptorListDashboardRoutes}; diff --git a/src/ui/pages/descriptorlist/BrowsePage.tsx b/src/descriptorlists/ui/BrowsePage.tsx similarity index 86% rename from src/ui/pages/descriptorlist/BrowsePage.tsx rename to src/descriptorlists/ui/BrowsePage.tsx index 6241308..9831e5d 100644 --- a/src/ui/pages/descriptorlist/BrowsePage.tsx +++ b/src/descriptorlists/ui/BrowsePage.tsx @@ -6,7 +6,7 @@ import {log} from 'utilities/debug'; import { parse } from 'query-string'; import { filterCodeToUrl } from 'actions/filterCode'; -import { listDescriptorLists, promiseListDescriptorLists, listDescriptorListsByCode } from 'actions/descriptorList'; +import { listDescriptorLists } from 'descriptorlists/actions/public'; import { listCrops } from 'actions/crop'; import { Page, Pagination } from 'model/common.model'; @@ -32,8 +32,6 @@ interface IBrowsePageProps extends React.ClassAttributes { paged?: Page; loading: any; listDescriptorLists: any; - listDescriptorListsByCode: any; - promiseListDescriptorLists: any; listCrops: () => any; filterCodeToUrl: any; crop: any; @@ -45,21 +43,17 @@ interface IBrowsePageProps extends React.ClassAttributes { class BrowsePage extends React.Component { protected static needs = [ - ({search}) => listDescriptorListsByCode(parse(search).p, parse(search).l, parse(search).s, parse(search).filter, parse(search).d), + ({search}) => listDescriptorLists(parse(search).p, parse(search).l, parse(search).s, parse(search).filter, parse(search).d), ]; public componentWillMount() { - const {pagination, paged, listDescriptorLists, listCrops, listDescriptorListsByCode} = this.props; + const {pagination, paged, listDescriptorLists, listCrops} = this.props; log(`BrowsePage.componentWillMount...`, this.props); if (! paged || paged.filterCode !== pagination.filterCode) { log('Loading descriptor lists'); - if (pagination.filterCode) { - listDescriptorListsByCode(pagination.page, pagination.size, pagination.sort, pagination.filterCode, pagination.dir); - } else { - listDescriptorLists(pagination.page, pagination.size, pagination.sort, {}, pagination.dir); - } + listDescriptorLists(pagination.page, pagination.size, pagination.sort, pagination.filter || pagination.filterCode, pagination.dir); } listCrops(); } @@ -110,8 +104,8 @@ class BrowsePage extends React.Component { } protected loadNextPage = (page: number, pageSize: number) => { - const {promiseListDescriptorLists, pagination} = this.props; - return promiseListDescriptorLists(page, pageSize, pagination.sort, pagination.filter, pagination.dir); + const {listDescriptorLists, pagination} = this.props; + return listDescriptorLists(page, pageSize, pagination.sort, pagination.filter, pagination.dir); } protected renderDescriptorList = (d: DescriptorList) => ( @@ -186,15 +180,13 @@ const mapStateToProps = (state, ownProps) => ({ filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, filterCode: parse(ownProps.location.search).filter, }), - paged: state.descriptorList.paged, + paged: state.descriptorList.public.paged, loading: state.descriptorList.loading, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ listDescriptorLists, listCrops, - promiseListDescriptorLists, - listDescriptorListsByCode, filterCodeToUrl, }, dispatch); diff --git a/src/descriptorlists/ui/DashboardPage.tsx b/src/descriptorlists/ui/DashboardPage.tsx new file mode 100644 index 0000000..7cba81b --- /dev/null +++ b/src/descriptorlists/ui/DashboardPage.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import { parse } from 'query-string'; + +import BaseMyDataPage from 'ui/catalog/dashboard/MyDataPage'; +import {listMyDescriptorLists, approveDescriptorList, deleteDescriptorList, unpublishDescriptorList, publishDescriptorList} from 'descriptorlists/actions/dashboard'; +import {DescriptorListLink} from 'ui/catalog/Links'; +import {PublishState} from 'model/common.model'; + +const renderDataLink = ({row, children}) => ({ children }); + +class DashboardPage extends BaseMyDataPage { + protected static needs = [ + ({ search }) => { + const pageCurrent = parse(search).p || 0; + const pageSize = parse(search).l || 100; + const pageSort = parse(search).s; + const pageDir = parse(search).d; + const filterCode = parse(search).filter; + + return listMyDescriptorLists(pageCurrent, pageSize, pageSort, filterCode || {}, pageDir); + }, + ]; +} + +const mapStateToProps = (state, ownProps) => ({ + paged: state.descriptorList.dashboard.paged, + tab: 'descriptorlists', +}); + +const mapDispatchToProps = (dispatch) => bindActionCreators({ + listMyData: listMyDescriptorLists, + deleteOne: deleteDescriptorList, + publishOne: publishDescriptorList, + approveOne: approveDescriptorList, + unpublishOne: unpublishDescriptorList, + renderDataLink, +}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage); diff --git a/src/ui/pages/descriptorlist/DisplayPage.tsx b/src/descriptorlists/ui/DisplayPage.tsx similarity index 95% rename from src/ui/pages/descriptorlist/DisplayPage.tsx rename to src/descriptorlists/ui/DisplayPage.tsx index 11a8eb8..b936a8f 100644 --- a/src/ui/pages/descriptorlist/DisplayPage.tsx +++ b/src/descriptorlists/ui/DisplayPage.tsx @@ -6,8 +6,8 @@ import { withStyles } from '@material-ui/core/styles'; import { loadDescriptorList, publishDescriptorList, approveDescriptorList, rejectDescriptorList, deleteDescriptorList, setDescriptorsToDescriptorList, -} from 'actions/descriptorList'; -import { copyDescriptor } from 'actions/descriptors'; +} from 'descriptorlists/actions/editor'; +import { copyDescriptor } from 'descriptors/actions/public'; import { DescriptorList} from 'model/descriptor.model'; import Loading from 'ui/common/Loading'; import ContentHeaderWithButton from 'ui/common/heading/ContentHeaderWithButton'; @@ -80,7 +80,7 @@ class DescriptorListPage extends React.Component const mapStateToProps = (state, { match }) => ({ uuid: match.params.uuid, - descriptorList: state.descriptorList.currentDescriptorList, + descriptorList: state.descriptorList.dashboard.descriptorList, loading: state.descriptorList.loading, }); diff --git a/src/ui/pages/descriptorlist/c/DescriptorListDisplay.tsx b/src/descriptorlists/ui/c/DescriptorListDisplay.tsx similarity index 100% rename from src/ui/pages/descriptorlist/c/DescriptorListDisplay.tsx rename to src/descriptorlists/ui/c/DescriptorListDisplay.tsx diff --git a/src/ui/pages/descriptorlist/c/DescriptorListForm.tsx b/src/descriptorlists/ui/c/DescriptorListForm.tsx similarity index 96% rename from src/ui/pages/descriptorlist/c/DescriptorListForm.tsx rename to src/descriptorlists/ui/c/DescriptorListForm.tsx index f8da5b3..43c9eb4 100644 --- a/src/ui/pages/descriptorlist/c/DescriptorListForm.tsx +++ b/src/descriptorlists/ui/c/DescriptorListForm.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import {Field, reduxForm} from 'redux-form'; -import { DESCRIPTORLIST_FORM } from 'constants/descriptors'; +import { DESCRIPTORLIST_FORM } from 'descriptors/constants'; import { TextField } from 'ui/common/text-field'; import { MarkdownField } from 'ui/catalog/markdown'; import Authorize from 'ui/common/authorized/Authorize'; import SelectPartner from 'ui/catalog/partner/SelectPartner'; import Validators from 'utilities/Validators'; -import remoteSubmit from 'ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/RemoteSubmit'; +import remoteSubmit from 'descriptorlists/ui/descriptorlist-stepper/steps/basic-info/RemoteSubmit'; import CropSelector from 'ui/catalog/crop/CropSelector'; class DescriptorListForm extends React.Component { diff --git a/src/ui/pages/descriptorlist/c/Extras.tsx b/src/descriptorlists/ui/c/Extras.tsx similarity index 100% rename from src/ui/pages/descriptorlist/c/Extras.tsx rename to src/descriptorlists/ui/c/Extras.tsx diff --git a/src/ui/pages/descriptorlist/c/Filters.tsx b/src/descriptorlists/ui/c/Filters.tsx similarity index 96% rename from src/ui/pages/descriptorlist/c/Filters.tsx rename to src/descriptorlists/ui/c/Filters.tsx index b7a93e8..ffccb0b 100644 --- a/src/ui/pages/descriptorlist/c/Filters.tsx +++ b/src/descriptorlists/ui/c/Filters.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { reduxForm } from 'redux-form'; -import { DESCRIPTORLIST_FILTERFORM } from 'constants/descriptors'; +import { DESCRIPTORLIST_FILTERFORM } from 'descriptors/constants'; import FiltersBlock from 'ui/common/filter/FiltersBlock'; import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/index.tsx similarity index 91% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/index.tsx rename to src/descriptorlists/ui/descriptorlist-stepper/index.tsx index 1cfa7b8..0de73a3 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/index.tsx @@ -7,14 +7,14 @@ import { log } from 'utilities/debug'; import confirm from 'utilities/confirmAlert'; import { setPageTitle } from 'actions/pageTitle'; -import { loadDescriptorList, deleteDescriptorList, publishDescriptorList} from 'actions/descriptorList'; +import { loadDescriptorList, deleteDescriptorList, publishDescriptorList} from 'descriptorlists/actions/editor'; import { navigateTo } from 'actions/navigation'; import TopSection from 'ui/common/stepper/TopSection'; import BottomSection from 'ui/common/stepper/BottomSection'; import { DescriptorList } from 'model/descriptor.model'; import renderRoutes from 'ui/renderRoutes'; -import {loadMyPartners} from 'actions/partner'; +import {loadMyPartners} from 'partners/actions/dashboard'; import {Partner} from 'model/partner.model'; import steps from './steps'; @@ -65,9 +65,9 @@ class DescriptorListStepper extends React.Component { protected gotoStep = (id) => { const {descriptorList, uuid, navigateTo} = this.props; - const path = steps.find((e) => e.id === id).link; + const path = steps.find((e) => e.id === id).path; if (uuid || (descriptorList && descriptorList.uuid)) { - navigateTo(`/descriptorlists/${descriptorList ? descriptorList.uuid : uuid}/${path}`); + navigateTo(`/dashboard/descriptorlists/${descriptorList ? descriptorList.uuid : uuid}/${path}`); } else { // no navigation! } @@ -103,7 +103,7 @@ class DescriptorListStepper extends React.Component { } public render() { - const {uuid, pageTitle, descriptorList, route, match} = this.props; + const {uuid, descriptorList, pageTitle, route, match} = this.props; const stillLoading: boolean = (! descriptorList || (uuid && (descriptorList.uuid !== uuid))); return ( @@ -121,7 +121,7 @@ class DescriptorListStepper extends React.Component { const mapStateToProps = (state, ownProps) => ({ uuid: ownProps.match.params.uuid, pageTitle: ownProps.route.extraProps.title, // route-configured - descriptorList: state.descriptorList.currentDescriptorList, + descriptorList: state.descriptorList.dashboard.descriptorList, location: ownProps.location, }); diff --git a/src/descriptorlists/ui/descriptorlist-stepper/steps.ts b/src/descriptorlists/ui/descriptorlist-stepper/steps.ts new file mode 100644 index 0000000..1ec4cab --- /dev/null +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps.ts @@ -0,0 +1,46 @@ +import SelectDescriptorsStep from 'descriptorlists/ui/descriptorlist-stepper/steps/select'; +import ImportDescriptorsStep from 'descriptorlists/ui/descriptorlist-stepper/steps/import'; +import ReorderDescriptorsStep from 'descriptorlists/ui/descriptorlist-stepper/steps/reorder'; +import ReviewDescriptorListStep from 'descriptorlists/ui/descriptorlist-stepper/steps/review'; + +import DescriptorListBasicStep from 'descriptorlists/ui/descriptorlist-stepper/steps/basic-info'; + +const steps = [ + { + id: 1, + name: 'Basic information', + path: 'edit', + component: DescriptorListBasicStep, + exact: true, + }, + { + id: 2, + name: 'Select registered descriptors', + path: 'edit/select-descriptors', + component: ImportDescriptorsStep, + exact: true, + }, + { + id: 3, + name: 'Import descriptors', + path: 'edit/import-descriptors', + component: SelectDescriptorsStep, + exact: true, + }, + { + id: 4, + name: 'Reorder descriptors', + path: 'edit/reorder-descriptors', + component: ReorderDescriptorsStep, + exact: true, + }, + { + id: 5, + name: 'Review and publish', + path: 'edit/review-and-publish', + component: ReviewDescriptorListStep, + exact: true, + }, +]; + +export default steps; diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts b/src/descriptorlists/ui/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts similarity index 72% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts rename to src/descriptorlists/ui/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts index 316e892..23ee438 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/basic-info/RemoteSubmit.ts @@ -1,4 +1,4 @@ -import {saveDescriptorList} from 'actions/descriptorList'; +import {saveDescriptorList} from 'descriptorlists/actions/editor'; import {DescriptorList} from 'model/descriptor.model'; export default function remoteSubmit(values: DescriptorList, dispatch) { diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/basic-info/index.tsx similarity index 84% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/index.tsx rename to src/descriptorlists/ui/descriptorlist-stepper/steps/basic-info/index.tsx index e4c37b3..1b756ac 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/basic-info/index.tsx @@ -2,15 +2,15 @@ import * as React from 'react'; import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import DescriptorListForm from 'ui/pages/descriptorlist/c/DescriptorListForm'; +import DescriptorListForm from 'descriptorlists/ui/c/DescriptorListForm'; import {DescriptorList} from 'model/descriptor.model'; -import {loadDescriptorList, saveDescriptorList} from 'actions/descriptorList'; -import {loadMyPartners} from 'actions/partner'; +import {loadDescriptorList, saveDescriptorList} from 'descriptorlists/actions/editor'; +import {loadMyPartners} from 'partners/actions/dashboard'; import {Partner} from 'model/partner.model'; import {submit, isInvalid} from 'redux-form'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; -import {DESCRIPTORLIST_FORM} from 'constants/descriptors'; -import steps from '../../steps'; +import {DESCRIPTORLIST_FORM} from 'descriptors/constants'; +import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; interface IDescriptorListProps extends React.ClassAttributes { uuid: string; @@ -69,8 +69,8 @@ class BasicInfoStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - myPartners: state.partner.myPartners, - descriptorList: state.descriptorList.currentDescriptorList, + myPartners: state.partner.dashboard.myPartners, + descriptorList: state.descriptorList.dashboard.descriptorList, location: ownProps.location, onDelete: ownProps.onDelete, onPublish: ownProps.onPublish, diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/import/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx similarity index 95% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/steps/import/index.tsx rename to src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx index 393a6b3..43f66d7 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/import/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx @@ -6,10 +6,10 @@ import {log} from 'utilities/debug'; import {Descriptor, DescriptorList} from 'model/descriptor.model'; import Grid from '@material-ui/core/Grid'; -import {importDescriptor} from 'actions/descriptors'; -import {addDescriptorsToDescriptorList} from 'actions/descriptorList'; +import {importDescriptor} from 'descriptors/actions/editor'; +import {addDescriptorsToDescriptorList} from 'descriptorlists/actions/editor'; import DescriptorParser from 'ui/catalog/descriptor/DescriptorParser'; -import steps from '../../steps'; +import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; @@ -120,7 +120,7 @@ class ImportDescriptorsStep extends React.Component { } const mapStateToProps = (state, ownProps) => ({ - descriptorList: state.descriptorList.currentDescriptorList, + descriptorList: state.descriptorList.dashboard.descriptorList, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/reorder/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/reorder/index.tsx similarity index 93% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/steps/reorder/index.tsx rename to src/descriptorlists/ui/descriptorlist-stepper/steps/reorder/index.tsx index ae10cbd..e2a2060 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/reorder/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/reorder/index.tsx @@ -6,9 +6,9 @@ import * as _ from 'lodash'; import {log} from 'utilities/debug'; import {DescriptorList} from 'model/descriptor.model'; -import {loadDescriptorList, setDescriptorsToDescriptorList} from 'actions/descriptorList'; +import {loadDescriptorList, setDescriptorsToDescriptorList} from 'descriptorlists/actions/editor'; import DescriptorOrder from 'ui/common/reorderable/DescriptorOrder'; -import steps from '../../steps'; +import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; interface IDescriptorListProps extends React.ClassAttributes { @@ -59,7 +59,7 @@ class ReorderDescriptorsStep extends React.Component } const mapStateToProps = (state, ownProps) => ({ - descriptorList: state.descriptorList.currentDescriptorList, + descriptorList: state.descriptorList.dashboard.descriptorList, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/review/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/review/index.tsx similarity index 86% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/steps/review/index.tsx rename to src/descriptorlists/ui/descriptorlist-stepper/steps/review/index.tsx index fc3ea45..c0e560b 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/review/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/review/index.tsx @@ -2,10 +2,10 @@ import * as React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {publishDescriptorList} from 'actions/descriptorList'; +import {publishDescriptorList} from 'descriptorlists/actions/editor'; import {DescriptorList} from 'model/descriptor.model'; -import DescriptorListDisplay from 'ui/pages/descriptorlist/c/DescriptorListDisplay'; -import steps from '../../steps'; +import DescriptorListDisplay from 'descriptorlists/ui/c/DescriptorListDisplay'; +import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; interface IDescriptorListPageProps extends React.ClassAttributes { @@ -46,7 +46,7 @@ class ReviewDescriptorsStep extends React.Component ({ - descriptorList: state.descriptorList.currentDescriptorList, + descriptorList: state.descriptorList.dashboard.descriptorList, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/select/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx similarity index 84% rename from src/ui/pages/descriptorlist/descriptorlist-stepper/steps/select/index.tsx rename to src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx index 18a2c6d..943aa93 100644 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps/select/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx @@ -7,13 +7,14 @@ import {Descriptor, DescriptorList, IDescriptorFilter} from 'model/descriptor.mo import {listCrops} from 'actions/crop'; import DescriptorPicker from 'ui/catalog/descriptor/DescriptorPicker'; -import {loadDescriptors, importDescriptor} from 'actions/descriptors'; +import {importDescriptor} from 'descriptors/actions/editor'; +import {listMyDescriptors as listMatchingDescriptors} from 'descriptors/actions/dashboard'; import {Page, Pagination} from 'model/common.model'; import { loadDescriptorList, saveDescriptorList, addDescriptorsToDescriptorList, removeDescriptorsFromDescriptorList, - addDescriptorToDescriptorList, removeDescriptorFromDescriptorList} from 'actions/descriptorList'; + addDescriptorToDescriptorList, removeDescriptorFromDescriptorList} from 'descriptorlists/actions/editor'; import { parse } from 'query-string'; -import steps from '../../steps'; +import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; interface IDescriptorListProps extends React.ClassAttributes { @@ -27,7 +28,7 @@ interface IDescriptorListProps extends React.ClassAttributes { saveDescriptorList: any; importDescriptor: any; matchingDescriptors: Page; - loadDescriptors: (page?: number, results?: number, sortBy?: string, filter?: IDescriptorFilter, order?: string) => void; + listMatchingDescriptors: (page?: number, results?: number, sortBy?: string, filter?: IDescriptorFilter, order?: string) => void; addDescriptorToDescriptorList: any; addDescriptorsToDescriptorList: (descriptorList: DescriptorList, descriptorUuids: string[]) => void; removeDescriptorsFromDescriptorList: (descriptorList: DescriptorList, descriptorUuids: string[]) => void; @@ -42,7 +43,7 @@ interface IDescriptorListProps extends React.ClassAttributes { class SelectDescriptorsStep extends React.Component { protected static needs = [ - ({ search }) => loadDescriptors(parse(search).p, parse(search).l || 20, parse(search).s, {}, parse(search).d), + ({ search }) => listMatchingDescriptors(parse(search).p, parse(search).l || 20, parse(search).s, {}, parse(search).d), ]; protected gotoStep = (id) => () => { @@ -97,7 +98,7 @@ class SelectDescriptorsStep extends React.Component { } public render() { - const {loadDescriptors, descriptorList, pagination, matchingDescriptors, listCrops, history, location} = this.props; + const {listMatchingDescriptors, descriptorList, pagination, matchingDescriptors, listCrops, history, location} = this.props; const {stillLoading, onDelete, onPublish} = this.props; return ( @@ -105,7 +106,7 @@ class SelectDescriptorsStep extends React.Component { disabled={ false } steps={ steps } gotoStep={ this.gotoStep } onDelete={ onDelete } onPublish={ onPublish }> { } const mapStateToProps = (state, ownProps) => ({ - descriptorList: state.descriptorList.currentDescriptorList, - matchingDescriptors: state.descriptors.paged, + descriptorList: state.descriptorList.dashboard.descriptorList, + matchingDescriptors: state.descriptors.dashboard.paged, pagination: new Pagination({ page: +parse(ownProps.location.search).p || 0, // current page size: +parse(ownProps.location.search).l || 20, // page size sort: parse(ownProps.location.search).s, // page sorts dir: parse(ownProps.location.search).d, // page sort directions - filter: state.descriptors.pagedQuery && state.descriptors.pagedQuery.filter || null, + filter: state.descriptors.dashboard.pagedQuery && state.descriptors.dashboard.pagedQuery.filter || null, }), stillLoading: ownProps.stillLoading, location: ownProps.location, @@ -146,7 +147,7 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ importDescriptor, removeDescriptorFromDescriptorList, addDescriptorToDescriptorList, - loadDescriptors, + listMatchingDescriptors, listCrops, addDescriptorsToDescriptorList, removeDescriptorsFromDescriptorList, diff --git a/src/descriptors/actions/dashboard.ts b/src/descriptors/actions/dashboard.ts new file mode 100644 index 0000000..a30a5e4 --- /dev/null +++ b/src/descriptors/actions/dashboard.ts @@ -0,0 +1,118 @@ +import {push} from 'react-router-redux'; + +// Actions +import {addFilterCode} from 'actions/filterCode'; + +// Constants +import {DASHBOARD_RECEIVE_DESCRIPTOR_PAGE, DASHBOARD_REMOVE_DESCRIPTOR, DASHBOARD_LIST_DESCRIPTORS, CREATE_DESCRIPTOR, DASHBOARD_APPEND_DESCRIPTOR_PAGE, RECEIVE_DESCRIPTOR} from 'descriptors/constants'; + +// Model +import {Descriptor, IDescriptorFilter} from 'model/descriptor.model'; +import {Page, PublishState} from 'model/common.model'; +import {Partner} from 'model/partner.model'; + +// Service +import {DescriptorService} from 'service/DescriptorService'; + +// Util +import {log} from 'utilities/debug'; +import {dereferenceReferences} from 'utilities'; + +const appendDescriptorPage = (paged: Page, page, results, sortBy, filter: string | IDescriptorFilter, order) => ({ + type: DASHBOARD_APPEND_DESCRIPTOR_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const receiveDescriptorPage = (paged: Page, page, results, sortBy, filter: string | IDescriptorFilter, order) => ({ + type: DASHBOARD_RECEIVE_DESCRIPTOR_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const removeDescriptor = (descriptor: Descriptor) => ({ + type: DASHBOARD_REMOVE_DESCRIPTOR, + payload: descriptor, +}); +const receiveDescriptor = (descriptor: Descriptor) => ({ + type: RECEIVE_DESCRIPTOR, + payload: descriptor, +}); + +const loadingDescriptors = (page, results, sortBy, filter, order) => ({ + type: DASHBOARD_LIST_DESCRIPTORS, + payload: { page, results, sortBy, filter, order }, +}); + +// Create a new descriptor +export const createDescriptor = () => (dispatch) => { + dispatch({ type: CREATE_DESCRIPTOR }); + return dispatch(push(`/dashboard/descriptors/edit`)); +}; + +export function listMyDescriptors(page?, results?, sortBy?, filter?: string | IDescriptorFilter, order?) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + dispatch(loadingDescriptors(page, results, sortBy, filter, order)); + + return DescriptorService.listMyDescriptors(token, page, results, sortBy, filter, order) + .then((paged) => { + dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); + if (paged.number === 0) { + dispatch(receiveDescriptorPage(paged, page, results, sortBy, filter, order)); + } else { + dispatch(appendDescriptorPage(paged, page, results, sortBy, filter, order)); + } + return dispatch(addFilterCode(paged.filterCode, paged.filter)); + }) + .catch((error) => { + log('Error', error); + }); + }; +} + +// Dashboard actions section +const getOneFromStateByUUID = (uuid: string, state) => { + return state.descriptors.dashboard.paged.content.find((descriptorList) => descriptorList.uuid === uuid); +}; + +export const deleteDescriptor = (descriptorUUID: string) => (dispatch, getState) => { + const descriptor = getOneFromStateByUUID(descriptorUUID, getState()); + return DescriptorService.deleteDescriptor(getState().login.access_token, descriptor) + .then((descriptor) => { + dispatch(removeDescriptor(descriptor)); + return descriptor; + }) + .catch((error) => { + log('Error', error); + }); +}; + +export const publishDescriptor = (descriptorUUID: string) => (dispatch, getState) => { + const descriptor = getOneFromStateByUUID(descriptorUUID, getState()); + return descriptor.state === PublishState.DRAFT && + DescriptorService.updatePublishState(getState().login.access_token, descriptor, PublishState.REVIEWING) + .then((descriptor) => dispatch(receiveDescriptor(descriptor))) + .catch((error) => { + log('Error', error); + }); +}; + +export const unpublishDescriptor = (descriptorUUID: string) => (dispatch, getState) => { + const descriptor = getOneFromStateByUUID(descriptorUUID, getState()); + return descriptor.state !== PublishState.DRAFT && + DescriptorService.updatePublishState(getState().login.access_token, descriptor, PublishState.DRAFT) + .then((descriptor) => dispatch(receiveDescriptor(descriptor))) + .catch((error) => { + log('Error', error); + }); +}; + +export const approveDescriptor = (descriptorUUID: string) => (dispatch, getState) => { + const descriptor = getOneFromStateByUUID(descriptorUUID, getState()); + return descriptor.state === PublishState.REVIEWING && + DescriptorService.updatePublishState(getState().login.access_token, descriptor, PublishState.PUBLISHED) + .then((descriptor) => dispatch(receiveDescriptor(descriptor))) + .catch((error) => { + log('Error', error); + }); +}; diff --git a/src/descriptors/actions/editor.ts b/src/descriptors/actions/editor.ts new file mode 100644 index 0000000..0a5c634 --- /dev/null +++ b/src/descriptors/actions/editor.ts @@ -0,0 +1,156 @@ +import {push} from 'react-router-redux'; +import {SubmissionError} from 'redux-form'; + +// Actions +import {navigateTo} from 'actions/navigation'; + +// Constants +import {DASHBOARD_GET_DESCRIPTOR, RECEIVE_DESCRIPTOR, DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA, DASHBOARD_REMOVE_DESCRIPTOR} from 'descriptors/constants'; + +// Model +import {Descriptor} from 'model/descriptor.model'; +import {PublishState} from 'model/common.model'; + +// Service +import {DescriptorService} from 'service/DescriptorService'; + +// Util +import {log} from 'utilities/debug'; + +const receiveDescriptor = (descriptor: Descriptor) => ({ + type: RECEIVE_DESCRIPTOR, + payload: descriptor, +}); + +const receiveDescriptorExtra = (descriptor: Descriptor, extra: any) => ({ + type: DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA, + payload: { descriptor, extra }, +}); + +const removeDescriptor = (descriptor: Descriptor) => ({ + type: DASHBOARD_REMOVE_DESCRIPTOR, + payload: descriptor, +}); + +function showDescriptor(uuid: string) { + return (dispatch) => { + dispatch(push(`/descriptors/${uuid}`)); + }; +} + +export function approveDescriptor(descriptor: Descriptor) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorService.updatePublishState(token, descriptor, PublishState.PUBLISHED) + .then((saved) => { + dispatch(receiveDescriptor(saved)); + }).catch((error) => { + log('Error', error); + }); + }; +} + +// Delete a record +export const deleteDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { + return DescriptorService.deleteDescriptor(getState().login.access_token, descriptor) + .then((descriptor) => { + dispatch(removeDescriptor(descriptor)); + dispatch(push(`/descriptors`)); + }) + .catch((error) => { + log('Error', error); + }); +}; + +export function rejectDescriptor(descriptor: Descriptor, needToRedirect: boolean = true) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorService.updatePublishState(token, descriptor, PublishState.DRAFT) + .then((saved) => { + dispatch(receiveDescriptor(saved)); + if (needToRedirect) { + dispatch(navigateTo(`/dashboard/descriptors/${saved.uuid}/edit`)); + } + }).catch((error) => { + log('Error', error); + }); + }; +} + +export function publishDescriptor(descriptor: Descriptor, needToRedirect: boolean = false) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorService.updatePublishState(token, descriptor, PublishState.REVIEWING) + .then((saved) => { + dispatch(receiveDescriptor(saved)); + if (needToRedirect) { + dispatch(showDescriptor(saved.uuid)); + } + }).catch((error) => { + log('Error', error); + }); + }; +} + +export function loadDescriptor(uuid: string, success?: (d) => any, fail?: (error) => any) { + log('Loading descriptor', uuid); + return (dispatch, getState) => { + const token = getState().login.access_token; + + dispatch({ type: DASHBOARD_GET_DESCRIPTOR, payload: uuid }); + + return DescriptorService.loadDescriptor(token, uuid) + .then((loaded) => { + if (success) { + return success(loaded); + } + return DescriptorService.loadDescriptorExtra(token, uuid) + .then((extra) => { + dispatch(receiveDescriptorExtra(loaded, extra)); + return { loaded, extra }; + }); + }).catch((error) => { + log(`No descriptor with uuid ${uuid}`, error); + if (fail) { + return fail(error); + } + throw new SubmissionError({ title: 'Title already used', _error: error.error }); + }); + }; +} + +export const searchMatchingDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorService.searchMatchingDescriptor(token, descriptor) + .catch((error) => { + log('Error', error); + }); +}; + +// This method only saves the descriptor +export const importDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { + log('Importing descriptor', descriptor); + const createOrSave = descriptor.version && descriptor.uuid ? DescriptorService.updateDescriptor : DescriptorService.createDescriptor; + + return createOrSave(getState().login.access_token, descriptor); +}; + +export const saveDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { + log('Saving descriptor', descriptor); + const createOrSave = descriptor.version && descriptor.uuid ? DescriptorService.updateDescriptor : DescriptorService.createDescriptor; + + return createOrSave(getState().login.access_token, descriptor) + .then((descriptor) => { + // receive the updated descriptor + dispatch(receiveDescriptor(descriptor)); + // and redirect to proper edit page + return dispatch(push(`/dashboard/descriptors/${descriptor.uuid}/edit`)); + }).catch((error) => { + log('Save error', error); + throw new SubmissionError({ title: 'Could not save descriptor', _error: error.error }); + }); +}; diff --git a/src/descriptors/actions/public.ts b/src/descriptors/actions/public.ts new file mode 100644 index 0000000..ed36f12 --- /dev/null +++ b/src/descriptors/actions/public.ts @@ -0,0 +1,97 @@ +import {SubmissionError} from 'redux-form'; + +// Actions +import {addFilterCode} from 'actions/filterCode'; + +// Constants +import {RECEIVE_DESCRIPTOR_EXTRA, RECEIVE_DESCRIPTOR_PAGE, GET_DESCRIPTOR, LIST_DESCRIPTORS, APPEND_DESCRIPTOR_PAGE} from 'descriptors/constants'; + +// Model +import {Descriptor, IDescriptorFilter} from 'model/descriptor.model'; +import {Partner} from 'model/partner.model'; +import {Page} from 'model/common.model'; + +// Service +import {DescriptorService} from 'service/DescriptorService'; + +// Util +import {dereferenceReferences} from 'utilities'; +import {log} from 'utilities/debug'; + +const receiveDescriptorExtra = (descriptor: Descriptor, extra: any) => ({ + type: RECEIVE_DESCRIPTOR_EXTRA, + payload: { descriptor, extra }, +}); + +const appendDescriptorPage = (paged: Page, page, results, sortBy, filter: string | IDescriptorFilter, order) => ({ + type: APPEND_DESCRIPTOR_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const receiveDescriptorPage = (paged: Page, page, results, sortBy, filter: string | IDescriptorFilter, order) => ({ + type: RECEIVE_DESCRIPTOR_PAGE, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const loadingDescriptors = (page, results, sortBy, filter, order) => ({ + type: LIST_DESCRIPTORS, + payload: { page, results, sortBy, filter, order }, +}); + +export function loadDescriptor(uuid: string, success?: (d) => any, fail?: (error) => any) { + log('Loading descriptor', uuid); + return (dispatch, getState) => { + const token = getState().login.access_token; + + dispatch({ type: GET_DESCRIPTOR, payload: uuid }); + + return DescriptorService.loadDescriptor(token, uuid) + .then((loaded) => { + if (success) { + return success(loaded); + } + return DescriptorService.loadDescriptorExtra(token, uuid) + .then((extra) => { + dispatch(receiveDescriptorExtra(loaded, extra)); + return { loaded, extra }; + }); + }).catch((error) => { + log(`No descriptor with uuid ${uuid}`, error); + if (fail) { + return fail(error); + } + throw new SubmissionError({ title: 'Title already used', _error: error.error }); + }); + }; +} + + +export const copyDescriptor = (descriptor: Descriptor) => (dispatch, getState) => { + return DescriptorService.copyDescriptor(getState().login.access_token, descriptor) + .catch((error) => { + log('Save error', error); + throw new SubmissionError({ title: 'Could not save descriptor', _error: error.error }); + }); +}; + +export function loadDescriptors(page?, results?, sortBy?, filter?, order?) { + return (dispatch, getState) => { + const token = getState().login.access_token; + + dispatch(loadingDescriptors(page, results, sortBy, filter, order)); + + return DescriptorService.listDescriptors(token, page, results, sortBy, filter, order) + .then((paged) => { + dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); + if (paged.number === 0) { + dispatch(receiveDescriptorPage(paged, page, results, sortBy, filter, order)); + } else { + dispatch(appendDescriptorPage(paged, page, results, sortBy, filter, order)); + } + return dispatch(addFilterCode(paged.filterCode, paged.filter)); + }) + .catch((error) => { + log('Error', error); + }); + }; +} diff --git a/src/constants/descriptors.ts b/src/descriptors/constants.ts similarity index 58% rename from src/constants/descriptors.ts rename to src/descriptors/constants.ts index b657d22..c3ce20c 100644 --- a/src/constants/descriptors.ts +++ b/src/descriptors/constants.ts @@ -7,13 +7,29 @@ export const REMOVE_DESCRIPTOR = 'App/REMOVE_DESCRIPTOR'; export const RECEIVE_DESCRIPTOR_EXTRA = 'App/Descriptor/RECEIVE_DESCRIPTOR_EXTRA'; export const DESCRIPTOR_FORM = 'Form/DESCRIPTOR_FORM'; export const RECEIVE_DESCRIPTOR_PAGE = 'App/RECEIVE_DESCRIPTOR_PAGE'; +export const APPEND_DESCRIPTOR_PAGE = 'App/APPEND_DESCRIPTOR_PAGE'; export const GET_DESCRIPTOR = 'App/GET_DESCRIPTOR'; export const LIST_DESCRIPTORS = 'App/LIST_DESCRIPTORS'; +// Descriptors: dashboard +export const DASHBOARD_GET_DESCRIPTOR = 'descriptor/dashboard/GET_DESCRIPTOR'; +export const DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA = 'descriptor/dashboard/RECEIVE_DESCRIPTOR_EXTRA'; +export const DASHBOARD_REMOVE_DESCRIPTOR = 'descriptor/dashboard/REMOVE_DESCRIPTOR'; +export const DASHBOARD_RECEIVE_DESCRIPTOR_PAGE = 'descriptor/dashboard/RECEIVE_DESCRIPTOR_PAGE'; +export const DASHBOARD_APPEND_DESCRIPTOR_PAGE = 'descriptor/dashboard/APPEND_DESCRIPTOR_PAGE'; +export const DASHBOARD_LIST_DESCRIPTORS = 'descriptor/dashboard/LIST_DESCRIPTORS'; + // Descriptor lists export const GET_DESCRIPTORLIST = 'App/GET_DESCRIPTORLIST'; export const RECEIVE_DESCRIPTORLIST = 'App/RECEIVE_DESCRIPTORLIST'; +// Descriptor lists: dashboard +export const DASHBOARD_RECEIVE_DESCRIPTORLISTS = 'descriptorList/dashboard/RECEIVE_DESCRIPTORLISTS'; +export const DASHBOARD_APPEND_DESCRIPTORLISTS = 'descriptorList/dashboard/APPEND_DESCRIPTORLISTS'; +export const DASHBOARD_REMOVE_DESCRIPTORLIST = 'descriptorList/dashboard/REMOVE_DESCRIPTORLIST'; +export const DASHBOARD_LIST_DESCRIPTORLISTS = 'descriptorList/dashboard/LIST_DESCRIPTORLISTS'; +export const DASHBOARD_GET_DESCRIPTORLIST = 'descriptorList/dashboard/GET_DESCRIPTORLIST'; + export const CREATE_DESCRIPTORLIST = 'App/CREATE_DESCRIPTORLIST'; export const EDIT_DESCRIPTORLIST = 'App/EDIT_DESCRIPTORLIST'; export const DESCRIPTORLIST_FORM = 'Form/DESCRIPTORLIST'; @@ -26,6 +42,7 @@ export const DESCRIPTORLIST_FILTERFORM = 'Form/DESCRIPTORLIST_FILTERS'; export const LIST_DESCRIPTORLISTS = 'App/LIST_DESCRIPTORLISTS'; export const REMOVE_DESCRIPTORLIST = 'App/REMOVE_DESCRIPTORLIST'; export const RECEIVE_DESCRIPTORLISTS = 'App/RECEIVE_DESCRIPTORLISTS'; +export const APPEND_DESCRIPTORLISTS = 'App/APPEND_DESCRIPTORLISTS'; /* // Descriptor list actions diff --git a/src/descriptors/reducers/dashboard.ts b/src/descriptors/reducers/dashboard.ts new file mode 100644 index 0000000..d1372f4 --- /dev/null +++ b/src/descriptors/reducers/dashboard.ts @@ -0,0 +1,133 @@ +import update from 'immutability-helper'; +import * as _ from 'lodash'; +import { log } from 'utilities/debug'; + +import { IReducerAction, Page } from 'model/common.model'; +import { Descriptor } from 'model/descriptor.model'; + +import { + CREATE_DESCRIPTOR, + RECEIVE_DESCRIPTOR, + DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA, + DASHBOARD_RECEIVE_DESCRIPTOR_PAGE, + DASHBOARD_GET_DESCRIPTOR, + DASHBOARD_LIST_DESCRIPTORS, + DASHBOARD_REMOVE_DESCRIPTOR, + DASHBOARD_APPEND_DESCRIPTOR_PAGE, +} from 'descriptors/constants'; + + +const INITIAL_STATE: { + descriptor: Descriptor; + descriptorExtra: any; + paged: Page; + pagedQuery: any; + loading: boolean; +} = { + descriptor: null, + descriptorExtra: null, + paged: null, + pagedQuery: null, + loading: null, +}; + +function descriptorsDashboard(state = INITIAL_STATE, action: IReducerAction) { + + switch (action.type) { + case DASHBOARD_GET_DESCRIPTOR: { + return update(state, { + loading: { $set: { uuid: action.payload } }, + }); + } + + case DASHBOARD_LIST_DESCRIPTORS: { + return update(state, { + loading: { $set: { uuid: null, ...action.payload } }, + }); + } + + case CREATE_DESCRIPTOR: { + return update(state, { + descriptor: { $set: new Descriptor() }, + descriptorExtra: { $set: null }, + }); + } + + case RECEIVE_DESCRIPTOR: { + const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; + + if (receivedIndex !== -1) { + return update(state, { + descriptor: { $set: action.payload }, + descriptorExtra: { $set: null }, + loading: { $set: null }, + paged: { + content: { + [receivedIndex]: {$set: action.payload}, + }, + }, + }); + } else { + return update(state, { + descriptor: { $set: action.payload }, + descriptorExtra: { $set: null }, + loading: { $set: null }, + paged: {$set: null}, + }); + } + } + case DASHBOARD_REMOVE_DESCRIPTOR: { + if (state.paged) { + const removeIndex = _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid); + return removeIndex === -1 ? state + : update(state, { + paged: { + content: {$splice: [[removeIndex, 1]]}, + numberOfElements: {$set: state.paged.numberOfElements - 1}, + totalElements: {$set: state.paged.totalElements - 1}, + }, + }); + } + return state; + } + + case DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA: { + log(DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA, action); + return update(state, { + descriptor: { $set: action.payload.descriptor }, + descriptorExtra: { $set: action.payload.extra }, + loading: { $set: null }, + }); + } + + case DASHBOARD_RECEIVE_DESCRIPTOR_PAGE: { + return update(state, { + loading: { $set: null }, + paged: { $set: action.payload.paged }, + pagedQuery: { $set: _.cloneDeep(action.payload.query) }, + }); + } + + case DASHBOARD_APPEND_DESCRIPTOR_PAGE: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } + + default: + return state; + } +} + +export default descriptorsDashboard; diff --git a/src/descriptors/reducers/index.ts b/src/descriptors/reducers/index.ts new file mode 100644 index 0000000..519d44d --- /dev/null +++ b/src/descriptors/reducers/index.ts @@ -0,0 +1,10 @@ +import { combineReducers } from 'redux'; +import dashboard from './dashboard'; +import descriptorsPublic from './public'; + +const rootReducer = combineReducers({ + dashboard, + public: descriptorsPublic, +}); + +export default rootReducer; diff --git a/src/reducers/descriptors.ts b/src/descriptors/reducers/public.ts similarity index 56% rename from src/reducers/descriptors.ts rename to src/descriptors/reducers/public.ts index 7e9cebe..ed3a50c 100644 --- a/src/reducers/descriptors.ts +++ b/src/descriptors/reducers/public.ts @@ -5,24 +5,24 @@ import { log } from 'utilities/debug'; import { IReducerAction, Page } from 'model/common.model'; import { Descriptor } from 'model/descriptor.model'; -import {CREATE_DESCRIPTOR, RECEIVE_DESCRIPTOR, RECEIVE_DESCRIPTOR_EXTRA, RECEIVE_DESCRIPTOR_PAGE, GET_DESCRIPTOR, LIST_DESCRIPTORS, REMOVE_DESCRIPTOR} from 'constants/descriptors'; +import {RECEIVE_DESCRIPTOR, RECEIVE_DESCRIPTOR_EXTRA, RECEIVE_DESCRIPTOR_PAGE, GET_DESCRIPTOR, LIST_DESCRIPTORS, APPEND_DESCRIPTOR_PAGE} from 'descriptors/constants'; import { LOGIN_USER, LOGIN_APP, LOGOUT } from 'constants/login'; const INITIAL_STATE: { - currentDescriptor: Descriptor; - currentDescriptorExtra: any; + descriptor: Descriptor; + descriptorExtra: any; paged: Page; pagedQuery: any; loading: boolean; } = { - currentDescriptor: null, - currentDescriptorExtra: null, + descriptor: null, + descriptorExtra: null, paged: null, pagedQuery: null, loading: null, }; -function descriptors(state = INITIAL_STATE, action: IReducerAction) { +function descriptorsPublic(state = INITIAL_STATE, action: IReducerAction) { switch (action.type) { case LOGIN_USER: @@ -43,21 +43,14 @@ function descriptors(state = INITIAL_STATE, action: IReducerAction) { }); } - case CREATE_DESCRIPTOR: { - return update(state, { - currentDescriptor: { $set: new Descriptor() }, - currentDescriptorExtra: { $set: null }, - }); - } - case RECEIVE_DESCRIPTOR: { log(RECEIVE_DESCRIPTOR, action); const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; if (receivedIndex !== -1) { return update(state, { - currentDescriptor: { $set: action.payload }, - currentDescriptorExtra: { $set: null }, + descriptor: { $set: action.payload }, + descriptorExtra: { $set: null }, loading: { $set: null }, paged: { content: { @@ -67,33 +60,19 @@ function descriptors(state = INITIAL_STATE, action: IReducerAction) { }); } else { return update(state, { - currentDescriptor: { $set: action.payload }, - currentDescriptorExtra: { $set: null }, + descriptor: { $set: action.payload }, + descriptorExtra: { $set: null }, loading: { $set: null }, paged: {$set: null}, }); } } - case REMOVE_DESCRIPTOR: { - if (state.paged) { - const removeIndex = _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid); - return removeIndex === -1 ? state - : update(state, { - paged: { - content: {$splice: [[removeIndex, 1]]}, - numberOfElements: {$set: state.paged.numberOfElements - 1}, - totalElements: {$set: state.paged.totalElements - 1}, - }, - }); - } - return state; - } case RECEIVE_DESCRIPTOR_EXTRA: { log(RECEIVE_DESCRIPTOR, action); return update(state, { - currentDescriptor: { $set: action.payload.descriptor }, - currentDescriptorExtra: { $set: action.payload.extra }, + descriptor: { $set: action.payload.descriptor }, + descriptorExtra: { $set: action.payload.extra }, loading: { $set: null }, }); } @@ -106,9 +85,26 @@ function descriptors(state = INITIAL_STATE, action: IReducerAction) { }); } + case APPEND_DESCRIPTOR_PAGE: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } + default: return state; } } -export default descriptors; +export default descriptorsPublic; diff --git a/src/descriptors/routes.ts b/src/descriptors/routes.ts new file mode 100644 index 0000000..9c164b9 --- /dev/null +++ b/src/descriptors/routes.ts @@ -0,0 +1,56 @@ +import DescriptorBrowsePage from 'descriptors/ui/BrowsePage'; +import DescriptorDisplayPage from 'descriptors/ui/DisplayPage'; +import DescriptorEditPage from 'descriptors/ui/EditPage'; +import DescriptorDashboardPage from 'descriptors/ui/DashboardPage'; + +import Wrapper from 'ui/catalog/Wrapper'; +import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; + + +const publicRoutes = [ + { + path: '/descriptors', + component: Wrapper, + extraProps: { + title: 'p.descriptors.title', + subtitle: 'p.descriptors.subtitle', + }, + routes: [ + { + path: '/:uuid', + component: DescriptorDisplayPage, + exact: true, + }, + { + path: '/', + component: DescriptorBrowsePage, + exact: true, + }, + ], + }, +]; + +const dashboardRoutes = [ + { + path: '/descriptors/edit', + component: DescriptorEditPage, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + exact: true, + }, + { + path: '/descriptors/:uuid/edit', + component: DescriptorEditPage, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + exact: true, + }, + { + path: '/descriptors', + component: DescriptorDashboardPage, + auth: [ROLE_USER], + extraProps: { + title: 'My Dashboard', + }, + }, +]; + +export {publicRoutes as descriptorPublicRoutes, dashboardRoutes as descriptorDashboardRoutes}; diff --git a/src/ui/pages/descriptor/BrowsePage.tsx b/src/descriptors/ui/BrowsePage.tsx similarity index 86% rename from src/ui/pages/descriptor/BrowsePage.tsx rename to src/descriptors/ui/BrowsePage.tsx index a3ddf62..7f511a9 100644 --- a/src/ui/pages/descriptor/BrowsePage.tsx +++ b/src/descriptors/ui/BrowsePage.tsx @@ -7,7 +7,7 @@ import {log} from 'utilities/debug'; import { parse } from 'query-string'; import { filterCodeToUrl } from 'actions/filterCode'; -import { loadDescriptors, promiseLoadDescriptors, loadDescriptorsByCode } from 'actions/descriptors'; +import { loadDescriptors } from 'descriptors/actions/public'; import { listCrops } from 'actions/crop'; import { Descriptor, IDescriptorFilter } from 'model/descriptor.model'; import { Page, Pagination } from 'model/common.model'; @@ -25,8 +25,7 @@ interface IDescriptorListsPageProps extends React.ClassAttributes { classes: any; pagination?: Pagination; paged: Page; - loadDescriptors: (page?: number, results?: number, sortBy?: string, filter?: IDescriptorFilter) => void; - loadDescriptorsByCode: (page?: number, results?: number, sortBy?: string, filterCode?: string) => void; + loadDescriptors: (page?: number, results?: number, sortBy?: string, filter?: IDescriptorFilter, dir?: string) => void; listCrops: () => any; filterCodeToUrl: any; loading: any; @@ -39,7 +38,7 @@ const styles = (theme) => ({ class BrowsePage extends React.Component { protected static needs = [ - ({ search }) => loadDescriptorsByCode(parse(search).p, parse(search).l || 50, parse(search).s, parse(search).filter, parse(search).d), + ({ search }) => loadDescriptors(parse(search).p, parse(search).l || 50, parse(search).s, parse(search).filter, parse(search).d), ]; constructor(props: IDescriptorListsPageProps, context: any) { @@ -47,15 +46,11 @@ class BrowsePage extends React.Component { } public componentWillMount() { - const {paged, pagination, loadDescriptors, listCrops, loadDescriptorsByCode} = this.props; + const {paged, pagination, loadDescriptors, listCrops} = this.props; if (! paged || paged.filterCode !== pagination.filterCode) { log('Loading descriptors'); - if (pagination.filterCode) { - loadDescriptorsByCode(pagination.page, pagination.size, pagination.sort, pagination.filterCode, pagination.dir); - } else { - loadDescriptors(pagination.page, pagination.size, pagination.sort, {}, pagination.dir); - } + loadDescriptors(pagination.page, pagination.size, pagination.sort, pagination.filter || pagination.filterCode, pagination.dir); } listCrops(); @@ -106,11 +101,11 @@ class BrowsePage extends React.Component { } public render() { - const { classes, paged, pagination, promiseLoadDescriptors } = this.props; + const { classes, paged, pagination, loadDescriptors } = this.props; const stillLoading: boolean = (! paged || ! paged.content); - const loadNextPage = (page: number, pageSize: number) => promiseLoadDescriptors(page, pageSize, pagination.sort, pagination.filter, pagination.dir); + const loadNextPage = (page: number, pageSize: number) => loadDescriptors(page, pageSize, pagination.sort, pagination.filter, pagination.dir); const renderDescriptor = (d: Descriptor) => ( @@ -180,14 +175,12 @@ const mapStateToProps = (state, ownProps) => ({ filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, filterCode: parse(ownProps.location.search).filter, }), - paged: state.descriptors.paged, - loading: state.descriptors.loading, + paged: state.descriptors.public.paged, + loading: state.descriptors.public.loading, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ loadDescriptors, - promiseLoadDescriptors, - loadDescriptorsByCode, listCrops, filterCodeToUrl, }, dispatch); diff --git a/src/descriptors/ui/DashboardPage.tsx b/src/descriptors/ui/DashboardPage.tsx new file mode 100644 index 0000000..9cdbeec --- /dev/null +++ b/src/descriptors/ui/DashboardPage.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import { parse } from 'query-string'; + +import BaseMyDataPage from 'ui/catalog/dashboard/MyDataPage'; +import {listMyDescriptors, approveDescriptor, deleteDescriptor, unpublishDescriptor, publishDescriptor} from 'descriptors/actions/dashboard'; +import {Descriptor} from 'model/descriptor.model'; +import {DescriptorLink} from 'ui/catalog/Links'; +import {PublishState} from 'model/common.model'; + + +const renderDataLink = ({row, children}) => ({ children }); + +class DashboardPage extends BaseMyDataPage { + protected static needs = [ + ({ search }) => { + const pageCurrent = parse(search).p || 0; + const pageSize = parse(search).l || 100; + const pageSort = parse(search).s; + const pageDir = parse(search).d; + const filterCode = parse(search).filter; + + return listMyDescriptors(pageCurrent, pageSize, pageSort, filterCode || {}, pageDir); + }, + ]; +} + +const mapStateToProps = (state, ownProps) => ({ + paged: state.descriptors.dashboard.paged, + tab: 'descriptors', +}); + +const mapDispatchToProps = (dispatch) => bindActionCreators({ + listMyData: listMyDescriptors, + deleteOne: deleteDescriptor, + publishOne: publishDescriptor, + approveOne: approveDescriptor, + unpublishOne: unpublishDescriptor, + renderDataLink, +}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage); diff --git a/src/ui/pages/descriptor/DisplayPage.tsx b/src/descriptors/ui/DisplayPage.tsx similarity index 98% rename from src/ui/pages/descriptor/DisplayPage.tsx rename to src/descriptors/ui/DisplayPage.tsx index 7338032..03795c1 100644 --- a/src/ui/pages/descriptor/DisplayPage.tsx +++ b/src/descriptors/ui/DisplayPage.tsx @@ -5,7 +5,7 @@ import {bindActionCreators} from 'redux'; import {log} from 'utilities/debug'; import { fixDate } from 'utilities'; -import { loadDescriptor, publishDescriptor, deleteDescriptor, approveDescriptor, rejectDescriptor } from 'actions/descriptors'; +import { loadDescriptor, publishDescriptor, deleteDescriptor, approveDescriptor, rejectDescriptor } from 'descriptors/actions/editor'; import { Descriptor, DataType as DescriptorDataType } from 'model/descriptor.model'; import { VocabularyTerm } from 'model/vocabulary.model'; @@ -22,7 +22,7 @@ import { ScrollToTopOnMount } from 'ui/common/page/scrollers'; import { PartnerLink, CropLink, DescriptorListLink, DatasetLink } from 'ui/catalog/Links'; import { Table, TableRow, TableCell } from 'ui/common/tables'; import { Properties, PropertiesItem } from 'ui/catalog/Properties'; -import VocabularyCard from 'ui/pages/vocabulary/c/VocabularyCard'; +import VocabularyCard from 'vocabulary/ui/c/VocabularyCard'; import DescriptorScale from 'ui/catalog/descriptor/DescriptorScale'; import BackButton from 'ui/common/buttons/BackButton'; import Permissions from 'ui/common/permission/Permissions'; @@ -291,8 +291,8 @@ class DisplayPage extends React.Component { const mapStateToProps = (state, { match }) => ({ uuid: match.params.uuid, - descriptor: state.descriptors.currentDescriptor, - descriptorExtra: state.descriptors.currentDescriptorExtra, + descriptor: state.descriptors.dashboard.descriptor, + descriptorExtra: state.descriptors.dashboard.descriptorExtra, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/descriptor/EditPage.tsx b/src/descriptors/ui/EditPage.tsx similarity index 95% rename from src/ui/pages/descriptor/EditPage.tsx rename to src/descriptors/ui/EditPage.tsx index d1a27d2..84c33dd 100644 --- a/src/ui/pages/descriptor/EditPage.tsx +++ b/src/descriptors/ui/EditPage.tsx @@ -4,12 +4,12 @@ import {bindActionCreators} from 'redux'; import {log} from 'utilities/debug'; -import {loadDescriptor, saveDescriptor, publishDescriptor} from 'actions/descriptors'; +import {loadDescriptor, saveDescriptor, publishDescriptor} from 'descriptors/actions/editor'; import { Descriptor } from 'model/descriptor.model'; import DescriptorForm from './c/DescriptorForm'; -import VocabularyCard from 'ui/pages/vocabulary/c/VocabularyCard'; +import VocabularyCard from 'vocabulary/ui/c/VocabularyCard'; import Grid from '@material-ui/core/Grid'; import Paper from '@material-ui/core/Paper'; @@ -92,7 +92,7 @@ class DescriptorEditPage extends React.Component const mapStateToProps = (state, { match }) => ({ uuid: match.params.uuid, - descriptor: state.descriptors.currentDescriptor, + descriptor: state.descriptors.dashboard.descriptor, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/descriptor/c/DescriptorForm.tsx b/src/descriptors/ui/c/DescriptorForm.tsx similarity index 99% rename from src/ui/pages/descriptor/c/DescriptorForm.tsx rename to src/descriptors/ui/c/DescriptorForm.tsx index 190af8c..fc5b826 100644 --- a/src/ui/pages/descriptor/c/DescriptorForm.tsx +++ b/src/descriptors/ui/c/DescriptorForm.tsx @@ -4,7 +4,7 @@ import {Field, reduxForm, formValueSelector} from 'redux-form'; import {log} from 'utilities/debug'; -import {DESCRIPTOR_FORM} from 'constants/descriptors'; +import {DESCRIPTOR_FORM} from 'descriptors/constants'; import ItemsEditor from 'ui/common/ItemsEditor'; import { VocabularyTerm } from 'model/vocabulary.model'; diff --git a/src/ui/pages/descriptor/c/SelectVocabulary.tsx b/src/descriptors/ui/c/SelectVocabulary.tsx similarity index 96% rename from src/ui/pages/descriptor/c/SelectVocabulary.tsx rename to src/descriptors/ui/c/SelectVocabulary.tsx index fdb1e4d..4c1994d 100644 --- a/src/ui/pages/descriptor/c/SelectVocabulary.tsx +++ b/src/descriptors/ui/c/SelectVocabulary.tsx @@ -5,7 +5,8 @@ import {withStyles} from '@material-ui/core/styles'; import {log} from 'utilities/debug'; -import { listVocabularies, saveVocabulary } from 'actions/vocabulary'; +import { saveVocabulary } from 'vocabulary/actions/admin'; +import { listVocabularies } from 'vocabulary/actions/public'; import { Vocabulary } from 'model/vocabulary.model'; import { Partner } from 'model/partner.model'; diff --git a/src/ui/pages/descriptor/c/VocabularyForm.tsx b/src/descriptors/ui/c/VocabularyForm.tsx similarity index 98% rename from src/ui/pages/descriptor/c/VocabularyForm.tsx rename to src/descriptors/ui/c/VocabularyForm.tsx index 3d0a611..8916cd3 100644 --- a/src/ui/pages/descriptor/c/VocabularyForm.tsx +++ b/src/descriptors/ui/c/VocabularyForm.tsx @@ -4,7 +4,7 @@ import {Field, reduxForm} from 'redux-form'; import {log} from 'utilities/debug'; -import {VOCABULARY_FORM} from 'constants/vocabulary'; +import {VOCABULARY_FORM} from 'vocabulary/constants'; import { VocabularyTerm } from 'model/vocabulary.model'; import { TextField } from 'ui/common/text-field'; diff --git a/src/partners/actions/dashboard.ts b/src/partners/actions/dashboard.ts new file mode 100644 index 0000000..7f892fb --- /dev/null +++ b/src/partners/actions/dashboard.ts @@ -0,0 +1,65 @@ +import {push} from 'react-router-redux'; + +// Actions +import {loadPartnerNames} from 'actions/uuidDecoder'; + +// Constants +import {DASHBOARD_GET_PARTNER, DASHBOARD_RECEIVE_PARTNER, DASHBOARD_CREATE_PARTNER, DASHBOARD_RECEIVE_MY_PARTNERLIST} from 'partners/constants'; + +// Model +import {Partner} from 'model/partner.model'; +import {IReducerAction} from 'model/common.model'; + +// Service +import {PartnerService} from 'service/PartnerService'; + +// Util +import {log} from 'utilities/debug'; + +const receivePartner = (partner: Partner): IReducerAction => ({ + type: DASHBOARD_RECEIVE_PARTNER, payload: partner, +}); +const receiveMyPartnerList = (partners: Partner[]): IReducerAction => ({ + type: DASHBOARD_RECEIVE_MY_PARTNERLIST, payload: partners, +}); + +// List user's partners +export const loadMyPartners = () => (dispatch, getState) => { + return PartnerService.listMyPartners(getState().login.access_token, 0, 50) + .then((paged) => { + dispatch(receiveMyPartnerList(paged.content)); + dispatch(loadPartnerNames(paged.content)); + }) + .catch((error) => { + log('Error', error); + }); +}; + +// Just load a record +export const loadPartner = (uuid: string) => (dispatch, getState) => { + log('Loading partner', uuid); + const token = getState().login.access_token; + + dispatch({ type: DASHBOARD_GET_PARTNER, payload: uuid }); + + return PartnerService.getPartner(token, uuid) + // receive the current partner + .then((partner) => { + return dispatch(receivePartner(partner)); + }).catch((error) => { + log(`No partner with uuid ${uuid}`, error); + }); +}; + +// Create a new record +export const createPartner = () => (dispatch) => { + log('Create new partner'); + dispatch({ type: DASHBOARD_CREATE_PARTNER }); + return dispatch(push(`/admin/partners/edit`)); +}; + + +export const editPartner = (uuid: string) => (dispatch, getState) => { + dispatch(loadPartner(uuid)); + dispatch(push(`/admin/partners/${uuid}/edit`)); +}; diff --git a/src/partners/actions/editor.ts b/src/partners/actions/editor.ts new file mode 100644 index 0000000..a1a26a1 --- /dev/null +++ b/src/partners/actions/editor.ts @@ -0,0 +1,47 @@ +import { push } from 'react-router-redux'; +import {SubmissionError} from 'redux-form'; + +// Constants +import {DASHBOARD_RECEIVE_PARTNER} from 'partners/constants'; + +// Model +import {Partner} from 'model/partner.model'; +import {IReducerAction} from 'model/common.model'; + +// Service +import {PartnerService} from 'service/PartnerService'; + +// Util +import {log} from 'utilities/debug'; + +const receivePartner = (partner: Partner): IReducerAction => ({ + type: DASHBOARD_RECEIVE_PARTNER, payload: partner, +}); + +const showPartner = (uuid: string) => (dispatch) => { + log('Navigating to Partner details'); + dispatch(push(`/partners/${uuid}`)); +}; + +export const savePartner = (partner: Partner) => (dispatch, getState) => { + + return PartnerService.savePartner(getState().login.access_token, partner) + .then((saved) => { + dispatch(receivePartner(saved)); + dispatch(showPartner(saved.uuid)); + }).catch((error) => { + log('Save error', error); + throw new SubmissionError({ name: 'Name already used', _error: error.error }); + }); +}; + +// Delete a record +export const deletePartner = (partner: Partner) => (dispatch, getState) => { + return PartnerService.deletePartner(getState().login.access_token, partner) + .then((partner) => { + dispatch(push(`/partners`)); + }) + .catch((error) => { + log('Error', error); + }); +}; diff --git a/src/partners/actions/public.ts b/src/partners/actions/public.ts new file mode 100644 index 0000000..f452161 --- /dev/null +++ b/src/partners/actions/public.ts @@ -0,0 +1,71 @@ +// Actions +import {loadPartnerNames} from 'actions/uuidDecoder'; +import {addFilterCode} from 'actions/filterCode'; + +// Constants +import {GET_PARTNER, RECEIVE_PARTNER, RECEIVE_PARTNERS, APPEND_PARTNERS} from 'partners/constants'; + + +// Model +import { IReducerAction, Page } from 'model/common.model'; +import { Partner } from 'model/partner.model'; +import { IPartnerFilter } from 'model/filter.model'; + +// Service +import { PartnerService } from 'service/PartnerService'; + +// Util +import {log} from 'utilities/debug'; + + +const receivePartnerPage = (paged: Page, page, results, sortBy, filter: string | IPartnerFilter, order): IReducerAction => ({ + type: RECEIVE_PARTNERS, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const appendPartnerPage = (paged: Page, page, results, sortBy, filter: string | IPartnerFilter, order): IReducerAction => ({ + type: APPEND_PARTNERS, + payload: { paged, query: { page, results, sortBy, filter, order } }, +}); + +const receivePartner = (partner: Partner): IReducerAction => ({ + type: RECEIVE_PARTNER, payload: partner, +}); + +// Just load a record +export const loadPartner = (uuid: string) => (dispatch, getState) => { + log('Loading partner', uuid); + const token = getState().login.access_token; + + dispatch({ type: GET_PARTNER, payload: uuid }); + + return PartnerService.getPartner(token, uuid) + // receive the current partner + .then((partner) => { + return dispatch(receivePartner(partner)); + }).catch((error) => { + log(`No partner with uuid ${uuid}`, error); + }); +}; + +// Load them +const loadPartners = (page: number, results: number = 100, sortBy?: string, filter?: IPartnerFilter, order?: string) => (dispatch, getState) => { + + return PartnerService.listPartners(getState().login.access_token, page, results, sortBy, order, filter) + .then((paged) => { + if (paged.number === 0) { + dispatch(receivePartnerPage(paged, page, results, sortBy, filter, order)); + } else { + dispatch(appendPartnerPage(paged, page, results, sortBy, filter, order)); + } + dispatch(loadPartnerNames(paged.content)); + return dispatch(addFilterCode(paged.filterCode, paged.filter)); + }) + .catch((error) => { + log('Error', error); + }); +}; + +export { + loadPartners, receivePartner, +}; diff --git a/src/constants/partner.ts b/src/partners/constants.ts similarity index 64% rename from src/constants/partner.ts rename to src/partners/constants.ts index ab60937..a91da5d 100644 --- a/src/constants/partner.ts +++ b/src/partners/constants.ts @@ -10,6 +10,14 @@ export const RECEIVE_PARTNER = 'App/Partner/RECEIVE_PARTNER'; export const PARTNER_FILTERFORM = 'Form/Partner/PARTNER_FILTERFORM'; export const LIST_PARTNERS = 'App/Partner/LIST_PARTNERS'; export const RECEIVE_PARTNERS = 'App/Partner/RECEIVE_PARTNERS'; +export const APPEND_PARTNERS = 'App/Partner/APPEND_PARTNERS'; // Action to update user's own list of partners export const RECEIVE_MY_PARTNERLIST = 'App/Partner/RECEIVE_MY_PARTNERLIST'; + +// dashboard +export const DASHBOARD_GET_PARTNER = 'partner/dashboard/GET_PARTNER'; +export const DASHBOARD_RECEIVE_PARTNER = 'partner/dashboard/RECEIVE_PARTNER'; +export const DASHBOARD_CREATE_PARTNER = 'partner/dashboard/CREATE_PARTNER'; +export const DASHBOARD_RECEIVE_MY_PARTNERLIST = 'partner/dashboard/RECEIVE_MY_PARTNERLIST'; + diff --git a/src/partners/reducers/dashboard.ts b/src/partners/reducers/dashboard.ts new file mode 100644 index 0000000..b8d00f7 --- /dev/null +++ b/src/partners/reducers/dashboard.ts @@ -0,0 +1,47 @@ +import update from 'immutability-helper'; +import { IReducerAction } from 'model/common.model'; +import { Partner } from 'model/partner.model'; + +import {DASHBOARD_CREATE_PARTNER, DASHBOARD_GET_PARTNER, DASHBOARD_RECEIVE_PARTNER, DASHBOARD_RECEIVE_MY_PARTNERLIST} from 'partners/constants'; + +const INITIAL_STATE = { + myPartners: [], // contains list of user's Partners + currentPartner: null, + loading: null, +}; + +export default function partner(state = INITIAL_STATE, action: IReducerAction = { type: '' }) { + + switch (action.type) { + case DASHBOARD_GET_PARTNER: { + return update(state, { + loading: { $set: { uuid: action.payload } }, + }); + } + + // set the currentPartner to whatever came in + case DASHBOARD_RECEIVE_PARTNER: { + return update(state, { + currentPartner: { $set: action.payload }, + loading: { $set: null }, + }); + } + + // set the currentPartner to a blank new object + case DASHBOARD_CREATE_PARTNER: { + return update(state, { + currentPartner: { $set: new Partner() }, + }); + } + + // set myPartners + case DASHBOARD_RECEIVE_MY_PARTNERLIST: { + // log('My partners', action.payload); + return update(state, { + myPartners: { $set: action.payload }, + }); + } + default: + return state; + } +} diff --git a/src/partners/reducers/index.ts b/src/partners/reducers/index.ts new file mode 100644 index 0000000..9608a71 --- /dev/null +++ b/src/partners/reducers/index.ts @@ -0,0 +1,10 @@ +import { combineReducers } from 'redux'; +import dashboard from './dashboard'; +import publicPartner from './public'; + +const rootReducer = combineReducers({ + dashboard, + public: publicPartner, +}); + +export default rootReducer; diff --git a/src/reducers/partner.ts b/src/partners/reducers/public.ts similarity index 65% rename from src/reducers/partner.ts rename to src/partners/reducers/public.ts index c4290ca..e6b1dd5 100644 --- a/src/reducers/partner.ts +++ b/src/partners/reducers/public.ts @@ -1,14 +1,9 @@ import update from 'immutability-helper'; import { IReducerAction } from 'model/common.model'; -import { Partner } from 'model/partner.model'; -import { - CREATE_PARTNER, GET_PARTNER, RECEIVE_PARTNER, LIST_PARTNERS, RECEIVE_PARTNERS, - RECEIVE_MY_PARTNERLIST, -} from 'constants/partner'; +import {GET_PARTNER, RECEIVE_PARTNER, LIST_PARTNERS, RECEIVE_PARTNERS, APPEND_PARTNERS} from 'partners/constants'; const INITIAL_STATE = { - myPartners: [], // contains list of user's Partners currentPartner: null, paged: null, pagedQuery: null, @@ -37,22 +32,6 @@ export default function partner(state = INITIAL_STATE, action: IReducerAction = loading: { $set: null }, }); } - - // set the currentPartner to a blank new object - case CREATE_PARTNER: { - return update(state, { - currentPartner: { $set: new Partner() }, - }); - } - - // set myPartners - case RECEIVE_MY_PARTNERLIST: { - // log('My partners', action.payload); - return update(state, { - myPartners: { $set: action.payload }, - }); - } - // set the paged to whatever came in case RECEIVE_PARTNERS: { // log('Marking loaded pagedQuery', action.payload); @@ -62,6 +41,23 @@ export default function partner(state = INITIAL_STATE, action: IReducerAction = pagedQuery: { $set: action.payload.query }, }); } + // set the paged to whatever came in + case APPEND_PARTNERS: { + const {paged, query} = action.payload; + + return !state.paged ? update(state, { + paged: { $set: paged }, + pagedQuery: { $set: query }, + }) : + update(state, { + paged: { + content: {$push: paged.content}, + number: {$set: paged.number}, + last: {$set: paged.last}, + }, + pagedQuery: { $set: query }, + }); + } default: return state; diff --git a/src/partners/routes.ts b/src/partners/routes.ts new file mode 100644 index 0000000..1c647e8 --- /dev/null +++ b/src/partners/routes.ts @@ -0,0 +1,46 @@ +import PartnerBrowsePage from 'partners/ui/BrowsePage'; +import PartnerDisplayPage from 'partners/ui/DisplayPage'; +import PartnerEditPage from 'partners/ui/EditPage'; +import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import Wrapper from 'ui/catalog/Wrapper'; + + +const publicRoutes = [ + { + path: '/partners', + component: Wrapper, + extraProps: { + title: 'p.partners.title', + subtitle: 'p.partners.subtitle', + }, + routes: [ + { + path: '/:uuid', + component: PartnerDisplayPage, + exact: true, + }, + { + path: '/', + component: PartnerBrowsePage, + exact: true, + }, + ], + }, +]; + +const adminRoutes = [ + { + path: '/partners/edit', + component: PartnerEditPage, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + exact: true, + }, + { + path: '/partners/:uuid/edit', + component: PartnerEditPage, + auth: [ROLE_USER, ROLE_ADMINISTRATOR], + exact: true, + }, +]; + +export {publicRoutes as partnerPublicRoutes, adminRoutes as partnerAdminRoutes}; diff --git a/src/ui/pages/partner/BrowsePage.tsx b/src/partners/ui/BrowsePage.tsx similarity index 87% rename from src/ui/pages/partner/BrowsePage.tsx rename to src/partners/ui/BrowsePage.tsx index b52f095..36d80dd 100644 --- a/src/ui/pages/partner/BrowsePage.tsx +++ b/src/partners/ui/BrowsePage.tsx @@ -10,7 +10,7 @@ import { filterCodeToUrl } from 'actions/filterCode'; import { Page, Pagination } from 'model/common.model'; import { Partner } from 'model/partner.model'; import { IPartnerFilter } from 'model/filter.model'; -import { loadPartners, promiseLoadPartners, loadPartnersByCode } from 'actions/partner'; +import { loadPartners } from 'partners/actions/public'; import PagedLoader from 'ui/common/PagedLoader'; import Loading from 'ui/common/Loading'; @@ -31,8 +31,6 @@ interface IBrowsePageProps extends React.ClassAttributes { paged?: Page; loading: any; loadPartners: any; - promiseLoadPartners: any; - loadPartnersByCode: any; filterCodeToUrl: any; history: any; location: any; @@ -45,20 +43,16 @@ const styles = (theme) => ({ class PartnerListPage extends React.Component { protected static needs = [ - ({ search }) => loadPartnersByCode(parse(search).p, parse(search).l, parse(search).s, parse(search).filter, parse(search).d), + ({ search }) => loadPartners(parse(search).p, parse(search).l, parse(search).s, parse(search).filter, parse(search).d), ]; public componentWillMount() { - const {pagination, paged, loadPartners, loadPartnersByCode} = this.props; + const {pagination, paged, loadPartners} = this.props; log(`BrowsePage.componentWillMount...`, this.props); if (! paged || paged.filterCode !== pagination.filterCode) { log('Loading partners lists'); - if (pagination.filterCode) { - loadPartnersByCode(pagination.page, pagination.size, pagination.sort, pagination.filterCode, pagination.dir); - } else { - loadPartners(pagination.page, pagination.size, pagination.sort, {}, pagination.dir); - } + loadPartners(pagination.page, pagination.size, pagination.sort, pagination.filter || pagination.filterCode, pagination.dir); } } @@ -107,8 +101,8 @@ class PartnerListPage extends React.Component { } protected loadNextPage = (page: number, pageSize: number) => { - const {promiseLoadPartners, pagination} = this.props; - return promiseLoadPartners(page, pageSize, pagination.sort, pagination.filter, pagination.dir); + const {loadPartners, pagination} = this.props; + return loadPartners(page, pageSize, pagination.sort, pagination.filter, pagination.dir); } protected renderPartner = (p: Partner) => ( @@ -187,14 +181,12 @@ const mapStateToProps = (state, ownProps) => ({ filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, filterCode: parse(ownProps.location.search).filter, }), - paged: state.partner.paged, - loading: state.partner.loading, + paged: state.partner.public.paged, + loading: state.partner.public.loading, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ loadPartners, - promiseLoadPartners, - loadPartnersByCode, filterCodeToUrl, }, dispatch); diff --git a/src/ui/pages/partner/DisplayPage.tsx b/src/partners/ui/DisplayPage.tsx similarity index 96% rename from src/ui/pages/partner/DisplayPage.tsx rename to src/partners/ui/DisplayPage.tsx index c090086..51719de 100644 --- a/src/ui/pages/partner/DisplayPage.tsx +++ b/src/partners/ui/DisplayPage.tsx @@ -4,7 +4,9 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import { translate } from 'react-i18next'; -import {loadPartner, editPartner, deletePartner} from 'actions/partner'; +import {deletePartner} from 'partners/actions/editor'; +import {loadPartner, editPartner} from 'partners/actions/dashboard'; + import {Partner} from 'model/partner.model'; import confirm from 'utilities/confirmAlert'; @@ -139,8 +141,8 @@ class PartnerPage extends React.Component { const mapStateToProps = (state, ownProps) => ({ uuid: ownProps.match.params.uuid, - partner: state.partner.currentPartner, - loading: state.partner.loading, + partner: state.partner.dashboard.currentPartner, + loading: state.partner.dashboard.loading, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/partner/EditPage.tsx b/src/partners/ui/EditPage.tsx similarity index 91% rename from src/ui/pages/partner/EditPage.tsx rename to src/partners/ui/EditPage.tsx index 43e769a..960622a 100644 --- a/src/ui/pages/partner/EditPage.tsx +++ b/src/partners/ui/EditPage.tsx @@ -3,7 +3,8 @@ import * as React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {loadPartner, savePartner} from 'actions/partner'; +import {savePartner} from 'partners/actions/editor'; +import {loadPartner} from 'partners/actions/dashboard'; import {Partner} from 'model/partner.model'; import PartnerForm from './c/PartnerForm'; @@ -62,7 +63,7 @@ class PartnerEditPage extends React.Component { const mapStateToProps = (state, ownProps) => ({ uuid: ownProps.match.params.uuid, - partner: state.partner.currentPartner, + partner: state.partner.dashboard.currentPartner, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/partner/c/Filters.tsx b/src/partners/ui/c/Filters.tsx similarity index 94% rename from src/ui/pages/partner/c/Filters.tsx rename to src/partners/ui/c/Filters.tsx index df43014..de3f153 100644 --- a/src/ui/pages/partner/c/Filters.tsx +++ b/src/partners/ui/c/Filters.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { reduxForm } from 'redux-form'; -import { PARTNER_FILTERFORM } from 'constants/partner'; +import { PARTNER_FILTERFORM } from 'partners/constants'; import FiltersBlock from 'ui/common/filter/FiltersBlock'; import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; diff --git a/src/ui/pages/partner/c/PartnerCard.tsx b/src/partners/ui/c/PartnerCard.tsx similarity index 100% rename from src/ui/pages/partner/c/PartnerCard.tsx rename to src/partners/ui/c/PartnerCard.tsx diff --git a/src/ui/pages/partner/c/PartnerForm.tsx b/src/partners/ui/c/PartnerForm.tsx similarity index 98% rename from src/ui/pages/partner/c/PartnerForm.tsx rename to src/partners/ui/c/PartnerForm.tsx index feaec83..2c59f8a 100644 --- a/src/ui/pages/partner/c/PartnerForm.tsx +++ b/src/partners/ui/c/PartnerForm.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import {PARTNER_FORM} from 'constants/partner'; +import {PARTNER_FORM} from 'partners/constants'; import { connect } from 'react-redux'; import { setPageTitle } from 'actions/pageTitle'; import { bindActionCreators } from 'redux'; diff --git a/src/ui/pages/partner/c/SearchMenu.tsx b/src/partners/ui/c/SearchMenu.tsx similarity index 100% rename from src/ui/pages/partner/c/SearchMenu.tsx rename to src/partners/ui/c/SearchMenu.tsx diff --git a/src/ui/pages/partner/c/Summary.tsx b/src/partners/ui/c/Summary.tsx similarity index 100% rename from src/ui/pages/partner/c/Summary.tsx rename to src/partners/ui/c/Summary.tsx diff --git a/src/reducers/dashboard.ts b/src/reducers/dashboard.ts index 42127fc..38c661a 100644 --- a/src/reducers/dashboard.ts +++ b/src/reducers/dashboard.ts @@ -1,64 +1,18 @@ import update from 'immutability-helper'; -import {ADD_TO_EDIT_LIST, RECEIVE_DASHBOARD_PAGE, REMOVE_FROM_EDIT_LIST, RECEIVE_IS_EDIT_MODE, REFRESH_ITEM, REMOVE_ITEM, SELECT_ALL, UNSELECT_ALL} from 'constants/dashboard'; -import {RECEIVE_DESCRIPTOR, RECEIVE_DESCRIPTORLIST, REMOVE_DESCRIPTOR, REMOVE_DESCRIPTORLIST} from 'constants/descriptors'; -import {RECEIVE_DATASET, REMOVE_DATASET} from 'constants/datasets'; -import {Descriptor, DescriptorList} from 'model/descriptor.model'; -import {Page} from 'model/common.model'; -import {Dataset} from 'model/dataset.model'; +import {ADD_TO_EDIT_LIST, REMOVE_FROM_EDIT_LIST, RECEIVE_IS_EDIT_MODE, SELECT_ALL, UNSELECT_ALL} from 'constants/dashboard'; import * as _ from 'lodash'; const INITIAL_STATE: { isEditMode: boolean, - paged: Page | Page | Page, selected: object[], } = { isEditMode: false, - paged: null, selected: [], }; export default function dashboard(state = INITIAL_STATE, action: { type?: string, payload?: any } = {type: '', payload: null}) { switch (action.type) { - case REFRESH_ITEM: - case RECEIVE_DESCRIPTOR: - case RECEIVE_DESCRIPTORLIST: - case RECEIVE_DATASET: { - const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; - - if (receivedIndex !== -1) { - return update(state, { - paged: { - content: { - [receivedIndex]: {$set: action.payload}, - }, - }, - }); - } else { - return update(state, { - paged: {$set: null}, - }); - } - } - - case REMOVE_ITEM: - case REMOVE_DESCRIPTOR: - case REMOVE_DESCRIPTORLIST: - case REMOVE_DATASET: { - if (state.paged) { - const removeIndex = _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid); - return removeIndex === -1 ? state - : update(state, { - paged: { - content: {$splice: [[removeIndex, 1]]}, - numberOfElements: {$set: state.paged.numberOfElements - 1}, - totalElements: {$set: state.paged.totalElements - 1}, - }, - }); - } - return state; - } - case RECEIVE_IS_EDIT_MODE: { return update(state, { isEditMode: { $set: action.payload }, @@ -72,16 +26,9 @@ export default function dashboard(state = INITIAL_STATE, action: { type?: string _.remove(state.selected, (item) => item === action.payload); return state; } - case RECEIVE_DASHBOARD_PAGE: { - return update(state, { - paged: {$set: action.payload}, - }); - } case SELECT_ALL: { - // @ts-ignore - const newEditList = state.paged.content.map((item) => item.uuid); return update(state, { - selected: {$set: newEditList }, + selected: {$set: action.payload }, }); } case UNSELECT_ALL: { diff --git a/src/reducers/datasets.ts b/src/reducers/datasets.ts deleted file mode 100644 index ffaf2f2..0000000 --- a/src/reducers/datasets.ts +++ /dev/null @@ -1,146 +0,0 @@ -import update from 'immutability-helper'; -import {log} from 'utilities/debug'; -import * as _ from 'lodash'; - -import {CREATE_DATASET, RECEIVE_DATASET, RECEIVE_DATASET_PAGE, ADD_CREATOR_TO_DATASET, REMOVE_CREATOR_FROM_DATASET, UPDATE_DATASET_CREATOR, ADD_LOCATION, RECEIVE_LOCATION, REMOVE_LOCATION, REMOVE_DATASET} from 'constants/datasets'; -import { LOGIN_USER, LOGIN_APP, LOGOUT } from 'constants/login'; - -import { Dataset } from 'model/dataset.model'; - -const INITIAL_STATE = { - currentDataset: null, - paged: null, - pagedQuery: null, -}; - -function datasets(state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) { - - switch (action.type) { - case LOGIN_USER: - case LOGIN_APP: - case LOGOUT: { - return update(state, { $set: INITIAL_STATE }); - } - - case CREATE_DATASET: { - return update(state, { - currentDataset: { $set: new Dataset() }, - }); - } - - case RECEIVE_DATASET: { - const receivedIndex = state.paged ? _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid) : -1; - - if (receivedIndex !== -1) { - return update(state, { - currentDataset: { $set: action.payload }, - paged: { - content: { - [receivedIndex]: {$set: action.payload}, - }, - }, - }); - } else { - return update(state, { - currentDataset: { $set: action.payload }, - paged: {$set: null}, - }); - } - } - - case REMOVE_DATASET: { - if (state.paged) { - const removeIndex = _.findIndex(state.paged.content, (item) => item.uuid === action.payload.uuid); - return removeIndex === -1 ? state - : update(state, { - paged: { - content: {$splice: [[removeIndex, 1]]}, - numberOfElements: {$set: state.paged.numberOfElements - 1}, - totalElements: {$set: state.paged.totalElements - 1}, - }, - }); - } - return state; - } - - case RECEIVE_DATASET_PAGE: { - return update(state, { - paged: { $set: action.payload.paged }, - pagedQuery: { $set: action.payload.query }, - }); - } - - case ADD_CREATOR_TO_DATASET: { - log('Payload ADD_CREATOR_TO_DATASET', action); - if (state.currentDataset) { // && action.payload.datasetUUID === state.currentDataset.uuid) { - return update(state, { - currentDataset: { creators: { $push: [ action.payload.creator ] } }, - }); - } else { - return state; - } - } - - case REMOVE_CREATOR_FROM_DATASET: { - log('Payload REMOVE_CREATOR_FROM_DATASET', action); - if (state.currentDataset) { // && action.payload.datasetUUID === state.currentDataset.uuid) { - return update(state, { - currentDataset: { creators: { $apply: (creators) => creators.filter((creator) => creator.uuid !== action.payload.creator.uuid) } }, - }); - } else { - return state; - } - } - - case UPDATE_DATASET_CREATOR: { - log('Payload UPDATE_DATASET_CREATOR', action); - if (state.currentDataset) { // && action.payload.datasetUUID === state.currentDataset.uuid) { - const index = state.currentDataset.creators.findIndex((creator) => creator.uuid === action.payload.creator.uuid); - return update(state, { - currentDataset: { creators: { [index]: { $set: action.payload.creator } } }, - }); - } else { - return state; - } - } - - case ADD_LOCATION: { - log('Payload ADD_LOCATION', action); - if (state.currentDataset) { // && action.payload.datasetUUID === state.currentDataset.uuid) { - return update(state, { - currentDataset: { locations: { $push: [ action.payload.location ] } }, - }); - } else { - return state; - } - } - - case REMOVE_LOCATION: { - log('Payload REMOVE_LOCATION', action); - if (state.currentDataset) { // && action.payload.datasetUUID === state.currentDataset.uuid) { - return update(state, { - currentDataset: { locations: { $apply: (locations) => locations.filter((location) => location.uuid !== action.payload.location.uuid) } }, - }); - } else { - return state; - } - } - - case RECEIVE_LOCATION: { - log('Payload RECEIVE_LOCATION', action); - if (state.currentDataset) { // && action.payload.datasetUUID === state.currentDataset.uuid) { - const index = state.currentDataset.locations.findIndex((location) => location.uuid === action.payload.location.uuid); - return update(state, { - currentDataset: { locations: { [index]: { $set: action.payload.location } } }, - }); - } else { - return state; - } - } - - default: - return state; - } -} - -export default datasets; diff --git a/src/reducers/index.ts b/src/reducers/index.ts index eb3fecf..cc817e2 100644 --- a/src/reducers/index.ts +++ b/src/reducers/index.ts @@ -3,15 +3,15 @@ import { reducer as formReducer } from 'redux-form'; import { routerReducer } from 'react-router-redux'; import applicationConfig from './applicationConfig'; import lookups from './lookups'; -import descriptors from './descriptors'; -import descriptorList from './descriptorList'; -import partner from './partner'; +import descriptors from 'descriptors/reducers'; +import descriptorList from 'descriptorlists/reducers'; +import partner from 'partners/reducers'; import login from './login'; import serverInfo from './serverInfo'; -import datasets from './datasets'; +import datasets from 'datasets/reducers'; import filter from './filter'; import appMounted from './appMounted'; -import vocabulary from './vocabulary'; +import vocabulary from 'vocabulary/reducers'; import crop from './crop'; import history from './history'; import search from './search'; diff --git a/src/service/DatasetService.ts b/src/service/DatasetService.ts index 93228bc..2870426 100644 --- a/src/service/DatasetService.ts +++ b/src/service/DatasetService.ts @@ -38,31 +38,25 @@ export class DatasetService { } // List published datasets - public static listDatasets(token: string, page: number = 0, results: number = 10, sortBy: string = 'title', filter: IDatasetFilter = {}, order: string = 'ASC'): Promise> { + public static listDatasets(token: string, page: number = 0, results: number = 10, sortBy: string = 'title', filter: string | IDatasetFilter = {}, order: string = 'ASC'): Promise> { - return authenticatedRequest(token, { - url: `${LIST_DATASET_URL}?p=${page}&l=${results}${order ? '&d=' + order : ''}${sortBy ? '&s=' + sortBy : ''}`, - method: 'POST', - data: { - ...filter, - }, - }) - .then(({ data }) => new Page(data, (d) => new Dataset(d))) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - return paged; - }); - } + const qs = stringify({ + f: typeof filter === 'string' ? filter : undefined, + p: page || undefined, + l: results || 100, + d: order, + s: sortBy , + }, {}); - // List published datasets by filter code - // TODO Remove - public static listDatasetsByCode(token: string, page: number = 0, results: number = 10, sortBy: string = 'title', filterCode: string, order: string = 'ASC'): Promise> { - const code = filterCode ? `/${filterCode}` : ''; + const content = typeof filter === 'string' ? null : { ...filter } ; + const apiUrl = LIST_DATASET_URL + (qs ? `?${qs}` : ''); return authenticatedRequest(token, { - url: `${LIST_DATASET_URL}${code}?p=${page}&l=${results}${order ? '&d=' + order : ''}${sortBy ? '&s=' + sortBy : ''}`, + url: apiUrl, method: 'POST', - data: {}, + data: { + ...content, + }, }) .then(({ data }) => new Page(data, (d) => new Dataset(d))) .then((paged) => { diff --git a/src/service/DescriptorListService.ts b/src/service/DescriptorListService.ts index 0a6cf5c..09ab075 100644 --- a/src/service/DescriptorListService.ts +++ b/src/service/DescriptorListService.ts @@ -43,15 +43,24 @@ export class DescriptorListService { } // Lists published descriptor lists - public static listDescriptorLists(token: string, page: number = 0, results: number = 10, sortBy: string = 'title', filter: IDescriptorListFilter = {}, order: string = 'ASC'): Promise> { + public static listDescriptorLists(token: string, page: number = 0, results: number = 10, sortBy: string = 'title', filter: string | IDescriptorListFilter = {}, order: string = 'ASC'): Promise> { - const sortParam = sortBy ? `&s=${sortBy}` : ''; + const qs = stringify({ + f: typeof filter === 'string' ? filter : undefined, + p: page || undefined, + l: results || 100, + d: order, + s: sortBy , + }, {}); + + const content = typeof filter === 'string' ? null : { ...filter } ; + const apiUrl = LIST_DESCRIPTORLISTS_URL + (qs ? `?${qs}` : ''); return authenticatedRequest(token, { - url: `${LIST_DESCRIPTORLISTS_URL}?p=${page}&l=${results}&d=${order}${sortParam}`, + url: apiUrl, method: 'POST', data: { - ...filter, + ...content, }, }) .then(({ data }) => new Page(data, (dl) => new DescriptorList(dl))) @@ -69,23 +78,6 @@ export class DescriptorListService { }).then(({data}) => data); } - // Lists published descriptor lists by filter code - // TODO Remove - public static listDescriptorListsByCode(token: string, page: number = 0, results: number = 10, sortBy: string = 'title', filterCode: string, order: string = 'ASC'): Promise> { - const sortParam = sortBy ? `&s=${sortBy}` : ''; - const code = filterCode ? `/${filterCode}` : ''; - - return authenticatedRequest(token, { - url: `${LIST_DESCRIPTORLISTS_URL}${code}?p=${page}&l=${results}&d=${order}${sortParam}`, - method: 'POST', - data: {}, - }).then(({ data }) => new Page(data, (dl) => new DescriptorList(dl))) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - return paged; - }); - } - // load descriptor list by uuid from server public static loadDescriptorList(token: string, uuid: string): Promise { log('Load descriptor list by UUID ', uuid); diff --git a/src/service/DescriptorService.ts b/src/service/DescriptorService.ts index c04d724..7faa1fa 100644 --- a/src/service/DescriptorService.ts +++ b/src/service/DescriptorService.ts @@ -52,13 +52,25 @@ export class DescriptorService { } // Lists published descriptors - public static listDescriptors(token: string, page: number = 0, results: number = 50, sortBy?: string, filter: IDescriptorFilter = {}, order?: string): Promise> { + public static listDescriptors(token: string, page: number = 0, results: number = 50, sortBy?: string, filter: string | IDescriptorFilter = {}, order?: string): Promise> { + + const qs = stringify({ + f: typeof filter === 'string' ? filter : undefined, + p: page || undefined, + l: results || 100, + d: order, + s: sortBy , + }, {}); + + const content = typeof filter === 'string' ? null : { ...filter } ; + const apiUrl = LIST_DESCRIPTORS_URL + (qs ? `?${qs}` : ''); + return authenticatedRequest(token, { - url: `${LIST_DESCRIPTORS_URL}?p=${page}&l=${results}${order ? '&d=' + order : ''}${sortBy ? '&s=' + sortBy : ''}`, + url: apiUrl, method: 'POST', data: { - ...filter, + ...content, }, }) .then(({ data }) => new Page(data, (dl) => new Descriptor(dl))) @@ -80,23 +92,6 @@ export class DescriptorService { .then(({ data }) => new Descriptor(data)); } - // Lists published descriptors by filter code - // TODO Remove - public static listDescriptorsByCode(token: string, page: number = 0, results: number = 50, sortBy?: string, filterCode?: string, order?: string): Promise> { - const code = filterCode ? `/${filterCode}` : ''; - - return authenticatedRequest(token, { - url: `${LIST_DESCRIPTORS_URL}${code}?p=${page}&l=${results}${order ? '&d=' + order : ''}${sortBy ? '&s=' + sortBy : ''}`, - method: 'POST', - data: {}, - }) - .then(({ data }) => new Page(data, (dl) => new Descriptor(dl))) - .then((paged) => { - dereferenceReferences(paged.content, 'owner', (o) => new Partner(o)); - return paged; - }); - } - public static listCategories(token: string): Promise { log('List descriptor categories'); diff --git a/src/service/GenesysService.ts b/src/service/GenesysService.ts deleted file mode 100644 index 786c996..0000000 --- a/src/service/GenesysService.ts +++ /dev/null @@ -1,51 +0,0 @@ -import authenticatedRequest from 'utilities/requestUtils'; -import * as _ from 'lodash'; - -import {Page} from 'model/common.model'; -import { APIv0_BASE_URL } from 'constants/apiURLS'; - -export class GenesysService { - - public static listAccessions(token: string, filters: object, page: number = 0, results: number = 50): Promise> { - - const flatFilters = genesysFlatten('', renameFilters(filters), {}); - // console.log(`Flatfilters ${JSON.stringify(flatFilters)}`, filters, flatFilters); - - return authenticatedRequest(token, { - url: `${APIv0_BASE_URL}/acn/filter?p=${page}&l=${results}`, - method: 'POST', - data: { - ...flatFilters, - }, - }).then(({ data }) => new Page(data)); - // TODO catch 403 -- reauth - } -} - -const renameFilters = (filters: any) => { - const renamed: any = { ...filters }; - renamed.crops = renamed.crop; - delete renamed.crop; - return renamed; -}; - -/** - * Genesys PGR uses a semi-flat JSON structure, with arrays and literals as values: - * { institute: { code: [ 'NGA039' ] } } --> { 'institute.code': [ 'NGA039' ] } - */ -const genesysFlatten = (prefix: string, obj: object, result: any) => { - for (const k of Object.keys(obj)) { - const val = obj[k]; - // console.log(`${k} = ${val} typeof ${typeof val}`); - if (_.isObject(val)) { - if (_.isArray(val) && val.length > 0) { - result[`${prefix}${k}`] = val; - } else { - genesysFlatten(`${prefix}${k}.`, val, result); - } - } else if (val !== null) { - result[`${prefix}${k}`] = val; - } - } - return result; -}; diff --git a/src/service/PartnerService.ts b/src/service/PartnerService.ts index ecb7688..ef03e52 100644 --- a/src/service/PartnerService.ts +++ b/src/service/PartnerService.ts @@ -1,3 +1,4 @@ +import { stringify } from 'query-string'; import {Partner} from 'model/partner.model'; import {Page} from 'model/common.model'; import {MY_PARTNERS_LIST_URL, GET_PARTNER_URL, LIST_PARTNER_URL, CREATE_PARTNER_URL, UPDATE_PARTNER_URL, REMOVE_PARTNER_URL } from 'constants/apiURLS'; @@ -35,12 +36,22 @@ export class PartnerService { // List public static listPartners(token: string, page: number = 0, results: number = 10, sortBy: string = 'name', order: string = 'ASC', filter: IPartnerFilter = {}): Promise> { + const qs = stringify({ + f: typeof filter === 'string' ? filter : undefined, + p: page || undefined, + l: results || 100, + d: order, + s: sortBy , + }, {}); + + const content = typeof filter === 'string' ? null : { ...filter } ; + const apiUrl = LIST_PARTNER_URL + (qs ? `?${qs}` : ''); return authenticatedRequest(token, { - url: `${LIST_PARTNER_URL}?p=${page}&l=${results}&s=${sortBy}&d=${order}`, + url: apiUrl, method: 'POST', data: { - ...filter, + ...content, }, }) .then(({data}) => new Page(data, (dl) => new Partner(dl))) @@ -49,21 +60,6 @@ export class PartnerService { }); } - // List by filter code - public static listPartnersByCode(token: string, page: number = 0, results: number = 10, sortBy: string = 'name', order: string = 'ASC', filterCode: string): Promise> { - const code = filterCode ? `/${filterCode}` : ''; - - return authenticatedRequest(token, { - url: `${LIST_PARTNER_URL}${code}?p=${page}&l=${results}&s=${sortBy}&d=${order}`, - method: 'POST', - data: {}, - }) - .then(({data}) => new Page(data, (dl) => new Partner(dl))) - .then((paged) => { - return paged; - }); - } - // Create or update a descriptor list public static getPartner(token: string, uuid: string): Promise { log(`Loading partner by UUID=${uuid}`); diff --git a/src/ui/catalog/Links.tsx b/src/ui/catalog/Links.tsx index 8a0d398..d624929 100644 --- a/src/ui/catalog/Links.tsx +++ b/src/ui/catalog/Links.tsx @@ -6,13 +6,13 @@ import {log} from 'utilities/debug'; import { Dataset } from 'model/dataset.model'; import { Descriptor, DescriptorList } from 'model/descriptor.model'; -import { loadDescriptorList } from 'actions/descriptorList'; +import { loadDescriptorList } from 'descriptorlists/actions/editor'; import { Partner } from 'model/partner.model'; -import { loadPartner } from 'actions/partner'; +import { loadPartner } from 'partners/actions/dashboard'; import { Vocabulary } from 'model/vocabulary.model'; -import { loadVocabulary } from 'actions/vocabulary'; +import { loadVocabulary } from 'vocabulary/actions/public'; import { Crop } from 'model/crop.model'; @@ -36,7 +36,7 @@ function DatasetLink({ }: IDatasetLinkProps) { if (edit) { return ( - + { children || } ); @@ -65,7 +65,7 @@ function DescriptorLink({ }: IDescriptorLinkProps) { if (edit) { return ( - + { children || } ); @@ -94,7 +94,7 @@ const DescriptorListLink_ = ({ to: descriptorList, edit = false, children, loadD if (edit) { return ( - { children || } + { children || } ); } else { return ( @@ -142,7 +142,7 @@ const PartnerLink_ = ({ to: partner, edit = false, children, loadPartner }: { to if (edit) { return ( - { children || partner.name } + { children || partner.name } ); } else { return ( @@ -161,7 +161,7 @@ const VocabularyLink_ = ({ to: vocabulary, edit = false, children, loadVocabular if (edit) { return ( - { children || vocabulary.name } + { children || vocabulary.name } ); } else { return ( @@ -192,7 +192,7 @@ class CropLink1 extends React.Component { if (crop) { if (edit) { return ( - { children || crop.name } + { children || crop.name } ); } else { return ( diff --git a/src/ui/catalog/dashboard/MyDataPage.tsx b/src/ui/catalog/dashboard/MyDataPage.tsx new file mode 100644 index 0000000..c11e381 --- /dev/null +++ b/src/ui/catalog/dashboard/MyDataPage.tsx @@ -0,0 +1,195 @@ +import * as React from 'react'; +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import update from 'immutability-helper'; + +import {Page} from 'model/common.model'; +import { parse } from 'query-string'; + +import { filterCodeToUrl } from 'actions/filterCode'; +import {setPageTitle} from 'actions/pageTitle'; +import { + setEditMode, addToEditList, deleteAll, publishAll, approveAll, removeFromEditList, unpublishAll, onPageChange, + selectAll, unselectAll, +} from 'actions/dashboard'; + +import MyDataTable from './c/MyDataTable'; +import DashboardActionsButton from './c/DashboardActionsButton'; + +interface IDataPublishedContainerProps extends React.ClassAttributes { + title: string; + tab?: string; + pagination: any; + paged: Page; + preFilter?: object; + basePath: string; + filterCodeToUrl: any; + listData: any; + renderDataLink: any; + setPageTitle: (title: string) => void; + addToEditList: (item: any) => void; + removeFromEditList: (item: any) => void; + onPageChange: () => void; + deleteAll: (deleteOne: (page?, results?, sortBy?, filter?, order?) => Promise) => void; + publishAll: (publishOne: (page?, results?, sortBy?, filter?, order?) => Promise) => void; + setEditState: (state: boolean) => void; + editList: string[]; + isEditMode: boolean; +} + +class BaseMyDataPage extends React.Component { + + constructor(props) { + super(props); + this.state = {tab: '', pagination: props.pagination }; + const { title, setPageTitle } = this.props; + setPageTitle(title); + } + + public componentWillMount() { + const { pagination, tab, paged } = this.props; + // console.log(`willM ${filterCode}`, filters[filterCode]); + + this.setState({tab}); + if (!paged) { + this.loadData(null, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); + } + } + + public componentWillReceiveProps(nextProps) { + const {filterCodeToUrl, paged} = this.props; + if (paged) { + filterCodeToUrl(paged.filterCode); + } + + const {tab} = nextProps; + if (tab !== this.state.tab) { + const { pagination } = nextProps; + this.loadData(null, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); + } + } + + protected getActionHandlers() { + const {listMyData, deleteOne, publishOne, approveOne, unpublishOne, deleteAll, publishAll, approveAll, unpublishAll, selectAll, unselectAll} = this.props; + + const promiseListData = listMyData; + const deleteAllAction = () => { deleteAll(deleteOne); }; + const publishAllAction = () => { publishAll(publishOne); }; + const approveAllAction = () => { approveAll(approveOne); }; + const unpublishAllAction = () => { unpublishAll(unpublishOne); }; + + return { promiseListData, deleteAllAction, publishAllAction, unpublishAllAction, approveAllAction, selectAll, unselectAll }; + } + + protected onPaginationChange = (page, results, sortBy, dir) => { + const { history, location } = this.props; + const params = new URLSearchParams(location.search); + params.set('p', page); + params.set('l', results); + if (sortBy) { + params.set('s', sortBy); + } else { + params.delete('s'); + } + if (dir) { + params.set('d', dir); + } else { + params.delete('d'); + } + + location.search = params.toString(); + history.push(location); + const { tab } = this.props; + this.loadData(null, tab, page, results, sortBy, dir); + } + + protected onFilter = (newFilters) => { + this.setState({...this.state, filter: newFilters}); + + const {tab, pagination } = this.props; + this.loadData(newFilters, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); + } + + protected loadData(filter, tab, page, size, sortBy, dir) { + + const {listMyData, preFilter, pagination, onPageChange } = this.props; + const newFilters = filter && { ...preFilter, ...filter }; + // console.log(`Filters code=${filterCode}`, newFilters, preFilter); + + if (newFilters || this.state.tab !== tab || this.state.pagination.page !== page || this.state.pagination.size !== size || this.state.pagination.sort !== sortBy || this.state.pagination.dir !== dir) { + // console.log('Reloading'); + onPageChange(); + this.setState(update(this.state, { + tab: {$set: tab}, + pagination: { + page: {$set: page}, + size: {$set: size}, + sort: {$set: sortBy}, + dir: {$set: dir}, + filterCode: {$set: pagination.filterCode}, + }, + })); + + listMyData(page, size, sortBy, newFilters || pagination.filterCode, dir); + } + } + + public render() { + const {tab, basePath, pagination, addToEditList, removeFromEditList, isEditMode, setEditMode, editList, paged, renderDataLink } = this.props; + const actionHandlers = this.getActionHandlers(); + + return ( +
+ + +
+ ); + } +} + +const mapStateToProps = (state, ownProps) => ({ + pagination: { + page: +parse(ownProps.location.search).p || 0, // current page + size: +parse(ownProps.location.search).l || 100, // page size + sort: parse(ownProps.location.search).s, // page sorts + dir: parse(ownProps.location.search).d, // page sort directions + filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, + filterCode: parse(ownProps.location.search).filter, + }, + title: ownProps.route.extraProps.title || 'My Dashboard', // route-configured + basePath: `/dashboard`, + preFilter: ownProps.route.extraProps.filter || {}, // route-configured + editList: state.dashboard.selected, + isEditMode: state.dashboard.isEditMode, +}); + +const mapDispatchToProps = (dispatch) => bindActionCreators({ + addToEditList, + removeFromEditList, + onPageChange, + deleteAll, + publishAll, + approveAll, + unpublishAll, + selectAll, + unselectAll, + setEditMode, + setPageTitle, + filterCodeToUrl, +}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(BaseMyDataPage); diff --git a/src/ui/pages/dashboard/c/DashboardActionsArea.tsx b/src/ui/catalog/dashboard/c/DashboardActionsArea.tsx similarity index 100% rename from src/ui/pages/dashboard/c/DashboardActionsArea.tsx rename to src/ui/catalog/dashboard/c/DashboardActionsArea.tsx diff --git a/src/ui/pages/dashboard/c/DashboardActionsButton.tsx b/src/ui/catalog/dashboard/c/DashboardActionsButton.tsx similarity index 94% rename from src/ui/pages/dashboard/c/DashboardActionsButton.tsx rename to src/ui/catalog/dashboard/c/DashboardActionsButton.tsx index e6ce0a8..7c4b6db 100644 --- a/src/ui/pages/dashboard/c/DashboardActionsButton.tsx +++ b/src/ui/catalog/dashboard/c/DashboardActionsButton.tsx @@ -15,10 +15,10 @@ import PartnerIcon from '@material-ui/icons/PersonAdd'; import DescriptorListIcon from '@material-ui/icons/List'; import Authorize from 'ui/common/authorized/Authorize'; -import {createPartner} from 'actions/partner'; -import {createDescriptorList} from 'actions/descriptorList'; -import {createDataset} from 'actions/dataset'; -import {createDescriptor} from 'actions/descriptors'; +import {createPartner} from 'partners/actions/dashboard'; +import {createDescriptorList} from 'descriptorlists/actions/dashboard'; +import {createDataset} from 'datasets/actions/dashboard'; +import {createDescriptor} from 'descriptors/actions/dashboard'; const styles = (theme) => ({ diff --git a/src/ui/pages/dashboard/c/DashboardButton.tsx b/src/ui/catalog/dashboard/c/DashboardButton.tsx similarity index 100% rename from src/ui/pages/dashboard/c/DashboardButton.tsx rename to src/ui/catalog/dashboard/c/DashboardButton.tsx diff --git a/src/ui/pages/dashboard/c/DashboardTableHeader.tsx b/src/ui/catalog/dashboard/c/DashboardTableHeader.tsx similarity index 92% rename from src/ui/pages/dashboard/c/DashboardTableHeader.tsx rename to src/ui/catalog/dashboard/c/DashboardTableHeader.tsx index 418068b..1eb173b 100644 --- a/src/ui/pages/dashboard/c/DashboardTableHeader.tsx +++ b/src/ui/catalog/dashboard/c/DashboardTableHeader.tsx @@ -7,8 +7,9 @@ import Checkbox from '@material-ui/core/Checkbox'; interface IDashboardTableHeaderProps extends React.ClassAttributes { isEditMode: boolean; editList: string[]; - selectAll: () => void; + selectAll: (tab: string) => void; unselectAll: () => void; + tab: string; } class DashboardTableHeader extends React.Component { @@ -24,9 +25,9 @@ class DashboardTableHeader extends React.Component { } private onCheckboxChange = (e, isAllSelected) => { - const {selectAll, unselectAll} = this.props; + const {selectAll, unselectAll, tab} = this.props; - isAllSelected ? selectAll() : unselectAll(); + isAllSelected ? selectAll(tab) : unselectAll(); this.setState({isAllSelected}); } diff --git a/src/ui/pages/dashboard/c/DashboardTableRow.tsx b/src/ui/catalog/dashboard/c/DashboardTableRow.tsx similarity index 76% rename from src/ui/pages/dashboard/c/DashboardTableRow.tsx rename to src/ui/catalog/dashboard/c/DashboardTableRow.tsx index 77fd97b..5fa1b10 100644 --- a/src/ui/pages/dashboard/c/DashboardTableRow.tsx +++ b/src/ui/catalog/dashboard/c/DashboardTableRow.tsx @@ -5,7 +5,6 @@ import {TableCell, TableRow} from 'ui/common/tables'; import PrettyDate from 'ui/common/time/PrettyDate'; import Permissions from 'ui/common/permission/Permissions'; import Markdown from 'ui/catalog/markdown'; -import {DatasetLink, DescriptorLink, DescriptorListLink} from 'ui/catalog/Links'; import Button from '@material-ui/core/Button'; import Checkbox from '@material-ui/core/Checkbox'; @@ -14,19 +13,6 @@ import FormControlLabel from '@material-ui/core/FormControlLabel'; // model import {PublishState} from 'model/common.model'; -const ResolveLink = ({tab, row, children}) => { - switch (tab) { - case 'datasets': - return { children }; - case 'descriptors': - return { children }; - case 'descriptorlists': - return { children }; - default: - return ({ children }); - } -}; - const StatusCell = ({publishState}: { publishState: PublishState}) => { switch (publishState) { case PublishState.PUBLISHED: @@ -62,7 +48,7 @@ export class DashboardTableRow extends React.Component { } public render() { - const {row, tab, index, isEditMode} = this.props; + const {row, tab, index, isEditMode, DataLink} = this.props; const { inEditList } = this.state; return ( @@ -80,16 +66,16 @@ export class DashboardTableRow extends React.Component { /> - { || (Untitled) } + { || (Untitled) } { row.owner.shortName } { row.createdDate && } { row.lastModifiedDate && } - + - + { row._permissions.manage && } diff --git a/src/ui/pages/dashboard/c/Filters.tsx b/src/ui/catalog/dashboard/c/Filters.tsx similarity index 97% rename from src/ui/pages/dashboard/c/Filters.tsx rename to src/ui/catalog/dashboard/c/Filters.tsx index 4a32c7b..b2f240a 100644 --- a/src/ui/pages/dashboard/c/Filters.tsx +++ b/src/ui/catalog/dashboard/c/Filters.tsx @@ -28,5 +28,6 @@ const DashboardFilters = ({handleSubmit, initialize, ...other}) => ( export default reduxForm({ enableReinitialize: true, + destroyOnUnmount: false, form: DASHBOARD_FILTERFORM, })(DashboardFilters); diff --git a/src/ui/pages/dashboard/c/MyDataTable.tsx b/src/ui/catalog/dashboard/c/MyDataTable.tsx similarity index 86% rename from src/ui/pages/dashboard/c/MyDataTable.tsx rename to src/ui/catalog/dashboard/c/MyDataTable.tsx index a3556c3..c10d67b 100644 --- a/src/ui/pages/dashboard/c/MyDataTable.tsx +++ b/src/ui/catalog/dashboard/c/MyDataTable.tsx @@ -19,8 +19,8 @@ import Paper from '@material-ui/core/Paper'; import Grid from '@material-ui/core/Grid'; import PagedLoader from 'ui/common/PagedLoader'; import Loading from 'ui/common/Loading'; -import DashboardActionsArea from 'ui/pages/dashboard/c/DashboardActionsArea'; -import DashboardTableHeader from 'ui/pages/dashboard/c/DashboardTableHeader'; +import DashboardActionsArea from 'ui/catalog/dashboard/c/DashboardActionsArea'; +import DashboardTableHeader from 'ui/catalog/dashboard/c/DashboardTableHeader'; const styles = (theme) => ({ filterSection: theme.leftPanel.root, @@ -34,6 +34,7 @@ interface IMyDataTableProps extends React.Props { onPaginationChange: (page: number, results: number, sortBy: string, dir?: string) => void; pageSort?: string; onFilter: (filter) => void; + renderDataLink: any; pagination: any; promiseListData: any; deleteAllAction: any; @@ -55,18 +56,6 @@ const defaultSortOptions = { owner: 'Owner', }; -const datasetSortOptions = { - ...defaultSortOptions, -}; - -const descriptorSortOptions = { - ...defaultSortOptions, -}; - -const descriptorListSortOptions = { - ...defaultSortOptions, -}; - function MyDataTable({ classes, tab, @@ -75,6 +64,7 @@ function MyDataTable({ onPaginationChange, onFilter, pagination, + renderDataLink, promiseListData, deleteAllAction, publishAllAction, @@ -93,14 +83,8 @@ function MyDataTable({ {title: 'Submit selected', action: publishAllAction }, {title: 'Approve selected', action: approveAllAction, admin: true }, {title: 'Unpublish selected', action: unpublishAllAction }, {title: 'Delete selected', action: deleteAllAction }, ]; - let sortOptions = defaultSortOptions; - - switch (tab) { - case 'datasets': sortOptions = datasetSortOptions; break; - case 'descriptors': sortOptions = descriptorSortOptions; break; - case 'descriptorlists': sortOptions = descriptorListSortOptions; break; - default: break; - } + const sortOptions = defaultSortOptions; + const renderTableRow = (row, index) => ( ); @@ -122,6 +107,7 @@ function MyDataTable({ const query = pagination.filterCode ? `?filter=${pagination.filterCode}` : ''; // console.log(`DF initialValues ${query}`, filter); + // TODO change `DashboardActionsArea` after merge tu genesys-ui return (
+ ) }> ({ - paginationDescriptorPage: state.descriptors.paged, + paginationDescriptorPage: state.descriptors.dashboard.paged, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/catalog/partner/SelectPartner.tsx b/src/ui/catalog/partner/SelectPartner.tsx index 3374a6e..9878048 100644 --- a/src/ui/catalog/partner/SelectPartner.tsx +++ b/src/ui/catalog/partner/SelectPartner.tsx @@ -6,7 +6,9 @@ import { bindActionCreators } from 'redux'; import {log} from 'utilities/debug'; import {Partner} from 'model/partner.model'; -import {loadPartners, loadMyPartners} from 'actions/partner'; +import {loadMyPartners} from 'partners/actions/dashboard'; +import {loadPartners} from 'partners/actions/public'; +import Markdown from 'ui/common/markdown'; import Input from '@material-ui/core/Input'; import FormControl from 'ui/common/forms/FormControl'; @@ -102,7 +104,9 @@ class SelectPartner extends React.Component { input={ } > { allowNull && Select partner } - { partners && partners.sort((a, b) => a.shortName.localeCompare(b.shortName)).map((p) => { p.shortName }{ p.name }) } + { partners && partners.sort((a, b) => a.shortName.localeCompare(b.shortName)).map((p) => + { p.shortName }) + } ); @@ -112,8 +116,8 @@ class SelectPartner extends React.Component { const mapStateToProps = (state, ownProps) => ({ partners: ownProps.onlyMine ? - state.partner.myPartners || null - : state.partner.paged && state.partner.paged.content || null, + state.partner.dashboard.myPartners || null + : state.partner.public.paged && state.partner.public.paged.content || null, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/catalog/vocabulary/VocabularyTermPicker.tsx b/src/ui/catalog/vocabulary/VocabularyTermPicker.tsx index 3ffc589..54aba54 100644 --- a/src/ui/catalog/vocabulary/VocabularyTermPicker.tsx +++ b/src/ui/catalog/vocabulary/VocabularyTermPicker.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import {connect} from 'react-redux'; import MaterialAutosuggest from 'ui/common/material-autosuggest'; import {bindActionCreators} from 'redux'; -import {autocomplete} from 'actions/vocabulary'; +import {autocomplete} from 'vocabulary/actions/public'; interface IVocabularyTermPickerProps extends React.ClassAttributes { vocabularyUuid: string; diff --git a/src/ui/common/PagedLoader.tsx b/src/ui/common/PagedLoader.tsx index 6429251..f5547e9 100644 --- a/src/ui/common/PagedLoader.tsx +++ b/src/ui/common/PagedLoader.tsx @@ -4,6 +4,7 @@ import {log} from 'utilities/debug'; import { Page } from 'model/common.model'; import * as VisibilitySensor from 'react-visibility-sensor'; import Loading from 'ui/common/Loading'; +import {ScrollToTopOnMount} from 'ui/common/page/scrollers'; interface IProps extends React.Props { paged: Page; @@ -16,89 +17,51 @@ interface IProps extends React.Props { export default class PagedLoader extends React.Component, any> { - public constructor(props: any) { - super(props); - const { paged: { number: pageNumber, content: newContent } } = this.props; - this.state = { - list: [ ...newContent ], - pageNumber, - loading: false, - }; - } - public componentWillMount() { // ? } - public componentWillReceiveProps(nextProps) { - // log('nextProps', nextProps); - const { paged: { number: pageNumber, content: newContent } } = nextProps; - - if (newContent) { - this.setState({ - ...this.state, - list: [ ...newContent ], - pageNumber, - loading: false, - }); - } - } - private endOfListVisibilityChange = (isVisible: boolean): void => { const { paged, loadPage } = this.props; - const { list, pageNumber, loading } = this.state; // log(`Visibility ${isVisible}`); if (paged && isVisible) { // we should load some stuff - if (! loading && paged.totalElements > list.length) { - log('Calling for next page', pageNumber + 1); + if (paged && paged.content && paged.totalElements > paged.content.length) { + log('Calling for next page', paged.number + 1); - this.setState({ - ...this.state, - loading: true, - }); - - loadPage(pageNumber + 1, paged.size) - .then((nextPage) => { - log('Received next page', nextPage); - this.setState({ - ...this.state, - list: [ ...this.state.list, ...nextPage.content ], - pageNumber: nextPage.number, - loading: false, - }); - // log('State', this.state, this.state.list); - }); + loadPage(paged.number + 1, paged.size); } } } public render() { - const { list, loading } = this.state; - const { itemRenderer, loadingIndicator, colSpan, roughItemHeight } = this.props; + const { paged, itemRenderer, loadingIndicator, colSpan, roughItemHeight } = this.props; - if (! list || list.length === 0) { + if (! paged || ! paged.content || paged.content.length === 0) { return null; } - // log(`Rendering ${list.length} items`); + console.log(`Rendering ${paged.content.length} items`); const inTable = colSpan ? true : false; - const visibilityOffset = (roughItemHeight && roughItemHeight || 50) * 10; + const visibilityOffset = (roughItemHeight && roughItemHeight || 50) * (paged.size * .4); const myLoadingIndicator = loadingIndicator || ; // log(`Visibility offset bottom: ${-visibilityOffset}`); const result = [ - ...list.map((item: T, index) => itemRenderer(item, index)), + , + ...paged.content.map((item: T, index) => itemRenderer(item, index)), inTable ? ( - - ) : ( + + + + ) : (
- { loading ? myLoadingIndicator : null } + { ! paged.last ? myLoadingIndicator : null }
), ]; diff --git a/src/ui/common/stepper/StepNavigation.tsx b/src/ui/common/stepper/StepNavigation.tsx index 61cf5e6..96a6a02 100644 --- a/src/ui/common/stepper/StepNavigation.tsx +++ b/src/ui/common/stepper/StepNavigation.tsx @@ -69,7 +69,7 @@ class StepNavigation extends React.Component { protected getStepId = (location) => { const {steps} = this.props; const path = location.pathname.split('/').pop(); - return steps.find((e) => e.link.endsWith(path)).id; + return steps.find((e) => e.path.endsWith(path)).id; } public render() { diff --git a/src/ui/common/stepper/progress-menu/index.tsx b/src/ui/common/stepper/progress-menu/index.tsx index f0b53cb..383a5fd 100644 --- a/src/ui/common/stepper/progress-menu/index.tsx +++ b/src/ui/common/stepper/progress-menu/index.tsx @@ -47,7 +47,7 @@ class ProgressMenu extends React.Component { key={ i } disabled={ disabled } onClick={ onGotoStep(i + 1) } - active={ step.link.endsWith(link) } + active={ step.path.endsWith(link) } index={ i } name = { step.name } /> diff --git a/src/ui/layout/Header/UserMenuComponent.tsx b/src/ui/layout/Header/UserMenuComponent.tsx index 5fe9676..a47cf79 100644 --- a/src/ui/layout/Header/UserMenuComponent.tsx +++ b/src/ui/layout/Header/UserMenuComponent.tsx @@ -112,7 +112,6 @@ class UserMenuComponent extends React.Component { > { t('menu.My Dashboard') } { t('menu.My profile') } - { t('menu.Accessions') } { t('menu.Crops') } { t('menu.Controlled vocabularies') } UI Tests diff --git a/src/ui/pages/dashboard/DashboardPage.tsx b/src/ui/pages/dashboard/DashboardPage.tsx deleted file mode 100644 index f214363..0000000 --- a/src/ui/pages/dashboard/DashboardPage.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { parse } from 'query-string'; - -import { filterCodeToUrl } from 'actions/filterCode'; -import { setPageTitle } from 'actions/pageTitle'; -import { - setEditMode, addToEditList, removeFromEditList, onPageChange, approveAll, deleteAll, publishAll, unpublishAll, - listMyDatasets, listMyDescriptors, listMyDescriptorLists, - promiseListMyDescriptors, promiseListMyDescriptorLists, promiseListMyDatasets, selectAll, unselectAll, -} from 'actions/dashboard'; - -import { BaseMyDataPage } from './MyDataPage'; -import MyDataTable from './c/MyDataTable'; -import DashboardActionsButton from './c/DashboardActionsButton'; - -interface IAdminDashProps extends React.ClassAttributes { - setPageTitle: (title: string) => void; - title: string; - history: any; -} - -class AdministrationDashboard extends BaseMyDataPage { - constructor(props) { - super(props); - const { setPageTitle, title } = this.props; - setPageTitle(title); - } - - public goToNewDataset = () => { - this.props.createDataset(); - } - - public goToNewDescriptorForm = () => { - this.props.history.push('/descriptor/edit'); - } - - public goToDataInPreparation = () => { - this.props.history.push('/dashboard/data-in-preparation'); - } - - public goToPartners = () => { - this.props.history.push('/partners'); - } - - public goToPublishedData = () => { - this.props.history.push('/dashboard/data-published'); - } - - public render() { - const {tab, paged, pagination, addToEditList, removeFromEditList, isEditMode, setEditMode, editList } = this.props; - const actionHandlers = this.getActionHandlers(tab); - - return ( -
- - -
- ); - } -} - -const mapStateToProps = (state, ownProps) => ({ - pagination: { - page: +parse(ownProps.location.search).p || 0, // current page - size: +parse(ownProps.location.search).l || 100, // page size - sort: parse(ownProps.location.search).s || 'lastModifiedDate', // page sort - dir: parse(ownProps.location.search).d || 'DESC', // page sort directions - filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, - filterCode: parse(ownProps.location.search).filter, - }, - title: ownProps.route.extraProps.title, // route-configured - tab: ownProps.match.params.tab || 'datasets', // current tab, or ownProps.location.pathname - paged: state.dashboard.paged, - editList: state.dashboard.selected, - isEditMode: state.dashboard.isEditMode, -}); - -const mapDispatchToProps = (dispatch) => bindActionCreators({ - listDatasets: listMyDatasets, - listDescriptors: listMyDescriptors, - listDescriptorLists: listMyDescriptorLists, - addToEditList, - removeFromEditList, - onPageChange, - deleteAll, - publishAll, - approveAll, - unpublishAll, - selectAll, - unselectAll, - setEditMode, - promiseListMyDatasets, - promiseListMyDescriptors, - promiseListMyDescriptorLists, - setPageTitle, - filterCodeToUrl, -}, dispatch); - -export default connect(mapStateToProps, mapDispatchToProps)(AdministrationDashboard); diff --git a/src/ui/pages/dashboard/MyDataPage.tsx b/src/ui/pages/dashboard/MyDataPage.tsx deleted file mode 100644 index 944df19..0000000 --- a/src/ui/pages/dashboard/MyDataPage.tsx +++ /dev/null @@ -1,303 +0,0 @@ -import * as React from 'react'; -import {connect} from 'react-redux'; -import {bindActionCreators} from 'redux'; -import update from 'immutability-helper'; - -import { Dataset } from 'model/dataset.model'; -import {Descriptor, DescriptorList} from 'model/descriptor.model'; -import {Page} from 'model/common.model'; -import { parse } from 'query-string'; - -import { filterCodeToUrl } from 'actions/filterCode'; -import { deleteDatasetPromise, publishDatasetPromise, unpublishDatasetPromise, approveDatasetPromise} from 'actions/dataset'; -import { deleteDescriptorPromise, approveDescriptorPromise, publishDescriptorPromise, unpublishDescriptorPromise} from 'actions/descriptors'; -import { deleteDescriptorListPromise, publishDescriptorListPromise, unpublishDescriptorListPromise, approveDescriptorListPromise} from 'actions/descriptorList'; -import {setPageTitle} from 'actions/pageTitle'; -import { - setEditMode, addToEditList, deleteAll, publishAll, approveAll, removeFromEditList, unpublishAll, onPageChange, - listMyDatasets, listMyDescriptors, listMyDescriptorLists, - promiseListMyDescriptors, promiseListMyDescriptorLists, promiseListMyDatasets, - selectAll, unselectAll, -} from 'actions/dashboard'; - -import ContentHeaderWithButton from 'ui/common/heading/ContentHeaderWithButton'; -import BackButton from 'ui/common/buttons/BackButton'; -import MyDataTable from './c/MyDataTable'; -import DashboardActionsButton from './c/DashboardActionsButton'; - -interface IDataPublishedContainerProps extends React.ClassAttributes { - title: string; - tab?: string; - pagination: any; - paged: Page | Page | Page; - preFilter?: object; - basePath: string; - filterCodeToUrl: any; - listDescriptorLists: any; - listDescriptors: any; - listDatasets: any; - promiseListMyDatasets: any; - promiseListMyDescriptors: any; - promiseListMyDescriptorLists: any; - setPageTitle: (title: string) => void; - addToEditList: (item: Dataset | Descriptor | DescriptorList) => void; - removeFromEditList: (item: Dataset | Descriptor | DescriptorList) => void; - onPageChange: () => void; - deleteAll: (deleteOne: (page?, results?, sortBy?, filter?, order?) => Promise | Promise | Promise) => void; - publishAll: (publishOne: (page?, results?, sortBy?, filter?, order?) => Promise | Promise | Promise) => void; - setEditState: (state: boolean) => void; - editList: string[]; - isEditMode: boolean; -} - -class BaseMyDataPage extends React.Component { - - // SSR only - protected static needs = [ - ({ params: { tab }, search }) => { - const pageCurrent = parse(search).p || 0; - const pageSize = parse(search).l || 100; - const pageSort = parse(search).s; - const pageDir = parse(search).d; - const filterCode = parse(search).filter; - switch (tab) { - case 'descriptors': return listMyDescriptors(pageCurrent, pageSize, pageSort, filterCode || {}, pageDir); - case 'descriptorlists': return listMyDescriptorLists(pageCurrent, pageSize, pageSort, filterCode || {}, pageDir); - case 'datasets': - default: return listMyDatasets(pageCurrent, pageSize, pageSort, filterCode || {}, pageDir); - } - }, - ]; - - constructor(props) { - super(props); - this.state = {tab: '', pagination: props.pagination }; - } - - public componentDidMount() { - // noop - } - - public componentWillMount() { - const { pagination, tab, paged } = this.props; - // console.log(`willM ${filterCode}`, filters[filterCode]); - - - - this.setState({tab}); - if (!paged) { - this.loadData(null, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); - } - } - - public componentWillUnmount() { - // noop - } - - public componentWillReceiveProps(nextProps) { - const {filterCodeToUrl, paged} = this.props; - if (paged) { - filterCodeToUrl(paged.filterCode); - } - - const {tab} = nextProps; - if (tab !== this.state.tab) { - const { pagination } = nextProps; - this.loadData(null, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); - } - } - - public componentWillUpdate(nextProps, nextState) { - // noop - } - - public componentDidUpdate() { - // noop - } - - protected getActionHandlers(tab) { - const {promiseListMyDatasets, promiseListMyDescriptors, promiseListMyDescriptorLists, - deleteAll, publishAll, approveAll, unpublishAll, selectAll, unselectAll} = this.props; - - let promiseListData; - let deleteAllAction; - let publishAllAction; - let approveAllAction; - let unpublishAllAction; - - switch (tab) { - case 'descriptorlists': - promiseListData = promiseListMyDescriptorLists; - deleteAllAction = () => { deleteAll(deleteDescriptorListPromise); }; - publishAllAction = () => { publishAll(publishDescriptorListPromise); }; - approveAllAction = () => { approveAll(approveDescriptorListPromise); }; - unpublishAllAction = () => { unpublishAll(unpublishDescriptorListPromise); }; - break; - case 'descriptors': - promiseListData = promiseListMyDescriptors; - deleteAllAction = () => { deleteAll(deleteDescriptorPromise); }; - publishAllAction = () => { publishAll(publishDescriptorPromise); }; - approveAllAction = () => { approveAll(approveDescriptorPromise); }; - unpublishAllAction = () => { unpublishAll(unpublishDescriptorPromise); }; - break; - case 'datasets': - default: - promiseListData = promiseListMyDatasets; - deleteAllAction = () => { deleteAll(deleteDatasetPromise); }; - publishAllAction = () => { publishAll(publishDatasetPromise); }; - approveAllAction = () => { approveAll(approveDatasetPromise); }; - unpublishAllAction = () => { unpublishAll(unpublishDatasetPromise); }; - break; - } - return { promiseListData, deleteAllAction, publishAllAction, unpublishAllAction, approveAllAction, selectAll, unselectAll }; - } - - protected getPaged(props) { - switch (props.tab) { - case 'descriptorlists': return props.descriptorLists; - case 'descriptors': return props.descriptors; - case 'datasets': - default: return props.datasets; - } - } - - protected onPaginationChange = (page, results, sortBy, dir) => { - const { history, location } = this.props; - const params = new URLSearchParams(location.search); - params.set('p', page); - params.set('l', results); - if (sortBy) { - params.set('s', sortBy); - } else { - params.delete('s'); - } - if (dir) { - params.set('d', dir); - } else { - params.delete('d'); - } - - location.search = params.toString(); - history.push(location); - const { tab } = this.props; - this.loadData(null, tab, page, results, sortBy, dir); - } - - protected onFilter = (newFilters) => { - this.setState({...this.state, filter: newFilters}); - - const {tab, pagination } = this.props; - this.loadData(newFilters, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); - } - - protected loadData(filter, tab, page, size, sortBy, dir) { - - const {listDatasets, listDescriptors, listDescriptorLists, preFilter, pagination, onPageChange } = this.props; - const newFilters = filter && { ...preFilter, ...filter }; - // console.log(`Filters code=${filterCode}`, newFilters, preFilter); - - if (newFilters || this.state.tab !== tab || this.state.pagination.page !== page || this.state.pagination.size !== size || this.state.pagination.sort !== sortBy || this.state.pagination.dir !== dir) { - // console.log('Reloading'); - onPageChange(); - this.setState(update(this.state, { - tab: {$set: tab}, - pagination: { - page: {$set: page}, - size: {$set: size}, - sort: {$set: sortBy}, - dir: {$set: dir}, - filterCode: {$set: pagination.filterCode}, - }, - })); - - switch (tab) { - case 'descriptors': listDescriptors(page, size, sortBy, newFilters || pagination.filterCode, dir); break; - case 'descriptorlists': listDescriptorLists(page, size, sortBy, newFilters || pagination.filterCode, dir); break; - case 'datasets': - default: listDatasets(page, size, sortBy, newFilters || pagination.filterCode, dir); break; - } - } else { - // noop - } - } -} - -class DP extends BaseMyDataPage { - - constructor(props) { - super(props); - const { title, setPageTitle } = this.props; - setPageTitle(title); - } - - public render() { - const {title, tab, basePath, pagination, addToEditList, removeFromEditList, isEditMode, setEditMode, editList, paged } = this.props; - const actionHandlers = this.getActionHandlers(tab); - - return ( -
- }/> - - -
- ); - } -} - -const mapStateToProps = (state, ownProps) => ({ - pagination: { - page: +parse(ownProps.location.search).p || 0, // current page - size: +parse(ownProps.location.search).l || 100, // page size - sort: parse(ownProps.location.search).s, // page sorts - dir: parse(ownProps.location.search).d, // page sort directions - filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, - filterCode: parse(ownProps.location.search).filter, - }, - title: ownProps.route.extraProps.title || 'Data', // route-configured - basePath: ownProps.route.extraProps.basePath, // route-configured - preFilter: ownProps.route.extraProps.filter || {}, // route-configured - tab: ownProps.match.params.tab || 'datasets', // current tab, or ownProps.location.pathname - paged: state.dashboard.paged, - editList: state.dashboard.selected, - isEditMode: state.dashboard.isEditMode, -}); - -const mapDispatchToProps = (dispatch) => bindActionCreators({ - listDatasets: listMyDatasets, - listDescriptors: listMyDescriptors, - listDescriptorLists: listMyDescriptorLists, - addToEditList, - removeFromEditList, - onPageChange, - deleteAll, - publishAll, - approveAll, - unpublishAll, - selectAll, - unselectAll, - setEditMode, - promiseListMyDatasets, - promiseListMyDescriptors, - promiseListMyDescriptorLists, - setPageTitle, - filterCodeToUrl, -}, dispatch); - -const MyDataPage = connect( - mapStateToProps, mapDispatchToProps, -)(DP); - -export {MyDataPage as default, BaseMyDataPage}; diff --git a/src/ui/pages/dataset/dataset-stepper/steps.ts b/src/ui/pages/dataset/dataset-stepper/steps.ts deleted file mode 100644 index 8065986..0000000 --- a/src/ui/pages/dataset/dataset-stepper/steps.ts +++ /dev/null @@ -1,49 +0,0 @@ -const steps = [ - { - id: 1, - name: 'Basic information', - link: 'edit', - }, - { - id: 2, - name: 'Dataset attachments', - link: 'edit/files', - }, - { - id: 3, - name: 'Dataset creators', - link: 'edit/dataset-creator', - }, - { - id: 4, - name: 'Location and timing', - link: 'edit/location', - }, - { - id: 5, - name: 'List of accessions', - link: 'edit/list-of-accessions', - }, - { - id: 6, - name: 'Select descriptors in batch', - link: 'edit/pasting-traits', - }, - { - id: 7, - name: 'Browse and select descriptors', - link: 'edit/traits-observed', - }, - { - id: 8, - name: 'Reorder descriptors', - link: 'edit/reorder-descriptors', - }, - { - id: 9, - name: 'Review and publish', - link: 'edit/review-and-publish', - }, -]; - -export default steps; diff --git a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps.ts b/src/ui/pages/descriptorlist/descriptorlist-stepper/steps.ts deleted file mode 100644 index 50c5482..0000000 --- a/src/ui/pages/descriptorlist/descriptorlist-stepper/steps.ts +++ /dev/null @@ -1,30 +0,0 @@ - -const steps = [ - { - id: 1, - name: 'Basic information', - link: 'edit', - }, - { - id: 2, - name: 'Select registered descriptors', - link: 'edit/select-descriptors', - }, - { - id: 3, - name: 'Import descriptors', - link: 'edit/import-descriptors', - }, - { - id: 4, - name: 'Reorder descriptors', - link: 'edit/reorder-descriptors', - }, - { - id: 5, - name: 'Review and publish', - link: 'edit/review-and-publish', - }, -]; - -export default steps; diff --git a/src/ui/pages/genesys/BrowsePage.tsx b/src/ui/pages/genesys/BrowsePage.tsx deleted file mode 100644 index 320caee..0000000 --- a/src/ui/pages/genesys/BrowsePage.tsx +++ /dev/null @@ -1,408 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { withStyles } from '@material-ui/core/styles'; - -import {log} from 'utilities/debug'; -import { parse } from 'query-string'; - -import { listCrops } from 'actions/crop'; -import { listAccessions, loadGenesysDescriptors } from 'actions/genesys'; -import { Descriptor, DescriptorList, DescriptorListExtra } from 'model/descriptor.model'; -import { VocabularyTerm } from 'model/vocabulary.model'; - -import { Page, Pagination } from 'model/common.model'; - -import Loading from 'ui/common/Loading'; -import PaginationComponent from 'ui/common/pagination'; -import GenesysBrowseFilters from './c/Filters'; -import PrettyFilters from 'ui/common/filter/PrettyFilters'; -import DOI from 'ui/common/DOI'; - -import { MultiGrid as VMultiGrid, AutoSizer, InfiniteLoader } from 'react-virtualized'; - -import Grid from '@material-ui/core/Grid'; - -const styles = (theme) => ({ - filterSection: theme.leftPanel.root, - BodyGrid: { - width: '100%', - border: '1px solid #e0e0e0', - }, - tableCell: { - padding: '.5rem 1rem', - borderRight: 'dotted 1px White', - borderBottom: 'solid 1px White', - textOverflow: 'ellipsis' as 'ellipsis', - whiteSpace: 'nowrap' as 'nowrap', - display: 'inline-block' as 'inline-block', - overflow: 'hidden' as 'hidden', - }, - tableHeaderCell: { - fontWeight: 'bold' as 'bold', - color: 'White', - borderRight: 'dotted 1px #a0d457', - }, - evenRow: { - backgroundColor: '#f3f2ee', - }, - oddRow: { - backgroundColor: '#f8f7f5', - }, - noCells: { - position: 'absolute' as 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - display: 'flex' as 'flex', - alignItems: 'center' as 'center', - justifyContent: 'center' as 'center', - fontSize: '1em', - color: '#bdbdbd', - }, -}); - -interface IBrowsePageProps extends React.ClassAttributes { - classes?: any; - router: any; - - pagination?: Pagination; - listCrops: any; - listAccessions: any; - loadGenesysDescriptors: any; - history: any; - location: any; -} - - -const SORT_OPTIONS = null; - -// Page to browse and filter descriptor lists -class BrowsePage extends React.Component { - - protected static needs = [ - loadGenesysDescriptors, - ]; - - - public constructor(props: any) { - super(props); - this.state = { - paged: null, - filter: {}, - displayedColumns: [ - { path: 'acceNumb', width: 200, title: 'Accession number' }, - { path: 'seqNo', width: 100, className: 'text-right', title: 'Seq' }, - { path: 'taxonomy', width: 400, title: 'Scientific name', renderer: (data) => { - // console.log('Rendering taxonomy', data.taxonomy.sciNameHtml); - return ; - } }, - { path: 'acceName', width: 400, title: 'Accession name' }, - { path: 'doi', width: 200, title: 'DOI', renderer: (data) => { - // console.log('Rendering DOI', data.doi); - return data.doi ? : null; - } }, - { path: 'institute.code', width: 100, title: 'Institute code', renderer: (data) => data.institute.code }, - { path: 'institute.name', width: 400, title: 'Institute name', renderer: (data) => data.institute.fullName }, - { path: 'cropName', width: 200, title: 'Crop' }, - { path: 'sampStat', width: 300, title: 'Biological status of sample', renderer: (data) => data.sampStat && this.decode(data.sampStat, 'sampStat') }, - ], - list: [], - }; - - this._cellRenderer = this._cellRenderer.bind(this); - this._getColumnWidth = this._getColumnWidth.bind(this); - this._getRowClassName = this._getRowClassName.bind(this); - // this._getRowHeight = this._getRowHeight.bind(this); - this._noContentRenderer = this._noContentRenderer.bind(this); - } - - - public componentWillMount() { - const {pagination, listCrops, loadGenesysDescriptors} = this.props; - - log(`BrowsePage.componentWillMount...`, this.props); - listCrops(); - - // Descriptors - loadGenesysDescriptors() - .then((genesysMcpd: DescriptorList) => { - // console.log('Genesys descriptors', g); - const mapping: Map = new Map(); - const decoder: Map> = new Map>(); - if (genesysMcpd && genesysMcpd.extras) { - console.log('Genesys PGR mapping', genesysMcpd.extras[DescriptorListExtra.JSON_MAPPING]); - for (const m of genesysMcpd.extras[DescriptorListExtra.JSON_MAPPING]) { - const d = genesysMcpd.descriptors.find((d) => d.uuid === m.uuid); - mapping.set(m.jsonPath, d); - if (d && d.terms) { - decoder.set(m.jsonPath, d.terms.reduce((codes, term) => codes.set(term.code, term), new Map())); - } - } - } - console.log(mapping, decoder); - this.setState({ ...this.state, mapping, decoder }); - return genesysMcpd; - }); - - // if (! paged) { - log('Loading genesys accessions'); - this.fetchAccessions(this.state.filter, pagination.page, pagination.size); - // } - } - - public componentWillReceiveProps(nextProps) { - const {pagination: oldPagination} = this.props; - const {pagination} = nextProps; - - if (! oldPagination.equals(pagination)) { - log('Paginations differ!', pagination); - this.fetchAccessions(this.state.filter, pagination.page, pagination.size); - } - } - - protected onPaginationChange = (page, results, sortBy, dir) => { - log('onPaginationChange', page, results, sortBy); - const { history, location } = this.props; - const params = new URLSearchParams(location.search); - params.set('p', page); - params.set('l', results); - if (sortBy) { - params.set('s', sortBy); - } else { - params.delete('s'); - } - if (dir) { - params.set('d', dir); - } else { - params.delete('d'); - } - - location.search = params.toString(); - history.push(location); - } - - protected applyFilters = (newFilters) => { - const {pagination} = this.props; - - log('Applying new filter', newFilters); - this.fetchAccessions(newFilters, pagination.page, pagination.size); - } - - private fetchAccessions(filter, page, size) { - const {listAccessions} = this.props; - console.log(`Fetching p=${page} l=${size}`, filter); - listAccessions(filter, page, size) - .then((data: Page) => { - this.setState((state) => ({state, paged: data, filter, list: data.content })); - }) - .catch((error) => { - console.log(error); - }); - } - - private htmlTaxa(taxonomyHtml: string) { - return { __html: taxonomyHtml }; - } - - private decode(val, path): string { - if (! val) { - return null; - } - const { decoder } = this.state; - if (! decoder) { - return val; - } - - const terms = decoder.get(path); - // console.log(path, terms); - if (terms) { - const term = terms.get(`${val}`); - // console.log(val, term); - return term ? term.title : val; - } - return val; - } - - private isRowLoaded = ({ index }) => { - const {list, paged} = this.state; - return paged.last || index < list.length; - } - - protected loadMoreRows = () => { - const {listAccessions, pagination} = this.props; - const {filter, paged} = this.state; - - listAccessions(filter, paged.number + 1, pagination.size) - .then((data: Page) => { - this.setState((state) => ({...state, paged: data, filter, list: state.list.concat(data.content) })); - }); - } - - public render() { - const { classes } = this.props; - const { paged, filter, list } = this.state; - - const stillLoading: boolean = (! paged || ! paged.content); - - return ( - - - - - - - - - - - - - - { stillLoading ? : - - { this._infiniteLoaderChildFunction } - - } - - - - - - - - ); - } - - private _onRowsRendered = (obj) => { - // this method defined later - } - - private _onSectionRendered = ({ rowStartIndex, rowStopIndex }) => { - this._onRowsRendered({ - startIndex: rowStartIndex, - stopIndex: rowStopIndex, - }); - } - - private _infiniteLoaderChildFunction = ({ onRowsRendered, registerChild }) => { - this._onRowsRendered = onRowsRendered; - - const { classes } = this.props; - const { displayedColumns, paged, list } = this.state; - - return ( - - { ({ width }) => ( - - ) } - - ); - } - - private _cellRenderer({columnIndex, key, rowIndex, style}) { - if (rowIndex === 0) { - return this._headerRenderer({columnIndex, key, style}); - } - const { classes } = this.props; - const { list, displayedColumns } = this.state; - const rowClass = this._getRowClassName(rowIndex); - const cellClass = displayedColumns[columnIndex].className || ''; - - return list[rowIndex - 1] ? ( -
- { displayedColumns[columnIndex].renderer ? - displayedColumns[columnIndex].renderer(list[rowIndex - 1]) - : - list[rowIndex - 1][displayedColumns[columnIndex].path] - } -
- ) : ( -
- ); - } - - private _headerRenderer({columnIndex, key, style}) { - const { classes } = this.props; - const { displayedColumns } = this.state; - const cellClass = displayedColumns[columnIndex].className || ''; - - // console.log(`c ${rowIndex},${columnIndex}`, paged.content[rowIndex]); - return ( -
- { displayedColumns[columnIndex].title } -
- ); - } - - private _noContentRenderer() { - const { classes } = this.props; - return
No cells
; - } - - private _getColumnWidth({index}) { - const { displayedColumns } = this.state; - return displayedColumns[index].width; - } - - private _getRowClassName(row) { - const { classes } = this.props; - return row % 2 === 0 ? classes.evenRow : classes.oddRow; - } -} - -const mapStateToProps = (state, ownProps) => ({ - pagination: new Pagination({ - page: +parse(ownProps.location.search).p || 0, // current page - size: +parse(ownProps.location.search).l || 50, // page size - sort: parse(ownProps.location.search).s, // page sorts - dir: parse(ownProps.location.search).d, // page sort directions - filter: null, - }), -}); - -const mapDispatchToProps = (dispatch) => bindActionCreators({ - listCrops, - listAccessions, - loadGenesysDescriptors, -}, dispatch); - -export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(BrowsePage)); diff --git a/src/ui/pages/genesys/DisplayPage.tsx b/src/ui/pages/genesys/DisplayPage.tsx deleted file mode 100644 index 67d503b..0000000 --- a/src/ui/pages/genesys/DisplayPage.tsx +++ /dev/null @@ -1,217 +0,0 @@ - -import * as React from 'react'; -import {connect} from 'react-redux'; -import {bindActionCreators} from 'redux'; -import { withStyles } from '@material-ui/core/styles'; - -import {log} from 'utilities/debug'; - -import { loadDescriptorList, publishDescriptorList, deleteDescriptorList } from 'actions/descriptorList'; -import { DescriptorList, Descriptor } from 'model/descriptor.model'; - -import confirm from 'utilities/confirmAlert'; -import Authorize from 'ui/common/authorized/Authorize'; -import Loading from 'ui/common/Loading'; -import Markdown from 'ui/catalog/markdown'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; -import ContentHeaderWithButton from 'ui/common/heading/ContentHeaderWithButton'; -import { PartnerLink, DescriptorListLink, CropLink, ExternalLink } from 'ui/catalog/Links'; -import { Properties, PropertiesItem } from 'ui/catalog/Properties'; - -import Grid from '@material-ui/core/Grid'; -import Card, {CardHeader, CardContent, CardActions } from 'ui/common/Card'; -import Section from 'ui/common/layout/Section'; -import Divider from '@material-ui/core/Divider'; -import Button from '@material-ui/core/Button'; - -interface IDescriptorListPageProps extends React.ClassAttributes { - classes: any; - uuid?: string; - descriptorList?: DescriptorList; - loading?: any; - loadDescriptorList: any; - publishDescriptorList: any; - deleteDescriptorList: any; -} - -const styles = (theme) => ({ - filterSection: theme.leftPanel.root, - contentContainer: { - backgroundColor: '#E8E5E0', - padding: '1.5rem', - }, - card: { - marginBottom: '1.5rem', - }, - propertiesContainer: { - marginTop: '20px', - marginBottom: '20px', - }, - propertiesRow: { - /* tslint:disable */ - 'marginTop': '1px', - 'marginBottom': '1px', - '& > *:first-child': { - borderRight: 'solid 1px white', - }, - '&:nth-child(even)': { - backgroundColor: '#f8f7f5', - }, - '&:nth-child(odd)': { - backgroundColor: '#f3f2ee', - }, - /* tslint:enable */ - }, -}); - -// Page to edit a descriptor list -class DescriptorListPage extends React.Component { - - protected static needs = [ - ({ params: { uuid } }) => loadDescriptorList(uuid), - ]; - - public componentWillMount() { - const {uuid, loading, loadDescriptorList} = this.props; - - if (uuid && (! loading || loading.uuid !== uuid)) { - loadDescriptorList(uuid); - } - } - - private onPublish = (e) => { - const {descriptorList, publishDescriptorList} = this.props; - - confirm(Publish { descriptorList.title }?, { - description: `After publishing the descriptor list no changes are permitted, a new version must be created.`, - confirmLabel: 'Publish', - abortLabel: 'Cancel', - }).then(() => { - log('Publishing descriptor list', descriptorList); - publishDescriptorList(descriptorList); - }).catch(() => { - // don't - }); - } - - private onUnpublish = (e) => { - const {descriptorList, publishDescriptorList} = this.props; - - confirm(Unpublish { descriptorList.title }?, { - // description: `Deleting the descriptor is only possible when there is no associated data.`, - confirmLabel: 'Unpublish', - abortLabel: 'Cancel', - }).then(() => { - log('Publishing descriptor list', descriptorList); - publishDescriptorList(descriptorList, false); - }).catch(() => { - // don't - }); - } - - private onDelete = (e) => { - const {descriptorList, deleteDescriptorList} = this.props; - - confirm(Delete { descriptorList.title }?, { - description: `Deleting the descriptor is only possible when there is no associated data.`, - confirmLabel: 'Delete', - abortLabel: 'Cancel', - }).then(() => { - deleteDescriptorList(descriptorList); - }).catch(() => { - // don't - }); - } - - public render() { - const {classes, uuid, descriptorList } = this.props; - - const stillLoading: boolean = (! descriptorList || (uuid && (descriptorList.uuid !== uuid))); - - return ( -
- - { stillLoading ? : - - - - - { descriptorList.versionTag } - ) } /> - - - { ! descriptorList.published &&

This descriptor list is not yet published!

} - { descriptorList.description && } - - - { descriptorList.crop && - } - - { descriptorList.publisher || Not specified } - - { descriptorList.url && - { { descriptorList.url } } } - - { descriptorList.bibliographicCitation && - { descriptorList.bibliographicCitation } } - - { (descriptorList.publisher === null && descriptorList.owner) && - } - - { descriptorList.versionTag } - -
- - { (descriptorList._permissions.write || descriptorList._permissions.delete) && ( - - { descriptorList.published ? - - - - : - - } - { ! descriptorList.published && descriptorList._permissions.write && } - { ! descriptorList.published && descriptorList._permissions.delete && } - - - ) } - - - - - { descriptorList.descriptors.map((descriptor: Descriptor) => ( -
- -
- )) } -
- -
- { descriptorList.descriptors.map((descriptor: Descriptor) => ( - - )) } -
-
- - - } -
- ); - } -} - -const mapStateToProps = (state, ownProps) => ({ - uuid: ownProps.match.params.uuid, - descriptorList: state.descriptorList.currentDescriptorList, - loading: state.descriptorList.loading, -}); - -const mapDispatchToProps = (dispatch) => bindActionCreators({ - loadDescriptorList, - publishDescriptorList, - deleteDescriptorList, -}, dispatch); - -export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(DescriptorListPage)); diff --git a/src/ui/pages/genesys/c/Filters.tsx b/src/ui/pages/genesys/c/Filters.tsx deleted file mode 100644 index bdb154e..0000000 --- a/src/ui/pages/genesys/c/Filters.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import * as React from 'react'; -import { reduxForm } from 'redux-form'; - -import { GENESYSBROWSE_FILTERFORM } from 'constants/genesys'; - -import FiltersBlock from 'ui/common/filter/FiltersBlock'; -import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; -// import StringFilter from 'ui/common/filter/StringFilter'; -import StringArrFilter from 'ui/common/filter/StringArrFilter'; -// import CropFilter from 'ui/catalog/crop/CropFilter'; - -// -// -// - -const GenesysBrowseFilters = ({handleSubmit, initialize, ...other}) => ( - - - - - - - - - - - - -); - -export default reduxForm({ - enableReinitialize: true, - form: GENESYSBROWSE_FILTERFORM, -})(GenesysBrowseFilters); diff --git a/src/ui/routes.tsx b/src/ui/routes.tsx index 89894e1..541a762 100644 --- a/src/ui/routes.tsx +++ b/src/ui/routes.tsx @@ -5,51 +5,18 @@ import Wrapper from 'ui/catalog/Wrapper'; import CropBrowsePage from './pages/crop/BrowsePage'; import CropEditPage from './pages/crop/EditPage'; -import PartnerBrowsePage from './pages/partner/BrowsePage'; -import PartnerDisplayPage from './pages/partner/DisplayPage'; -import PartnerEditPage from './pages/partner/EditPage'; - -import DatasetSuggestionsPage from './pages/search/SuggestionsPage'; -import DatasetBrowsePage from './pages/dataset/BrowsePage'; -import DatasetDisplayPage from './pages/dataset/DisplayPage'; -import DatasetStepper from './pages/dataset/dataset-stepper'; - -import DescriptorBrowsePage from './pages/descriptor/BrowsePage'; -import DescriptorDisplayPage from './pages/descriptor/DisplayPage'; -import DescriptorEditPage from './pages/descriptor/EditPage'; - -import DescriptorListDisplayPage from './pages/descriptorlist/DisplayPage'; -import DescriptorListBrowsePage from './pages/descriptorlist/BrowsePage'; -import DescriptorListStepper from 'ui/pages/descriptorlist/descriptorlist-stepper'; -import DescriptorListBasicStep from 'ui/pages/descriptorlist/descriptorlist-stepper/steps/basic-info'; -import SelectDescriptorsStep from 'ui/pages/descriptorlist/descriptorlist-stepper/steps/select'; -import ImportDescriptorsStep from 'ui/pages/descriptorlist/descriptorlist-stepper/steps/import'; -import ReorderDescriptorsStep from 'ui/pages/descriptorlist/descriptorlist-stepper/steps/reorder'; -import ReviewDescriptorListStep from 'ui/pages/descriptorlist/descriptorlist-stepper/steps/review'; - -import VocabularyBrowsePage from './pages/vocabulary/BrowsePage'; -import VocabularyEditPage from './pages/vocabulary/EditPage'; -import VocabularyDisplayPage from './pages/vocabulary/DisplayPage'; - -import DashboardPage from './pages/dashboard/DashboardPage'; -import MyDataPage from './pages/dashboard/MyDataPage'; - -import BasicInfoStep from './pages/dataset/dataset-stepper/steps/basic-info'; -import FilesStep from './pages/dataset/dataset-stepper/steps/files'; -import Creators from './pages/dataset/dataset-stepper/steps/creators'; -import AccessionsListStep from './pages/dataset/dataset-stepper/steps/accessions-list'; -import LocationStep from './pages/dataset/dataset-stepper/steps/location'; -import ReviewAndPublishStep from './pages/dataset/dataset-stepper/steps/review'; -import PastingTraitsStep from './pages/dataset/dataset-stepper/steps/pasting-traits'; -import Traits from './pages/dataset/dataset-stepper/steps/traits'; -import ReorderTraitsStep from 'ui/pages/dataset/dataset-stepper/steps/reorder'; +import {datasetPublicRoutes, datasetDashboardRoutes} from 'datasets/routes'; +import {descriptorListDashboardRoutes, descriptorListPublicRoutes} from 'descriptorlists/routes'; +import {descriptorDashboardRoutes, descriptorPublicRoutes} from 'descriptors/routes'; +import {partnerAdminRoutes, partnerPublicRoutes} from 'partners/routes'; +import {vocabularyAdminRoutes, vocabularyPublicRoutes} from 'vocabulary/routes'; import UserProfilePage from './pages/profile/ProfilePage'; -import AccessionsBrowsePage from './pages/genesys/BrowsePage'; import LoginPage from './pages/login/LoginPage'; import GuiTest from './pages/ui-design/Gui'; import NotFound from './common/not-found'; import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import DatasetDashboardPage from 'datasets/ui/DashboardPage'; const routes = [ { @@ -60,236 +27,6 @@ const routes = [ exact: true, component: WelcomePage, }, - { - path: '/partners', - component: Wrapper, - extraProps: { - title: 'p.partners.title', - subtitle: 'p.partners.subtitle', - }, - routes: [ - { - path: '/edit', - component: PartnerEditPage, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - exact: true, - }, - { - path: '/:uuid/edit', - component: PartnerEditPage, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - exact: true, - }, - { - path: '/:uuid', - component: PartnerDisplayPage, - exact: true, - }, - { - path: '/', - component: PartnerBrowsePage, - exact: true, - }, - ], - }, - { - path: '/descriptors', - component: Wrapper, - extraProps: { - title: 'p.descriptors.title', - subtitle: 'p.descriptors.subtitle', - }, - routes: [ - { - path: '/edit', - component: DescriptorEditPage, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - exact: true, - }, - { - path: '/:uuid/edit', - component: DescriptorEditPage, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - exact: true, - }, - { - path: '/:uuid', - component: DescriptorDisplayPage, - exact: true, - }, - { - path: '/', - component: DescriptorBrowsePage, - exact: true, - }, - ], - }, - { - path: '/descriptorlists/edit', - component: DescriptorListStepper, - exact: true, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - extraProps: { - title: 'Descriptor list publisher', - }, - routes: [ - { - path: '/', - component: DescriptorListBasicStep, - exact: true, - }, - ], - }, - { - path: '/descriptorlists/:uuid/edit', - component: DescriptorListStepper, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - extraProps: { - title: 'Descriptor list publisher', - }, - routes: [ - { - path: '/review-and-publish', - component: ReviewDescriptorListStep, - exact: true, - }, - { - path: '/reorder-descriptors', - component: ReorderDescriptorsStep, - exact: true, - }, - { - path: '/select-descriptors', - component: SelectDescriptorsStep, - exact: true, - }, - { - path: '/import-descriptors', - component: ImportDescriptorsStep, - exact: true, - }, - { - path: '/', - component: DescriptorListBasicStep, - exact: true, - }, - ], - }, - { - path: '/descriptorlists', - component: Wrapper, - extraProps: { - title: 'p.descriptorlists.title', - subtitle: 'p.descriptorlists.subtitle', - }, - routes: [ - { - path: '/:uuid', - component: DescriptorListDisplayPage, - exact: true, - }, - { - path: '/', - component: DescriptorListBrowsePage, - exact: true, - }, - ], - }, - { - path: '/datasets/edit', - component: DatasetStepper, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - extraProps: { - title: 'Phenotypic dataset publisher', - }, - routes: [ - { - path: '/', - component: BasicInfoStep, - exact: true, - }, - ], - }, - { - path: '/datasets/:uuid/edit', - component: DatasetStepper, - auth: [ROLE_USER, ROLE_ADMINISTRATOR], - extraProps: { - title: 'Phenotypic dataset publisher', - }, - routes: [ - { - path: '/files', - component: FilesStep, - exact: true, - }, - { - path: '/dataset-creator', - component: Creators, - exact: true, - }, - { - path: '/location', - component: LocationStep, - exact: true, - }, - { - path: '/list-of-accessions', - component: AccessionsListStep, - exact: true, - }, - { - path: '/pasting-traits', - component: PastingTraitsStep, - exact: true, - }, - { - path: '/traits-observed', - component: Traits, - exact: true, - }, - { - path: '/reorder-descriptors', - component: ReorderTraitsStep, - exact: true, - }, - { - path: '/review-and-publish', - component: ReviewAndPublishStep, - exact: true, - }, - { - path: '/', - component: BasicInfoStep, - exact: true, - }, - ], - }, - { - path: '/datasets', - component: Wrapper, - extraProps: { - title: 'p.datasets.title', - subtitle: 'p.datasets.subtitle', - }, - routes: [ - { - path: '/suggest', - component: DatasetSuggestionsPage, - exact: true, - }, - { - path: '/:uuid', - component: DatasetDisplayPage, - exact: true, - }, - { - path: '/', - component: DatasetBrowsePage, - exact: true, - }, - ], - }, { path: '/crops', component: Wrapper, @@ -317,53 +54,6 @@ const routes = [ }, ], }, - { - path: '/vocabulary', - component: Wrapper, - extraProps: { - title: 'p.vocab.title', - subtitle: 'p.vocab.subtitle', - }, - routes: [ - { - path: '/create', - component: VocabularyEditPage, - auth: [ROLE_ADMINISTRATOR], - exact: true, - }, - { - path: '/:uuid/edit', - component: VocabularyEditPage, - auth: [ROLE_ADMINISTRATOR], - exact: true, - }, - { - path: '/:uuid', - component: VocabularyDisplayPage, - exact: true, - }, - { - path: '/', - component: VocabularyBrowsePage, - exact: true, - }, - ], - }, - { - path: '/accessions', - component: Wrapper, - extraProps: { - title: 'Genesys accessions', - subtitle: 'Browse accession data on Genesys', - }, - routes: [ - { - path: '/', - component: AccessionsBrowsePage, - exact: true, - }, - ], - }, { path: '/login', component: LoginPage, @@ -378,36 +68,32 @@ const routes = [ }, auth: [ROLE_USER, ROLE_ADMINISTRATOR], routes: [ + ...datasetDashboardRoutes, + ...descriptorListDashboardRoutes, + ...descriptorDashboardRoutes, { - path: '/data-published/:tab?', - component: MyDataPage, - exact: true, - extraProps: { - title: 'Published data', - basePath: '/dashboard/data-published', - filter: { published: true }, - }, - }, - { - path: '/data-in-preparation/:tab?', - component: MyDataPage, - exact: true, - extraProps: { - title: 'Data in preparation', - basePath: '/dashboard/data-in-preparation', - filter: { published: false }, - }, - }, - { - path: '/:tab?', - component: DashboardPage, - exact: true, + path: '/', + component: DatasetDashboardPage, + auth: [ROLE_USER], extraProps: { title: 'My Dashboard', }, }, ], }, + { + path: '/admin', + component: Wrapper, + extraProps: { + title: 'p.admin.title', + subtitle: 'p.admin.subtitle', + }, + auth: [ROLE_ADMINISTRATOR], + routes: [ + ...partnerAdminRoutes, + ...vocabularyAdminRoutes, + ], + }, { path: '/profile', component: Wrapper, @@ -424,6 +110,11 @@ const routes = [ }, ], }, + ...datasetPublicRoutes, + ...descriptorListPublicRoutes, + ...descriptorPublicRoutes, + ...partnerPublicRoutes, + ...vocabularyPublicRoutes, { path: '/gui/:tab', component: GuiTest, diff --git a/src/vocabulary/actions/admin.ts b/src/vocabulary/actions/admin.ts new file mode 100644 index 0000000..4679738 --- /dev/null +++ b/src/vocabulary/actions/admin.ts @@ -0,0 +1,47 @@ +import { push } from 'react-router-redux'; +import { SubmissionError } from 'redux-form'; + +// Constants +import {RECEIVE_VOCABULARY, RECEIVE_VOCABULARIES} from 'vocabulary/constants'; + +// Models +import {Vocabulary} from 'model/vocabulary.model'; +import {IReducerAction, Page} from 'model/common.model'; + +// Service +import {VocabularyService} from 'service/VocabularyService'; + +// Util +import {log} from 'utilities/debug'; + +const receiveVocabulary = (vocabulary: Vocabulary): IReducerAction => ({ + type: RECEIVE_VOCABULARY, payload: vocabulary, +}); + +const receiveVocabularyPage = (page: Page): IReducerAction => ({ + type: RECEIVE_VOCABULARIES, payload: page, +}); + +// Delete a record +export const deleteVocabulary = (vocabulary: Vocabulary) => (dispatch, getState) => { + return VocabularyService.deleteVocabulary(getState().login.access_token, vocabulary) + .then((vocabulary) => { + dispatch(receiveVocabularyPage(null)); + dispatch(push(`/vocabulary`)); + }) + .catch((error) => { + log('Error', error); + }); +}; + +export const saveVocabulary = (vocabulary: Vocabulary) => (dispatch, getState) => { + + return VocabularyService.saveVocabulary(getState().login.access_token, vocabulary) + .then((saved) => { + dispatch(receiveVocabulary(saved)); + // dispatch(showVocabulary(saved.uuid)); + }).catch((error) => { + log('Save error', error); + throw new SubmissionError({ name: 'Name already used', _error: error.error }); + }); +}; diff --git a/src/actions/vocabulary.ts b/src/vocabulary/actions/public.ts similarity index 76% rename from src/actions/vocabulary.ts rename to src/vocabulary/actions/public.ts index bc6a1da..4475592 100644 --- a/src/actions/vocabulary.ts +++ b/src/vocabulary/actions/public.ts @@ -1,11 +1,10 @@ import { push } from 'react-router-redux'; -import { SubmissionError } from 'redux-form'; import { VocabularyService } from 'service/VocabularyService'; import { log } from 'utilities/debug'; import { CREATE_VOCABULARY, RECEIVE_VOCABULARY, RECEIVE_VOCABULARIES, RECEIVE_MY_VOCABULARYLIST, -} from 'constants/vocabulary'; +} from 'vocabulary/constants'; import { IReducerAction, Page } from 'model/common.model'; import { Vocabulary, IVocabularyFilter } from 'model/vocabulary.model'; @@ -27,22 +26,10 @@ export const createVocabulary = () => (dispatch) => { log('Create new vocabulary'); return Promise.all([ dispatch({ type: CREATE_VOCABULARY }), - dispatch(push(`/vocabulary/create`)), + dispatch(push(`/admin/vocabulary/create`)), ]); }; -// Delete a record -export const deleteVocabulary = (vocabulary: Vocabulary) => (dispatch, getState) => { - return VocabularyService.deleteVocabulary(getState().login.access_token, vocabulary) - .then((vocabulary) => { - dispatch(receiveVocabularyPage(null)); - dispatch(push(`/vocabulary`)); - }) - .catch((error) => { - log('Error', error); - }); -}; - // Just load a record export const loadVocabulary = (uuid: string) => (dispatch, getState) => { log('Loading vocabulary', uuid); @@ -80,13 +67,13 @@ export const autocomplete = (uuid: string, term: string) => (dispatch, getState) export const editVocabulary = (uuid: string) => (dispatch, getState) => { return Promise.all([ dispatch(loadVocabulary(uuid)), - dispatch(push(`/vocabulary/${uuid}/edit`)), + dispatch(push(`/admin/vocabulary/${uuid}/edit`)), ]); }; const showVocabulary = (uuid: string) => (dispatch) => { log('Navigating to Vocabulary details'); - dispatch(push(`/vocabulary/${uuid}`)); + dispatch(push(`/admin/vocabulary/${uuid}`)); }; // List user's vocabularies @@ -122,17 +109,6 @@ const listVocabularies = (page: number = 0, results: number = 50, sortBy?: strin }); }; -const saveVocabulary = (vocabulary: Vocabulary) => (dispatch, getState) => { - - return VocabularyService.saveVocabulary(getState().login.access_token, vocabulary) - .then((saved) => { - dispatch(receiveVocabulary(saved)); - // dispatch(showVocabulary(saved.uuid)); - }).catch((error) => { - log('Save error', error); - throw new SubmissionError({ name: 'Name already used', _error: error.error }); - }); -}; const autoUpdate = () => (dispatch, getState) => { @@ -140,5 +116,5 @@ const autoUpdate = () => (dispatch, getState) => { }; export { - listMyVocabularies, listVocabularies, saveVocabulary, showVocabulary, autoUpdate, + listMyVocabularies, listVocabularies, showVocabulary, autoUpdate, }; diff --git a/src/constants/vocabulary.ts b/src/vocabulary/constants.ts similarity index 100% rename from src/constants/vocabulary.ts rename to src/vocabulary/constants.ts diff --git a/src/vocabulary/reducers/admin.ts b/src/vocabulary/reducers/admin.ts new file mode 100644 index 0000000..901c667 --- /dev/null +++ b/src/vocabulary/reducers/admin.ts @@ -0,0 +1,32 @@ +import update from 'immutability-helper'; +import {log} from 'utilities/debug'; + +import { IReducerAction } from 'model/common.model'; +import { Vocabulary } from 'model/vocabulary.model'; + +import { CREATE_VOCABULARY, RECEIVE_VOCABULARY } from 'vocabulary/constants'; + +const INITIAL_STATE = { + currentVocabulary: null, +}; + +export default function adminVocabulary(state = INITIAL_STATE, action: IReducerAction = { type: '' }) { + + switch (action.type) { + case CREATE_VOCABULARY: { + return update(state, { + currentVocabulary: { $set: new Vocabulary() }, + }); + } + + case RECEIVE_VOCABULARY: { + log(RECEIVE_VOCABULARY); + return update(state, { + currentVocabulary: { $set: action.payload }, + }); + } + + default: + return state; + } +} diff --git a/src/vocabulary/reducers/index.ts b/src/vocabulary/reducers/index.ts new file mode 100644 index 0000000..a74659c --- /dev/null +++ b/src/vocabulary/reducers/index.ts @@ -0,0 +1,10 @@ +import { combineReducers } from 'redux'; +import admin from './admin'; +import publicVocabulary from './public'; + +const rootReducer = combineReducers({ + admin, + public: publicVocabulary, +}); + +export default rootReducer; diff --git a/src/reducers/vocabulary.ts b/src/vocabulary/reducers/public.ts similarity index 76% rename from src/reducers/vocabulary.ts rename to src/vocabulary/reducers/public.ts index ab8317c..ec8642b 100644 --- a/src/reducers/vocabulary.ts +++ b/src/vocabulary/reducers/public.ts @@ -2,21 +2,19 @@ import update from 'immutability-helper'; import {log} from 'utilities/debug'; import { IReducerAction } from 'model/common.model'; -import { Vocabulary } from 'model/vocabulary.model'; -import { CREATE_VOCABULARY, RECEIVE_VOCABULARY, RECEIVE_VOCABULARIES } from 'constants/vocabulary'; +import { CREATE_VOCABULARY, RECEIVE_VOCABULARY, RECEIVE_VOCABULARIES } from 'vocabulary/constants'; const INITIAL_STATE = { currentVocabulary: null, paged: null, }; -export default function vocabulary(state = INITIAL_STATE, action: IReducerAction = { type: '' }) { +export default function publicVocabulary(state = INITIAL_STATE, action: IReducerAction = { type: '' }) { switch (action.type) { case CREATE_VOCABULARY: { return update(state, { - currentVocabulary: { $set: new Vocabulary() }, paged: { $set: null }, }); } diff --git a/src/vocabulary/routes.ts b/src/vocabulary/routes.ts new file mode 100644 index 0000000..3a1a7a5 --- /dev/null +++ b/src/vocabulary/routes.ts @@ -0,0 +1,47 @@ +import VocabularyBrowsePage from 'vocabulary/ui/BrowsePage'; +import VocabularyEditPage from 'vocabulary/ui/EditPage'; +import VocabularyDisplayPage from 'vocabulary/ui/DisplayPage'; + +import Wrapper from 'ui/catalog/Wrapper'; +import {ROLE_ADMINISTRATOR} from 'constants/userRoles'; + + +const publicRoutes = [ + { + path: '/vocabulary', + component: Wrapper, + extraProps: { + title: 'p.vocab.title', + subtitle: 'p.vocab.subtitle', + }, + routes: [ + { + path: '/:uuid', + component: VocabularyDisplayPage, + exact: true, + }, + { + path: '/', + component: VocabularyBrowsePage, + exact: true, + }, + ], + }, +]; + +const adminRoutes = [ + { + path: '/vocabulary/create', + component: VocabularyEditPage, + auth: [ROLE_ADMINISTRATOR], + exact: true, + }, + { + path: '/vocabulary/:uuid/edit', + component: VocabularyEditPage, + auth: [ROLE_ADMINISTRATOR], + exact: true, + }, +]; + +export {publicRoutes as vocabularyPublicRoutes, adminRoutes as vocabularyAdminRoutes}; diff --git a/src/ui/pages/vocabulary/BrowsePage.tsx b/src/vocabulary/ui/BrowsePage.tsx similarity index 98% rename from src/ui/pages/vocabulary/BrowsePage.tsx rename to src/vocabulary/ui/BrowsePage.tsx index 6333caf..5e87cd9 100644 --- a/src/ui/pages/vocabulary/BrowsePage.tsx +++ b/src/vocabulary/ui/BrowsePage.tsx @@ -4,7 +4,7 @@ import { bindActionCreators } from 'redux'; import { withStyles } from '@material-ui/core/styles'; import { parse } from 'query-string'; -import { listVocabularies, promiseListVocabularies, createVocabulary, autoUpdate } from 'actions/vocabulary'; +import { listVocabularies, promiseListVocabularies, createVocabulary, autoUpdate } from 'vocabulary/actions/public'; import { Vocabulary, IVocabularyFilter } from 'model/vocabulary.model'; import { Page, Pagination } from 'model/common.model'; @@ -157,7 +157,7 @@ const mapStateToProps = (state, ownProps) => ({ sort: parse(ownProps.location.search).s, // page sorts dir: parse(ownProps.location.search).d, // page sort directions }), - paged: state.vocabulary.paged, + paged: state.vocabulary.public.paged, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/vocabulary/DisplayPage.tsx b/src/vocabulary/ui/DisplayPage.tsx similarity index 97% rename from src/ui/pages/vocabulary/DisplayPage.tsx rename to src/vocabulary/ui/DisplayPage.tsx index 561f667..7d5bd02 100644 --- a/src/ui/pages/vocabulary/DisplayPage.tsx +++ b/src/vocabulary/ui/DisplayPage.tsx @@ -3,7 +3,8 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {withStyles} from '@material-ui/core/styles'; -import {loadVocabulary, listVocabularyTerms, deleteVocabulary} from 'actions/vocabulary'; +import {loadVocabulary, listVocabularyTerms} from 'vocabulary/actions/public'; +import {deleteVocabulary} from 'vocabulary/actions/admin'; import {Vocabulary, VocabularyTerm} from 'model/vocabulary.model'; import {Page} from 'model/common.model'; @@ -184,7 +185,7 @@ class DisplayPage extends React.Component { const mapStateToProps = (state, ownProps) => ({ uuid: ownProps.match.params.uuid, - vocabulary: state.vocabulary.currentVocabulary, + vocabulary: state.vocabulary.public.currentVocabulary, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/vocabulary/EditPage.tsx b/src/vocabulary/ui/EditPage.tsx similarity index 91% rename from src/ui/pages/vocabulary/EditPage.tsx rename to src/vocabulary/ui/EditPage.tsx index 457f723..58692fc 100644 --- a/src/ui/pages/vocabulary/EditPage.tsx +++ b/src/vocabulary/ui/EditPage.tsx @@ -6,8 +6,9 @@ import Grid from '@material-ui/core/Grid'; import {log} from 'utilities/debug'; -import {loadMyPartners} from 'actions/partner'; -import {loadVocabulary, saveVocabulary, deleteVocabulary} from 'actions/vocabulary'; +import {loadMyPartners} from 'partners/actions/dashboard'; +import {saveVocabulary, deleteVocabulary} from 'vocabulary/actions/admin'; +import {loadVocabulary} from 'vocabulary/actions/public'; import confirm from 'utilities/confirmAlert'; import {Vocabulary} from 'model/vocabulary.model'; @@ -116,8 +117,8 @@ class VocabularyEditPage extends React.Component const mapStateToProps = (state, ownProps) => ({ uuid: ownProps.match.params.uuid, - myPartners: state.partner.myPartners, - vocabulary: state.vocabulary.currentVocabulary, + myPartners: state.partner.dashboard.myPartners, + vocabulary: state.vocabulary.admin.currentVocabulary, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ diff --git a/src/ui/pages/vocabulary/c/VocabularyCard.tsx b/src/vocabulary/ui/c/VocabularyCard.tsx similarity index 100% rename from src/ui/pages/vocabulary/c/VocabularyCard.tsx rename to src/vocabulary/ui/c/VocabularyCard.tsx diff --git a/src/ui/pages/vocabulary/c/VocabularyForm.tsx b/src/vocabulary/ui/c/VocabularyForm.tsx similarity index 98% rename from src/ui/pages/vocabulary/c/VocabularyForm.tsx rename to src/vocabulary/ui/c/VocabularyForm.tsx index d6e7954..71c4f66 100644 --- a/src/ui/pages/vocabulary/c/VocabularyForm.tsx +++ b/src/vocabulary/ui/c/VocabularyForm.tsx @@ -5,7 +5,7 @@ import { Link } from 'react-router-dom'; import {log} from 'utilities/debug'; -import {VOCABULARY_FORM} from 'constants/vocabulary'; +import {VOCABULARY_FORM} from 'vocabulary/constants'; import { VocabularyTerm } from 'model/vocabulary.model'; import { TextField } from 'ui/common/text-field'; -- GitLab From 99b2b5e7837d18359f794a1c81edf07b5ae2b235 Mon Sep 17 00:00:00 2001 From: Matija Obreza Date: Sun, 30 Sep 2018 08:35:47 +0200 Subject: [PATCH 2/2] Updates to modular code layout - Moved remaining components from ui/catalog --- .gitignore | 3 +- .../pages/crop => crops/ui}/BrowsePage.tsx | 0 src/{ui/pages/crop => crops/ui}/EditPage.tsx | 0 .../pages/crop => crops/ui}/c/CropCard.tsx | 0 .../catalog/crop => crops/ui/c}/CropChips.tsx | 0 .../crop => crops/ui/c}/CropFilter.tsx | 0 .../pages/crop => crops/ui}/c/CropForm.tsx | 0 .../crop => crops/ui/c}/CropSelector.tsx | 0 src/data/cropNames.ts | 31 ---------------- src/data/institutes.ts | 26 -------------- src/data/publicationYears.ts | 1 - src/datasets/routes.ts | 6 ++-- src/datasets/ui/c/Card.tsx | 2 +- src/datasets/ui/c/DatasetDisplay.tsx | 2 +- src/datasets/ui/c/Filters.tsx | 4 +-- .../steps/basic-info/BasicInfoForm.tsx | 6 ++-- .../steps/pasting-traits/index.tsx | 4 +-- .../ui/dataset-stepper/steps/traits/index.tsx | 2 +- src/datasets/ui/search/c/hits/Crop.tsx | 2 +- src/datasets/ui/search/c/hits/Dataset.tsx | 2 +- src/datasets/ui/search/c/hits/Descriptor.tsx | 2 +- src/descriptorlists/routes.ts | 6 ++-- src/descriptorlists/ui/BrowsePage.tsx | 2 +- .../ui/c}/Card.tsx | 0 .../ui/c/DescriptorListDisplay.tsx | 2 +- .../ui/c/DescriptorListForm.tsx | 4 +-- src/descriptorlists/ui/c/Filters.tsx | 4 +-- .../steps/import/index.tsx | 4 +-- .../steps/select/index.tsx | 2 +- src/descriptors/routes.ts | 6 ++-- src/descriptors/ui/BrowsePage.tsx | 4 +-- src/descriptors/ui/DisplayPage.tsx | 2 +- src/descriptors/ui/c/DashboardFilters.tsx | 35 +++++++++++++++++++ .../ui/c}/DescriptorCard.tsx | 0 .../ui/c}/DescriptorFilterForm.tsx | 0 src/descriptors/ui/c/DescriptorForm.tsx | 4 +-- .../ui/c}/DescriptorListPicker.tsx | 0 .../ui/c}/DescriptorParser.tsx | 0 .../ui/c}/DescriptorPicker.tsx | 4 +-- .../ui/c}/DescriptorScale.tsx | 0 .../ui/c}/DescriptorSearchMenu.tsx | 2 +- .../ui/c}/Filters.tsx | 4 +-- .../ui/c}/PartnerFilter.tsx | 0 .../ui/c}/SelectPartner.tsx | 0 src/ui/catalog/dashboard/c/Filters.tsx | 4 +-- .../ui-design/tests/UiDescriptorCard.tsx | 2 +- src/ui/routes.tsx | 6 ++-- src/vocabulary/ui/c/VocabularyForm.tsx | 2 +- .../ui/c}/VocabularyTermPicker.tsx | 0 49 files changed, 85 insertions(+), 107 deletions(-) rename src/{ui/pages/crop => crops/ui}/BrowsePage.tsx (100%) rename src/{ui/pages/crop => crops/ui}/EditPage.tsx (100%) rename src/{ui/pages/crop => crops/ui}/c/CropCard.tsx (100%) rename src/{ui/catalog/crop => crops/ui/c}/CropChips.tsx (100%) rename src/{ui/catalog/crop => crops/ui/c}/CropFilter.tsx (100%) rename src/{ui/pages/crop => crops/ui}/c/CropForm.tsx (100%) rename src/{ui/catalog/crop => crops/ui/c}/CropSelector.tsx (100%) delete mode 100644 src/data/cropNames.ts delete mode 100644 src/data/institutes.ts delete mode 100644 src/data/publicationYears.ts rename src/{ui/catalog/descriptorlist => descriptorlists/ui/c}/Card.tsx (100%) create mode 100644 src/descriptors/ui/c/DashboardFilters.tsx rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorCard.tsx (100%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorFilterForm.tsx (100%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorListPicker.tsx (100%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorParser.tsx (100%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorPicker.tsx (98%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorScale.tsx (100%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/DescriptorSearchMenu.tsx (97%) rename src/{ui/catalog/descriptor => descriptors/ui/c}/Filters.tsx (95%) rename src/{ui/catalog/partner => partners/ui/c}/PartnerFilter.tsx (100%) rename src/{ui/catalog/partner => partners/ui/c}/SelectPartner.tsx (100%) rename src/{ui/catalog/vocabulary => vocabulary/ui/c}/VocabularyTermPicker.tsx (100%) diff --git a/.gitignore b/.gitignore index 1539835..f7517a6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .awesome-typescript-loader-cache/ node_modules .idea -*.iml \ No newline at end of file +*.iml +.vscode diff --git a/src/ui/pages/crop/BrowsePage.tsx b/src/crops/ui/BrowsePage.tsx similarity index 100% rename from src/ui/pages/crop/BrowsePage.tsx rename to src/crops/ui/BrowsePage.tsx diff --git a/src/ui/pages/crop/EditPage.tsx b/src/crops/ui/EditPage.tsx similarity index 100% rename from src/ui/pages/crop/EditPage.tsx rename to src/crops/ui/EditPage.tsx diff --git a/src/ui/pages/crop/c/CropCard.tsx b/src/crops/ui/c/CropCard.tsx similarity index 100% rename from src/ui/pages/crop/c/CropCard.tsx rename to src/crops/ui/c/CropCard.tsx diff --git a/src/ui/catalog/crop/CropChips.tsx b/src/crops/ui/c/CropChips.tsx similarity index 100% rename from src/ui/catalog/crop/CropChips.tsx rename to src/crops/ui/c/CropChips.tsx diff --git a/src/ui/catalog/crop/CropFilter.tsx b/src/crops/ui/c/CropFilter.tsx similarity index 100% rename from src/ui/catalog/crop/CropFilter.tsx rename to src/crops/ui/c/CropFilter.tsx diff --git a/src/ui/pages/crop/c/CropForm.tsx b/src/crops/ui/c/CropForm.tsx similarity index 100% rename from src/ui/pages/crop/c/CropForm.tsx rename to src/crops/ui/c/CropForm.tsx diff --git a/src/ui/catalog/crop/CropSelector.tsx b/src/crops/ui/c/CropSelector.tsx similarity index 100% rename from src/ui/catalog/crop/CropSelector.tsx rename to src/crops/ui/c/CropSelector.tsx diff --git a/src/data/cropNames.ts b/src/data/cropNames.ts deleted file mode 100644 index 5c03a88..0000000 --- a/src/data/cropNames.ts +++ /dev/null @@ -1,31 +0,0 @@ -export default { - pigeonpea: 'Pigeonpea', - sorghum: 'Sorghum', - forages: 'Forages', - pearlmillet: 'Pearl millet', - tomato: 'Tomato', - apple: 'Apple', - potato: 'Potato', - beans: 'Beans', - cassava: 'Cassava', - wheat: 'Wheat', - taro: 'Taro', - eggplant: 'Eggplant', - fababean: 'Faba bean', - banana: 'Banana', - cowpea: 'Cowpea', - yam: 'Yam', - grasspea: 'Grass pea', - barley: 'Barley', - lentil: 'Lentil', - rice: 'Rice', - lettuce: 'Lettuce', - maize: 'Maize', - sweetpotato: 'Sweet potato', - chickpea: 'Chickpea', - sunflower: 'Sunflower', - coconut: 'Coconut', - fingermillet: 'Finger millet', - coffee: 'Coffee', - breadfruit: 'Breadfruit', -}; diff --git a/src/data/institutes.ts b/src/data/institutes.ts deleted file mode 100644 index 56ea466..0000000 --- a/src/data/institutes.ts +++ /dev/null @@ -1,26 +0,0 @@ -export default [ - { - code: 'ALB026', - name: 'Plant Genetic Resources Center', - }, - { - code: 'ARM005', - name: 'Institute of Botany', - }, - { - code: 'ARM006', - name: 'Scientific Center of Agriculture', - }, - { - code: 'ARM008', - name: 'Scientific Center of Vegetables and Industrial Crops', - }, - { - code: 'ARM035', - name: 'Laboratory of Plants Gene Pool and Breeding', - }, - { - code: 'ARM059', - name: 'Scientific Center of Agrobiotechnology', - }, -]; diff --git a/src/data/publicationYears.ts b/src/data/publicationYears.ts deleted file mode 100644 index 107c675..0000000 --- a/src/data/publicationYears.ts +++ /dev/null @@ -1 +0,0 @@ -export default [1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017]; diff --git a/src/datasets/routes.ts b/src/datasets/routes.ts index a7f4d2f..21fa1f9 100644 --- a/src/datasets/routes.ts +++ b/src/datasets/routes.ts @@ -7,7 +7,7 @@ import DatasetDashboardPage from 'datasets/ui/DashboardPage'; import datasetSteps from 'datasets/ui/dataset-stepper/steps'; import BasicInfoStep from 'datasets/ui/dataset-stepper/steps/basic-info'; -import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import { ROLE_ADMINISTRATOR, ROLE_USER } from 'constants/userRoles'; import Wrapper from 'ui/catalog/Wrapper'; const publicRoutes = [ @@ -68,7 +68,7 @@ const dashboardRoutes = [ { path: '/datasets', component: DatasetDashboardPage, - auth: [ROLE_USER], + auth: [ROLE_USER, ROLE_ADMINISTRATOR], extraProps: { title: 'My Dashboard', }, @@ -76,4 +76,4 @@ const dashboardRoutes = [ ]; -export {publicRoutes as datasetPublicRoutes, dashboardRoutes as datasetDashboardRoutes}; +export { publicRoutes as datasetPublicRoutes, dashboardRoutes as datasetDashboardRoutes }; diff --git a/src/datasets/ui/c/Card.tsx b/src/datasets/ui/c/Card.tsx index 2d8916f..5148964 100644 --- a/src/datasets/ui/c/Card.tsx +++ b/src/datasets/ui/c/Card.tsx @@ -9,7 +9,7 @@ import Markdown from 'ui/catalog/markdown'; import { PartnerLink } from 'ui/catalog/Links'; import { Properties, PropertiesItem } from 'ui/catalog/Properties'; import PrettyDate from 'ui/common/time/PrettyDate'; -import CropChips from 'ui/catalog/crop/CropChips'; +import CropChips from 'crops/ui/c/CropChips'; interface IDatasetCardProps extends React.ClassAttributes { className?: string; diff --git a/src/datasets/ui/c/DatasetDisplay.tsx b/src/datasets/ui/c/DatasetDisplay.tsx index 0365327..b83e52c 100644 --- a/src/datasets/ui/c/DatasetDisplay.tsx +++ b/src/datasets/ui/c/DatasetDisplay.tsx @@ -31,7 +31,7 @@ import ListItemText from '@material-ui/core/ListItemText'; import AccessionIdentifiersTable from 'ui/catalog/accession/IdentifiersTable'; import Permissions from 'ui/common/permission/Permissions'; -import CropChips from 'ui/catalog/crop/CropChips'; +import CropChips from 'crops/ui/c/CropChips'; import Card, {CardHeader, CardContent, CardActions } from 'ui/common/Card'; import McpdDate from 'ui/common/time/McpdDate'; diff --git a/src/datasets/ui/c/Filters.tsx b/src/datasets/ui/c/Filters.tsx index 91f640f..fbfb6ca 100644 --- a/src/datasets/ui/c/Filters.tsx +++ b/src/datasets/ui/c/Filters.tsx @@ -8,8 +8,8 @@ import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSea import StringFilter from 'ui/common/filter/StringFilter'; import StringArrFilter from 'ui/common/filter/StringArrFilter'; import TextFilter from 'ui/common/filter/TextFilter'; -import CropFilter from 'ui/catalog/crop/CropFilter'; -import PartnerFilter from 'ui/catalog/partner/PartnerFilter'; +import CropFilter from 'crops/ui/c/CropFilter'; +import PartnerFilter from 'partners/ui/c/PartnerFilter'; // diff --git a/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx index c530ca8..7074ef7 100644 --- a/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx @@ -5,14 +5,14 @@ import {DATASET_BASIC_INFO_FORM} from 'datasets/constants'; import {TextField} from 'ui/common/text-field'; import {MarkdownField} from 'ui/catalog/markdown'; -import SelectPartner from 'ui/catalog/partner/SelectPartner'; -import CropSelector from 'ui/catalog/crop/CropSelector'; +import SelectPartner from 'partners/ui/c/SelectPartner'; +import CropSelector from 'crops/ui/c/CropSelector'; import Validators from 'utilities/Validators'; import BasicInfoRadioGroup from './BasicInfoRadioGroup'; import remoteSubmit from './RemoteSubmit'; -import VocabularyTermPicker from 'ui/catalog/vocabulary/VocabularyTermPicker'; +import VocabularyTermPicker from 'vocabulary/ui/c/VocabularyTermPicker'; interface ILoginContainerProps extends React.ClassAttributes { handleSubmit: () => void; diff --git a/src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx b/src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx index 74e5457..3f971c1 100644 --- a/src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/pasting-traits/index.tsx @@ -8,10 +8,10 @@ import {log} from 'utilities/debug'; import {addDescriptorsToDataset} from 'datasets/actions/editor'; import {searchMatchingDescriptor} from 'descriptors/actions/editor'; -import DescriptorParser from 'ui/catalog/descriptor/DescriptorParser'; +import DescriptorParser from 'descriptors/ui/c/DescriptorParser'; import steps from 'datasets/ui/dataset-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; +import DescriptorCard from 'descriptors/ui/c/DescriptorCard'; import {Dataset} from 'model/dataset.model'; interface IPastingDescriptorsStepProps extends React.ClassAttributes { diff --git a/src/datasets/ui/dataset-stepper/steps/traits/index.tsx b/src/datasets/ui/dataset-stepper/steps/traits/index.tsx index 32932cf..20d9d04 100644 --- a/src/datasets/ui/dataset-stepper/steps/traits/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/traits/index.tsx @@ -9,7 +9,7 @@ import {listMyDescriptors as listMatchingDescriptors} from 'descriptors/actions/ import {addDescriptorsToDataset, removeDescriptorsFromDataset} from 'datasets/actions/editor'; import {Descriptor, IDescriptorFilter} from 'model/descriptor.model'; -import DescriptorPicker from 'ui/catalog/descriptor/DescriptorPicker'; +import DescriptorPicker from 'descriptors/ui/c/DescriptorPicker'; import {listCrops} from 'actions/crop'; import {Pagination} from 'model/common.model'; import steps from 'datasets/ui/dataset-stepper/steps'; diff --git a/src/datasets/ui/search/c/hits/Crop.tsx b/src/datasets/ui/search/c/hits/Crop.tsx index 8853e9e..bc02477 100644 --- a/src/datasets/ui/search/c/hits/Crop.tsx +++ b/src/datasets/ui/search/c/hits/Crop.tsx @@ -3,7 +3,7 @@ import { translate } from 'react-i18next'; import { Crop } from 'model/crop.model'; -import CropChips from 'ui/catalog/crop/CropChips'; +import CropChips from 'crops/ui/c/CropChips'; const HitCrop = ({ hit }: { hit: Crop }) => (
diff --git a/src/datasets/ui/search/c/hits/Dataset.tsx b/src/datasets/ui/search/c/hits/Dataset.tsx index a3e84ba..928ede1 100644 --- a/src/datasets/ui/search/c/hits/Dataset.tsx +++ b/src/datasets/ui/search/c/hits/Dataset.tsx @@ -3,7 +3,7 @@ import { translate } from 'react-i18next'; import { Dataset } from 'model/dataset.model'; -import CropChips from 'ui/catalog/crop/CropChips'; +import CropChips from 'crops/ui/c/CropChips'; import { DatasetLink } from 'ui/catalog/Links'; const HitDataset = ({ hit }: { hit: Dataset }) => ( diff --git a/src/datasets/ui/search/c/hits/Descriptor.tsx b/src/datasets/ui/search/c/hits/Descriptor.tsx index 7fdfa7d..1953332 100644 --- a/src/datasets/ui/search/c/hits/Descriptor.tsx +++ b/src/datasets/ui/search/c/hits/Descriptor.tsx @@ -4,7 +4,7 @@ import { translate } from 'react-i18next'; import { Descriptor } from 'model/descriptor.model'; import { DescriptorLink } from 'ui/catalog/Links'; -import CropChips from 'ui/catalog/crop/CropChips'; +import CropChips from 'crops/ui/c/CropChips'; const HitDescriptor = ({ hit }: { hit: Descriptor }) => (
diff --git a/src/descriptorlists/routes.ts b/src/descriptorlists/routes.ts index 728df52..8af99b8 100644 --- a/src/descriptorlists/routes.ts +++ b/src/descriptorlists/routes.ts @@ -7,7 +7,7 @@ import DescriptorListStepper from 'descriptorlists/ui/descriptorlist-stepper'; import DescriptorListBasicStep from 'descriptorlists/ui/descriptorlist-stepper/steps/basic-info'; import descriptorListSteps from 'descriptorlists/ui/descriptorlist-stepper/steps'; -import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import { ROLE_ADMINISTRATOR, ROLE_USER } from 'constants/userRoles'; import Wrapper from 'ui/catalog/Wrapper'; @@ -66,11 +66,11 @@ const dashboardRoutes = [ { path: '/descriptorlists', component: DescriptorListDashboardPage, - auth: [ROLE_USER], + auth: [ROLE_USER, ROLE_ADMINISTRATOR], extraProps: { title: 'My Dashboard', }, }, ]; -export {publicRoutes as descriptorListPublicRoutes, dashboardRoutes as descriptorListDashboardRoutes}; +export { publicRoutes as descriptorListPublicRoutes, dashboardRoutes as descriptorListDashboardRoutes }; diff --git a/src/descriptorlists/ui/BrowsePage.tsx b/src/descriptorlists/ui/BrowsePage.tsx index 9831e5d..b5e7e54 100644 --- a/src/descriptorlists/ui/BrowsePage.tsx +++ b/src/descriptorlists/ui/BrowsePage.tsx @@ -18,7 +18,7 @@ import Grid from '@material-ui/core/Grid'; import { ScrollToTopOnMount } from 'ui/common/page/scrollers'; import Loading from 'ui/common/Loading'; import PaginationComponent from 'ui/common/pagination'; -import DescriptorListCard from 'ui/catalog/descriptorlist/Card'; +import DescriptorListCard from 'descriptorlists/ui/c/Card'; import DescriptorListFilters from './c/Filters'; import PrettyFilters from 'ui/common/filter/PrettyFilters'; diff --git a/src/ui/catalog/descriptorlist/Card.tsx b/src/descriptorlists/ui/c/Card.tsx similarity index 100% rename from src/ui/catalog/descriptorlist/Card.tsx rename to src/descriptorlists/ui/c/Card.tsx diff --git a/src/descriptorlists/ui/c/DescriptorListDisplay.tsx b/src/descriptorlists/ui/c/DescriptorListDisplay.tsx index e74deb5..43e7fa0 100644 --- a/src/descriptorlists/ui/c/DescriptorListDisplay.tsx +++ b/src/descriptorlists/ui/c/DescriptorListDisplay.tsx @@ -9,7 +9,7 @@ import { fixDate } from 'utilities'; import Authorize from 'ui/common/authorized/Authorize'; import Markdown from 'ui/catalog/markdown'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; +import DescriptorCard from 'descriptors/ui/c/DescriptorCard'; import {PartnerLink, CropLink, DescriptorLink, ExternalLink} from 'ui/catalog/Links'; import { Properties, PropertiesItem } from 'ui/catalog/Properties'; import Permissions from 'ui/common/permission/Permissions'; diff --git a/src/descriptorlists/ui/c/DescriptorListForm.tsx b/src/descriptorlists/ui/c/DescriptorListForm.tsx index 43c9eb4..a4c338f 100644 --- a/src/descriptorlists/ui/c/DescriptorListForm.tsx +++ b/src/descriptorlists/ui/c/DescriptorListForm.tsx @@ -5,10 +5,10 @@ import { DESCRIPTORLIST_FORM } from 'descriptors/constants'; import { TextField } from 'ui/common/text-field'; import { MarkdownField } from 'ui/catalog/markdown'; import Authorize from 'ui/common/authorized/Authorize'; -import SelectPartner from 'ui/catalog/partner/SelectPartner'; +import SelectPartner from 'partners/ui/c/SelectPartner'; import Validators from 'utilities/Validators'; import remoteSubmit from 'descriptorlists/ui/descriptorlist-stepper/steps/basic-info/RemoteSubmit'; -import CropSelector from 'ui/catalog/crop/CropSelector'; +import CropSelector from 'crops/ui/c/CropSelector'; class DescriptorListForm extends React.Component { diff --git a/src/descriptorlists/ui/c/Filters.tsx b/src/descriptorlists/ui/c/Filters.tsx index ffccb0b..a24dc28 100644 --- a/src/descriptorlists/ui/c/Filters.tsx +++ b/src/descriptorlists/ui/c/Filters.tsx @@ -7,9 +7,9 @@ import FiltersBlock from 'ui/common/filter/FiltersBlock'; import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; import StringFilter from 'ui/common/filter/StringFilter'; import StringArrFilter from 'ui/common/filter/StringArrFilter'; -import CropFilter from 'ui/catalog/crop/CropFilter'; +import CropFilter from 'crops/ui/c/CropFilter'; import TextFilter from 'ui/common/filter/TextFilter'; -import PartnerFilter from 'ui/catalog/partner/PartnerFilter'; +import PartnerFilter from 'partners/ui/c/PartnerFilter'; const DescriptorListFilters = ({handleSubmit, initialize, ...other}) => ( diff --git a/src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx index 43f66d7..95a7a6e 100644 --- a/src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/import/index.tsx @@ -8,10 +8,10 @@ import Grid from '@material-ui/core/Grid'; import {importDescriptor} from 'descriptors/actions/editor'; import {addDescriptorsToDescriptorList} from 'descriptorlists/actions/editor'; -import DescriptorParser from 'ui/catalog/descriptor/DescriptorParser'; +import DescriptorParser from 'descriptors/ui/c/DescriptorParser'; import steps from 'descriptorlists/ui/descriptorlist-stepper/steps'; import NavigationWrapper from 'ui/common/stepper/NavigationWrapper'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; +import DescriptorCard from 'descriptors/ui/c/DescriptorCard'; interface IDescriptorListProps extends React.ClassAttributes { uuid: string; diff --git a/src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx b/src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx index 943aa93..0106eb3 100644 --- a/src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx +++ b/src/descriptorlists/ui/descriptorlist-stepper/steps/select/index.tsx @@ -6,7 +6,7 @@ import {log} from 'utilities/debug'; import {Descriptor, DescriptorList, IDescriptorFilter} from 'model/descriptor.model'; import {listCrops} from 'actions/crop'; -import DescriptorPicker from 'ui/catalog/descriptor/DescriptorPicker'; +import DescriptorPicker from 'descriptors/ui/c/DescriptorPicker'; import {importDescriptor} from 'descriptors/actions/editor'; import {listMyDescriptors as listMatchingDescriptors} from 'descriptors/actions/dashboard'; import {Page, Pagination} from 'model/common.model'; diff --git a/src/descriptors/routes.ts b/src/descriptors/routes.ts index 9c164b9..459da07 100644 --- a/src/descriptors/routes.ts +++ b/src/descriptors/routes.ts @@ -4,7 +4,7 @@ import DescriptorEditPage from 'descriptors/ui/EditPage'; import DescriptorDashboardPage from 'descriptors/ui/DashboardPage'; import Wrapper from 'ui/catalog/Wrapper'; -import {ROLE_ADMINISTRATOR, ROLE_USER} from 'constants/userRoles'; +import { ROLE_ADMINISTRATOR, ROLE_USER } from 'constants/userRoles'; const publicRoutes = [ @@ -46,11 +46,11 @@ const dashboardRoutes = [ { path: '/descriptors', component: DescriptorDashboardPage, - auth: [ROLE_USER], + auth: [ROLE_USER, ROLE_ADMINISTRATOR], extraProps: { title: 'My Dashboard', }, }, ]; -export {publicRoutes as descriptorPublicRoutes, dashboardRoutes as descriptorDashboardRoutes}; +export { publicRoutes as descriptorPublicRoutes, dashboardRoutes as descriptorDashboardRoutes }; diff --git a/src/descriptors/ui/BrowsePage.tsx b/src/descriptors/ui/BrowsePage.tsx index 7f511a9..f3b7e54 100644 --- a/src/descriptors/ui/BrowsePage.tsx +++ b/src/descriptors/ui/BrowsePage.tsx @@ -15,8 +15,8 @@ import PagedLoader from 'ui/common/PagedLoader'; import { ScrollToTopOnMount } from 'ui/common/page/scrollers'; import Loading from 'ui/common/Loading'; import PaginationComponent from 'ui/common/pagination'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; -import DescriptorFilters from 'ui/catalog/descriptor/Filters'; +import DescriptorCard from 'descriptors/ui/c/DescriptorCard'; +import DescriptorFilters from 'descriptors/ui/c/Filters'; import PrettyFilters from 'ui/common/filter/PrettyFilters'; import Grid from '@material-ui/core/Grid'; diff --git a/src/descriptors/ui/DisplayPage.tsx b/src/descriptors/ui/DisplayPage.tsx index 03795c1..e19366c 100644 --- a/src/descriptors/ui/DisplayPage.tsx +++ b/src/descriptors/ui/DisplayPage.tsx @@ -23,7 +23,7 @@ import { PartnerLink, CropLink, DescriptorListLink, DatasetLink } from 'ui/catal import { Table, TableRow, TableCell } from 'ui/common/tables'; import { Properties, PropertiesItem } from 'ui/catalog/Properties'; import VocabularyCard from 'vocabulary/ui/c/VocabularyCard'; -import DescriptorScale from 'ui/catalog/descriptor/DescriptorScale'; +import DescriptorScale from 'descriptors/ui/c/DescriptorScale'; import BackButton from 'ui/common/buttons/BackButton'; import Permissions from 'ui/common/permission/Permissions'; diff --git a/src/descriptors/ui/c/DashboardFilters.tsx b/src/descriptors/ui/c/DashboardFilters.tsx new file mode 100644 index 0000000..5142d41 --- /dev/null +++ b/src/descriptors/ui/c/DashboardFilters.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import { reduxForm } from 'redux-form'; + +import { DASHBOARD_FILTERFORM } from 'constants/dashboard'; + +import FiltersBlock from 'ui/common/filter/FiltersBlock'; +import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; +import CropFilter from 'crops/ui/c/CropFilter'; +import BooleanFilter from 'ui/common/filter/BooleanFilter'; +import TextFilter from 'ui/common/filter/TextFilter'; +import Authorize from 'ui/common/authorized/Authorize'; +import PartnerFilter from 'partners/ui/c/PartnerFilter'; +import StatusFilter from 'ui/catalog/dashboard/c/StatusFilter'; // move + +const DashboardFilters = ({handleSubmit, initialize, ...other}) => ( + + + + + + + + + + + + + +); + +export default reduxForm({ + enableReinitialize: true, + destroyOnUnmount: false, + form: DASHBOARD_FILTERFORM, +})(DashboardFilters); diff --git a/src/ui/catalog/descriptor/DescriptorCard.tsx b/src/descriptors/ui/c/DescriptorCard.tsx similarity index 100% rename from src/ui/catalog/descriptor/DescriptorCard.tsx rename to src/descriptors/ui/c/DescriptorCard.tsx diff --git a/src/ui/catalog/descriptor/DescriptorFilterForm.tsx b/src/descriptors/ui/c/DescriptorFilterForm.tsx similarity index 100% rename from src/ui/catalog/descriptor/DescriptorFilterForm.tsx rename to src/descriptors/ui/c/DescriptorFilterForm.tsx diff --git a/src/descriptors/ui/c/DescriptorForm.tsx b/src/descriptors/ui/c/DescriptorForm.tsx index fc5b826..4822099 100644 --- a/src/descriptors/ui/c/DescriptorForm.tsx +++ b/src/descriptors/ui/c/DescriptorForm.tsx @@ -13,7 +13,7 @@ import Validators from 'utilities/Validators'; import { TextField } from 'ui/common/text-field'; import {MarkdownField} from 'ui/catalog/markdown'; import Heading from 'ui/common/heading'; -import SelectPartner from 'ui/catalog/partner/SelectPartner'; +import SelectPartner from 'partners/ui/c/SelectPartner'; import SelectVocabulary from './SelectVocabulary'; import Button from '@material-ui/core/Button'; @@ -26,7 +26,7 @@ import FormControlLabel from '@material-ui/core/FormControlLabel'; import Grid from '@material-ui/core/Grid'; import { setPageTitle } from 'actions/pageTitle'; import { bindActionCreators } from 'redux'; -import CropSelector from 'ui/catalog/crop/CropSelector'; +import CropSelector from 'crops/ui/c/CropSelector'; import withStyles from '@material-ui/core/styles/withStyles'; /* tslint:disable */ diff --git a/src/ui/catalog/descriptor/DescriptorListPicker.tsx b/src/descriptors/ui/c/DescriptorListPicker.tsx similarity index 100% rename from src/ui/catalog/descriptor/DescriptorListPicker.tsx rename to src/descriptors/ui/c/DescriptorListPicker.tsx diff --git a/src/ui/catalog/descriptor/DescriptorParser.tsx b/src/descriptors/ui/c/DescriptorParser.tsx similarity index 100% rename from src/ui/catalog/descriptor/DescriptorParser.tsx rename to src/descriptors/ui/c/DescriptorParser.tsx diff --git a/src/ui/catalog/descriptor/DescriptorPicker.tsx b/src/descriptors/ui/c/DescriptorPicker.tsx similarity index 98% rename from src/ui/catalog/descriptor/DescriptorPicker.tsx rename to src/descriptors/ui/c/DescriptorPicker.tsx index 78d1a39..51f505e 100644 --- a/src/ui/catalog/descriptor/DescriptorPicker.tsx +++ b/src/descriptors/ui/c/DescriptorPicker.tsx @@ -8,9 +8,9 @@ import { Page, Pagination } from 'model/common.model'; import { Descriptor, IDescriptorFilter } from 'model/descriptor.model'; import Button from '@material-ui/core/Button'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; +import DescriptorCard from 'descriptors/ui/c/DescriptorCard'; import PaginationComponent from 'ui/common/pagination'; -import DescriptorFilters from 'ui/catalog/descriptor/Filters'; +import DescriptorFilters from 'descriptors/ui/c/Filters'; import {log} from 'utilities/debug'; interface IDescriptorPickerProps extends React.ClassAttributes { diff --git a/src/ui/catalog/descriptor/DescriptorScale.tsx b/src/descriptors/ui/c/DescriptorScale.tsx similarity index 100% rename from src/ui/catalog/descriptor/DescriptorScale.tsx rename to src/descriptors/ui/c/DescriptorScale.tsx diff --git a/src/ui/catalog/descriptor/DescriptorSearchMenu.tsx b/src/descriptors/ui/c/DescriptorSearchMenu.tsx similarity index 97% rename from src/ui/catalog/descriptor/DescriptorSearchMenu.tsx rename to src/descriptors/ui/c/DescriptorSearchMenu.tsx index 6a19bef..8e37cd9 100644 --- a/src/ui/catalog/descriptor/DescriptorSearchMenu.tsx +++ b/src/descriptors/ui/c/DescriptorSearchMenu.tsx @@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {updateDescriptorFilterModel} from 'actions/filter'; -import DescriptorFilters from 'ui/catalog/descriptor/Filters'; +import DescriptorFilters from 'descriptors/ui/c/Filters'; import { IDescriptorFilter } from 'model/descriptor.model'; import {Page} from 'model/common.model'; import ExpandFiltersComponent from 'ui/common/filter/ExpandFiltersComponent'; diff --git a/src/ui/catalog/descriptor/Filters.tsx b/src/descriptors/ui/c/Filters.tsx similarity index 95% rename from src/ui/catalog/descriptor/Filters.tsx rename to src/descriptors/ui/c/Filters.tsx index ba674ea..bfad9b4 100644 --- a/src/ui/catalog/descriptor/Filters.tsx +++ b/src/descriptors/ui/c/Filters.tsx @@ -7,11 +7,11 @@ import StringFilter from 'ui/common/filter/StringFilter'; import StringArrFilter from 'ui/common/filter/StringArrFilter'; import BooleanFilter from 'ui/common/filter/BooleanFilter'; import TextFilter from 'ui/common/filter/TextFilter'; -import CropFilter from 'ui/catalog/crop/CropFilter'; +import CropFilter from 'crops/ui/c/CropFilter'; import {DESCRIPTOR_FILTER_FORM} from 'constants/filter'; import {Descriptor} from 'model/descriptor.model'; import DescriptorListPicker from './DescriptorListPicker'; -import PartnerFilter from 'ui/catalog/partner/PartnerFilter'; +import PartnerFilter from 'partners/ui/c/PartnerFilter'; // // diff --git a/src/ui/catalog/partner/PartnerFilter.tsx b/src/partners/ui/c/PartnerFilter.tsx similarity index 100% rename from src/ui/catalog/partner/PartnerFilter.tsx rename to src/partners/ui/c/PartnerFilter.tsx diff --git a/src/ui/catalog/partner/SelectPartner.tsx b/src/partners/ui/c/SelectPartner.tsx similarity index 100% rename from src/ui/catalog/partner/SelectPartner.tsx rename to src/partners/ui/c/SelectPartner.tsx diff --git a/src/ui/catalog/dashboard/c/Filters.tsx b/src/ui/catalog/dashboard/c/Filters.tsx index b2f240a..24a7ba5 100644 --- a/src/ui/catalog/dashboard/c/Filters.tsx +++ b/src/ui/catalog/dashboard/c/Filters.tsx @@ -5,10 +5,10 @@ import { DASHBOARD_FILTERFORM } from 'constants/dashboard'; import FiltersBlock from 'ui/common/filter/FiltersBlock'; import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch'; -import CropFilter from 'ui/catalog/crop/CropFilter'; +import CropFilter from 'crops/ui/c/CropFilter'; import TextFilter from 'ui/common/filter/TextFilter'; import Authorize from 'ui/common/authorized/Authorize'; -import PartnerFilter from 'ui/catalog/partner/PartnerFilter'; +import PartnerFilter from 'partners/ui/c/PartnerFilter'; import StatusFilter from './StatusFilter'; const DashboardFilters = ({handleSubmit, initialize, ...other}) => ( diff --git a/src/ui/pages/ui-design/tests/UiDescriptorCard.tsx b/src/ui/pages/ui-design/tests/UiDescriptorCard.tsx index 71b42bc..3120abb 100644 --- a/src/ui/pages/ui-design/tests/UiDescriptorCard.tsx +++ b/src/ui/pages/ui-design/tests/UiDescriptorCard.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import {Descriptor} from 'model/descriptor.model'; import {Partner} from 'model/partner.model'; -import DescriptorCard from 'ui/catalog/descriptor/DescriptorCard'; +import DescriptorCard from 'descriptors/ui/c/DescriptorCard'; export default function GuiTest({ style }: React.HTMLProps) { const d: Descriptor = new Descriptor({ diff --git a/src/ui/routes.tsx b/src/ui/routes.tsx index 541a762..174b48c 100644 --- a/src/ui/routes.tsx +++ b/src/ui/routes.tsx @@ -2,8 +2,8 @@ import WelcomePage from './pages/welcome'; import App from './App'; import Wrapper from 'ui/catalog/Wrapper'; -import CropBrowsePage from './pages/crop/BrowsePage'; -import CropEditPage from './pages/crop/EditPage'; +import CropBrowsePage from 'crops/ui/BrowsePage'; +import CropEditPage from 'crops/ui//EditPage'; import {datasetPublicRoutes, datasetDashboardRoutes} from 'datasets/routes'; import {descriptorListDashboardRoutes, descriptorListPublicRoutes} from 'descriptorlists/routes'; @@ -74,7 +74,7 @@ const routes = [ { path: '/', component: DatasetDashboardPage, - auth: [ROLE_USER], + auth: [ROLE_USER, ROLE_ADMINISTRATOR], extraProps: { title: 'My Dashboard', }, diff --git a/src/vocabulary/ui/c/VocabularyForm.tsx b/src/vocabulary/ui/c/VocabularyForm.tsx index 71c4f66..8c78a4e 100644 --- a/src/vocabulary/ui/c/VocabularyForm.tsx +++ b/src/vocabulary/ui/c/VocabularyForm.tsx @@ -14,7 +14,7 @@ import Heading from 'ui/common/heading'; import Validators from 'utilities/Validators'; import ItemsEditor from 'ui/common/ItemsEditor'; -import SelectPartner from 'ui/catalog/partner/SelectPartner'; +import SelectPartner from 'partners/ui/c/SelectPartner'; import Card, {CardHeader, CardContent, CardActions} from 'ui/common/Card'; import Button from '@material-ui/core/Button'; diff --git a/src/ui/catalog/vocabulary/VocabularyTermPicker.tsx b/src/vocabulary/ui/c/VocabularyTermPicker.tsx similarity index 100% rename from src/ui/catalog/vocabulary/VocabularyTermPicker.tsx rename to src/vocabulary/ui/c/VocabularyTermPicker.tsx -- GitLab
- - { loading ?
{ myLoadingIndicator }
: null } -
+ + { ! paged.last ?
{ myLoadingIndicator }
: null } +