diff --git a/locales/en/translations.json b/locales/en/translations.json index d374f8cbde8618966d1bb6f1e6c6507ed9f3c16b..766df607bd1f5cd3d4a62852ba5ab1221748ce4d 100644 --- a/locales/en/translations.json +++ b/locales/en/translations.json @@ -1078,7 +1078,10 @@ }, "c": { "card": { - "evaluationPeriod": "Evaluation period" + "evaluationPeriod": "Evaluation period", + "version": "Version", + "newVersionLink": "See current version of the subset", + "currentVersion": "Current version" }, "datasetDisplay": { "accessionsEvaluated": "Accessions evaluated", diff --git a/src/datasets/actions/dashboard.ts b/src/datasets/actions/dashboard.ts index 028014ebe3bfd534ed81f99c0b49ce7580f5b0e0..4b0a145cd8614582b3c48b7cbd60db27fedbd108 100644 --- a/src/datasets/actions/dashboard.ts +++ b/src/datasets/actions/dashboard.ts @@ -31,6 +31,7 @@ export { createDataset }; // Wrapped API Calls const apiMyDatasets = createApiCaller(DatasetService.myDatasets, DASHBOARD_APPEND_DATASET_PAGE); const apiListAccessions = createApiCaller(DatasetService.listAccessions, DASHBOARD_APPEND_ACCESSIONS_PAGE); +const apiCreateNewVersion = createApiCaller(DatasetService.createNewVersion, RECEIVE_DATASET); export const apiGetDataset = createApiCaller(DatasetService.getDataset, RECEIVE_DATASET); export const apiRejectDataset = createApiCaller(DatasetService.rejectDataset, RECEIVE_DATASET); @@ -71,6 +72,10 @@ export const loadDataset = (uuid: string) => (dispatch) => { return dispatch(apiGetDataset(uuid)); }; +export const createNewVersion = (uuid) => (dispatch) => { + return dispatch(apiCreateNewVersion(uuid)) + .then((newVersion) => dispatch(navigateTo(`/dashboard/datasets/${newVersion.uuid}/edit`))); +}; function publishDataset(datasetUuid: string) { return (dispatch, getState) => { diff --git a/src/datasets/reducers/dashboard.ts b/src/datasets/reducers/dashboard.ts index 98db215c17bb476583b8eb12dda4cf6f2d25cd1e..b389eb24d4535d0b2d00d1c7e7a0028f2ab886db 100644 --- a/src/datasets/reducers/dashboard.ts +++ b/src/datasets/reducers/dashboard.ts @@ -62,6 +62,7 @@ function datasetsDashboard(state = INITIAL_STATE, action: { type?: string, paylo return update(state, { dataset: { $set: apiCall }, paged: apiCall.loading ? { $set: state.paged } : { $set: null }, + accessionRefs: { $set: mustRemoveAccessions ? null : state.accessionRefs }, }); } } diff --git a/src/datasets/reducers/public.ts b/src/datasets/reducers/public.ts index ce4abcf671ef9821cd7db71706909e4ffd2af3a4..41df044053c3744de521b3af8dfaae49a3acec51 100644 --- a/src/datasets/reducers/public.ts +++ b/src/datasets/reducers/public.ts @@ -35,7 +35,7 @@ function datasetsPublic(state = INITIAL_STATE, action: { type?: string, payload? const {apiCall} = action.payload; const receivedIndex = state.paged && state.paged.data ? _.findIndex(state.paged.data.content, (item) => item.uuid === apiCall.uuid) : -1; - const mustRemoveAccessions = state.dataset && state.dataset.data && (apiCall.uuid !== state.dataset.data.uuid); + const mustRemoveAccessions = state.dataset && state.dataset.data && apiCall.data && (apiCall.uuid !== state.dataset.data.uuid); if (receivedIndex !== -1) { return update(state, { @@ -50,6 +50,7 @@ function datasetsPublic(state = INITIAL_STATE, action: { type?: string, payload? } else { return update(state, { dataset: { $set: apiCall }, + accessionRefs: { $set: mustRemoveAccessions ? null : state.accessionRefs }, }); } } diff --git a/src/datasets/translations.json b/src/datasets/translations.json index 263a3eca7e684a5acade1fbd7d6dcf5dadbcf99e..232937154bba2916d03ecc4161b2a5d8e2fbb2b5 100644 --- a/src/datasets/translations.json +++ b/src/datasets/translations.json @@ -147,7 +147,10 @@ }, "c": { "card": { - "evaluationPeriod": "Evaluation period" + "evaluationPeriod": "Evaluation period", + "version": "Version", + "newVersionLink": "See current version of the subset", + "currentVersion": "Current version" }, "datasetDisplay": { "accessionsEvaluated": "Accessions evaluated", diff --git a/src/datasets/ui/DisplayPage.tsx b/src/datasets/ui/DisplayPage.tsx index 91fd30af43d6f84d7db7e0e2e2cf40ba76669c69..ce5ead839f770c210e822fa7970158fd6471ba66 100644 --- a/src/datasets/ui/DisplayPage.tsx +++ b/src/datasets/ui/DisplayPage.tsx @@ -61,6 +61,14 @@ class DatasetDetail extends React.Component { } } + public componentWillReceiveProps(nextProps) { + const { loading, dataset, uuid, loadDataset, loadMoreAccessions } = nextProps; + if (!loading && uuid && (! dataset || uuid !== dataset.uuid)) { + loadDataset(uuid); + loadMoreAccessions(uuid); + } + } + private loadMoreAccessions = (paged: Page) => { const { loadMoreAccessions, dataset } = this.props; loadMoreAccessions(dataset.uuid, paged); diff --git a/src/datasets/ui/c/DatasetDisplay.tsx b/src/datasets/ui/c/DatasetDisplay.tsx index a67a33d4ccc9aead8bd79a6e2a4e8db1df24e36e..56c46b8fea592e7c75da0360a60fdefcccaa724c 100644 --- a/src/datasets/ui/c/DatasetDisplay.tsx +++ b/src/datasets/ui/c/DatasetDisplay.tsx @@ -40,6 +40,7 @@ import PagedLoader from 'ui/common/PagedLoader'; import AccessionRefCard from 'accessions/ui/c/AccessionRefCard'; import Number from 'ui/common/Number'; import DownloadDialog from 'ui/common/download-dialog'; +import {DatasetLink} from 'ui/genesys/Links'; const styles = (theme) => ({ root: { @@ -129,6 +130,9 @@ const styles = (theme) => ({ marginRight: '0', }, }, + hasNewVersion: { + backgroundColor: '#ffe2e2 !important', + }, }); interface IDetailInfoProps extends React.ClassAttributes { @@ -264,7 +268,7 @@ class DetailInfo extends React.Component { - { dataset.versionTag } }/> @@ -291,6 +295,13 @@ class DetailInfo extends React.Component { + { dataset.currentVersion && + + + { t('datasets.public.c.card.newVersionLink') } + + + } { publishDataset && (dataset._permissions.write || dataset._permissions.delete) && ( diff --git a/src/datasets/ui/dashboard/DashboardPage.tsx b/src/datasets/ui/dashboard/DashboardPage.tsx index 690ed2856e426305b50d65e39c906bb075f3bd22..8c38efbe61a7097d386476b719a23cbed2b23609 100644 --- a/src/datasets/ui/dashboard/DashboardPage.tsx +++ b/src/datasets/ui/dashboard/DashboardPage.tsx @@ -3,12 +3,27 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import BaseMyDataPage from 'ui/catalog/dashboard/MyDataPage'; -import { approveDataset, deleteDataset, loadMoreDatasets, unpublishDataset, publishDataset } from 'datasets/actions/dashboard'; +import { approveDataset, deleteDataset, loadMoreDatasets, unpublishDataset, publishDataset, createNewVersion } from 'datasets/actions/dashboard'; import Dataset from 'model/catalog/Dataset'; -import { DatasetLink } from 'ui/catalog/Links'; +import { DatasetLink } from 'ui/genesys/Links'; import { PublishState } from 'model/common.model'; +import ActionButton from 'ui/common/buttons/ActionButton'; -const renderDataLink = ({ row, children }) => ({ children }); +const renderDataLink = ({ row, children, needCurrent, t }) => ( + + { needCurrent ? { t('datasets.public.c.card.currentVersion') } + : { children } + } + +); + +const renderActions = ({ row, handleCreateNewVersion, t }) => ( +
+ { row.state === PublishState.PUBLISHED && + handleCreateNewVersion(row.uuid) }/> + } +
+); class DashboardPage extends BaseMyDataPage {} @@ -18,6 +33,7 @@ const mapStateToProps = (state, ownProps) => ({ dataClassName: Dataset.clazz, filterCode: ownProps.match.params.filterCode, renderDataLink, + renderActions, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ @@ -26,6 +42,7 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ publishOne: publishDataset, approveOne: approveDataset, unpublishOne: unpublishDataset, + createNewVersion: (uuid) => dispatch(createNewVersion(uuid)), }, dispatch); export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage); diff --git a/src/model/catalog/Dataset.ts b/src/model/catalog/Dataset.ts index 34d2afdffa23a0921d38156548da7add6a1a4e40..8e718ba625e06d8fa05d98fc99198a49212a789e 100644 --- a/src/model/catalog/Dataset.ts +++ b/src/model/catalog/Dataset.ts @@ -23,6 +23,7 @@ class Dataset implements IUserPermissions { public createdDate: Date; public creators: DatasetCreator[]; public crops: string[]; + public currentVersion: string; public description: string; public descriptorCount: number; public descriptors: Descriptor[]; diff --git a/src/service/catalog/DatasetService.ts b/src/service/catalog/DatasetService.ts index ddb6985a84b2635eca73eed549053fca312dbb7d..17498b94f1018a0c262adbe6cd6e8d851b9f71e5 100644 --- a/src/service/catalog/DatasetService.ts +++ b/src/service/catalog/DatasetService.ts @@ -42,6 +42,7 @@ const URL_DELETE_LOCATION = UrlTemplate.parse(`/api/v1/dataset/{uuid}/location/d const URL_LIST_LOCATION = UrlTemplate.parse(`/api/v1/dataset/{uuid}/location/list`); const URL_UPDATE_LOCATION = UrlTemplate.parse(`/api/v1/dataset/{uuid}/location/update`); const URL_LOAD_LOCATION_BY_UUID = UrlTemplate.parse(`/api/v1/dataset/{uuid}/location/{locationUuid}`); +const URL_CREATE_NEW_VERSION = `/api/v1/dataset/create-new-version`; /* * Defined in Swagger as 'dataset' @@ -137,6 +138,28 @@ class DatasetService { }).then(({ data }) => data as Dataset); } + /** + * createNewVersion at /api/v1/dataset/create-new-version + * + * @param uuid uuid + */ + public static createNewVersion(uuid: string, xhrConfig?): Promise { + + const qs = QueryString.stringify({ + uuid: uuid || undefined, + }, {}); + const apiUrl = URL_CREATE_NEW_VERSION + (qs ? `?${qs}` : ''); + // console.log(`Fetching from ${apiUrl}`); + const content = { /* No content in request body */ }; + + return axiosBackend.request({ + ...xhrConfig, + url: apiUrl, + method: 'POST', + ...content, + }).then(({ data }) => data as Dataset); + } + /** * reviewDataset at /api/v1/dataset/for-review * diff --git a/src/ui/catalog/dashboard/MyDataPage.tsx b/src/ui/catalog/dashboard/MyDataPage.tsx index 376b9f49c141254c1b3e4044c29bd283e292de25..64cf7374901e123421f3de58942b6c4575fdcf89 100644 --- a/src/ui/catalog/dashboard/MyDataPage.tsx +++ b/src/ui/catalog/dashboard/MyDataPage.tsx @@ -33,6 +33,8 @@ interface IDataPublishedContainerProps extends React.ClassAttributes { listMyData: any; dataClassName: string; renderDataLink: any; + renderActions: any; + createNewVersion: (uuid: string) => void; addToEditList: (item: any) => void; removeFromEditList: (item: any) => void; onPageChange: () => void; @@ -117,7 +119,7 @@ class BaseMyDataPage extends React.Component extends React.Component ({ }, /*tslint:enable*/ }, + cardActions: { + width: '100%', + display: 'flex', + flexDirection: 'row-reverse' as 'row-reverse', + }, }); class DashboardCard extends React.Component { @@ -61,7 +66,7 @@ class DashboardCard extends React.Component { } public render() { - const { item, tab, index, isEditMode, DataLink, dataClassName, t, classes } = this.props; + const { item, tab, index, isEditMode, DataLink, dataClassName, createNewVersion, Actions, t, classes } = this.props; const { inEditList } = this.state; return ( @@ -93,6 +98,11 @@ class DashboardCard extends React.Component { { ` ${t('descriptors.common.modelName', {count: item.descriptorCount})} ` } } + { item.currentVersion && + + + + } @@ -108,7 +118,10 @@ class DashboardCard extends React.Component { onChange={ this.onCheckboxChange } style={ !isEditMode ? { opacity: 0 } : {} } /> - { item._permissions.manage && } +
+ { item._permissions.manage && } + { Actions && } +
); diff --git a/src/ui/catalog/dashboard/c/MyDataCards.tsx b/src/ui/catalog/dashboard/c/MyDataCards.tsx index 19815002bc9d9a82bdc4db6046b64b74e07652e4..171f3c71c3e4ee236334fc2e078f234dd64d24c0 100644 --- a/src/ui/catalog/dashboard/c/MyDataCards.tsx +++ b/src/ui/catalog/dashboard/c/MyDataCards.tsx @@ -32,6 +32,8 @@ interface IMyDataCardsProps extends React.Props { onFilter: (filter) => void; dataClassName: string; renderDataLink: any; + renderActions: any; + createNewVersion: (uuid: string) => void; pagination: any; promiseListData: any; deleteAllAction: any; @@ -74,6 +76,8 @@ class MyDataCards extends React.Component { removeFromEditAction={ this.props.removeFromEditList } dataClassName={ this.props.dataClassName } DataLink={ this.props.renderDataLink } + Actions={ this.props.renderActions } + createNewVersion={ this.props.createNewVersion } /> ) diff --git a/src/ui/genesys/Links.tsx b/src/ui/genesys/Links.tsx index 981daf0b2e56074b7d220f1c63c45bf356bcea83..d9c45712ce535e1e8419a16f82d2efb33572de73 100644 --- a/src/ui/genesys/Links.tsx +++ b/src/ui/genesys/Links.tsx @@ -3,6 +3,7 @@ import { Link } from 'react-router-dom'; import Markdown from 'ui/common/markdown'; import Subset from 'model/subset/Subset'; +import Dataset from 'model/catalog/Dataset'; import Accession from 'model/accession/Accession'; import FaoInstitute from 'model/genesys/FaoInstitute'; import MaterialRequest from 'model/request/MaterialRequest'; @@ -137,16 +138,20 @@ const RegionLink = ({ region, children }: { region: GeoRegion, children?: any }) ); }; -const DatasetLink = ({ to: dataset, edit = false, children = null } - : { to: any, edit?: boolean, children?: any }) => { +const DatasetLink = ({ to: dataset, uuid = null, edit = false, children = null } + : { to?: Dataset, uuid?: string, edit?: boolean, children?: any }) => { if (dataset) { return ( - + { children || } ); } else { - return null; + return uuid && children ? ( + + { children } + + ) : null; } };