Old versions are requested only when the details panel is open.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas@di-pentima.com.ar>
<Grid container justify="space-between">
<Typography variant="caption" className={classes.nameHeader}>
Name
- </Typography>
+ </Typography>
<Typography variant="caption" className={classes.fileSizeHeader}>
File size
- </Typography>
+ </Typography>
</Grid>
{isLoading
? <div className={classes.centeredLabel}><CircularProgress /></div>
// SPDX-License-Identifier: AGPL-3.0
import { Dispatch } from "redux";
-import { loadCollectionFiles, COLLECTION_PANEL_LOAD_FILES_THRESHOLD } from "./collection-panel-files/collection-panel-files-actions";
+import {
+ loadCollectionFiles,
+ COLLECTION_PANEL_LOAD_FILES_THRESHOLD
+} from "./collection-panel-files/collection-panel-files-actions";
import { CollectionResource } from '~/models/collection';
import { RootState } from "~/store/store";
import { ServiceRepository } from "~/services/services";
export const collectionPanelActions = unionize({
SET_COLLECTION: ofType<CollectionResource>(),
- LOAD_COLLECTION: ofType<{ uuid: string }>(),
LOAD_COLLECTION_SUCCESS: ofType<{ item: CollectionResource }>(),
LOAD_BIG_COLLECTIONS: ofType<boolean>(),
});
export const loadCollectionPanel = (uuid: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
const { collectionPanel: { item } } = getState();
- dispatch(collectionPanelActions.LOAD_COLLECTION({ uuid }));
const collection = item ? item : await services.collectionService.get(uuid);
- dispatch(loadDetailsPanel(collection.uuid));
+ dispatch<any>(loadDetailsPanel(collection.uuid));
dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: collection }));
dispatch(resourcesActions.SET_RESOURCES([collection]));
if (collection.fileCount <= COLLECTION_PANEL_LOAD_FILES_THRESHOLD &&
import { resourcesActions } from '~/store/resources/resources-actions';
import {snackbarActions, SnackbarKind} from '~/store/snackbar/snackbar-actions';
import { addProperty, deleteProperty } from '~/lib/resource-properties';
+import { FilterBuilder } from '~/services/api/filter-builder';
+import { OrderBuilder } from '~/services/api/order-builder';
+import { CollectionResource } from '~/models/collection';
+import { extractUuidKind, ResourceKind } from '~/models/resource';
export const SLIDE_TIMEOUT = 500;
export const detailsPanelActions = unionize({
TOGGLE_DETAILS_PANEL: ofType<{}>(),
- OPEN_DETAILS_PANEL: ofType<string>(),
+ OPEN_DETAILS_PANEL: ofType<number>(),
LOAD_DETAILS_PANEL: ofType<string>()
});
export const PROJECT_PROPERTIES_FORM_NAME = 'projectPropertiesFormName';
export const PROJECT_PROPERTIES_DIALOG_NAME = 'projectPropertiesDialogName';
-export const loadDetailsPanel = (uuid: string) => detailsPanelActions.LOAD_DETAILS_PANEL(uuid);
+export const loadDetailsPanel = (uuid: string) =>
+ (dispatch: Dispatch, getState: () => RootState) => {
+ if (getState().detailsPanel.isOpened) {
+ switch(extractUuidKind(uuid)) {
+ case ResourceKind.COLLECTION:
+ dispatch<any>(refreshCollectionVersionsList(uuid));
+ break;
+ default:
+ break;
+ }
+ }
+ dispatch(detailsPanelActions.LOAD_DETAILS_PANEL(uuid));
+ };
-export const openDetailsPanel = (uuid: string) => detailsPanelActions.OPEN_DETAILS_PANEL(uuid);
+export const openDetailsPanel = (uuid: string, tabNr: number = 0) =>
+ (dispatch: Dispatch) => {
+ dispatch<any>(loadDetailsPanel(uuid));
+ dispatch(detailsPanelActions.OPEN_DETAILS_PANEL(tabNr));
+ };
export const openProjectPropertiesDialog = () =>
(dispatch: Dispatch) => {
dispatch<any>(dialogActions.OPEN_DIALOG({ id: PROJECT_PROPERTIES_DIALOG_NAME, data: { } }));
};
+export const refreshCollectionVersionsList = (uuid: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const versions = await services.collectionService.list({
+ filters: new FilterBuilder()
+ .addEqual('current_version_uuid', uuid)
+ .getFilters(),
+ includeOldVersions: true,
+ order: new OrderBuilder<CollectionResource>().addDesc("version").getOrder()
+ });
+ dispatch(resourcesActions.SET_RESOURCES(versions.items.slice(1)));
+ };
+
export const deleteProjectProperty = (key: string, value: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
const { detailsPanel, resources } = getState();
export interface DetailsPanelState {
resourceUuid: string;
isOpened: boolean;
+ tabNr: number;
}
const initialState = {
resourceUuid: '',
- isOpened: false
+ isOpened: false,
+ tabNr: 0
};
export const detailsPanelReducer = (state: DetailsPanelState = initialState, action: DetailsPanelAction) =>
detailsPanelActions.match(action, {
default: () => state,
LOAD_DETAILS_PANEL: resourceUuid => ({ ...state, resourceUuid }),
- OPEN_DETAILS_PANEL: resourceUuid => ({ resourceUuid, isOpened: true }),
+ OPEN_DETAILS_PANEL: tabNr => ({ ...state, isOpened: true, tabNr }),
TOGGLE_DETAILS_PANEL: () => ({ ...state, isOpened: !state.isOpened }),
});
const process = await dispatch<any>(processesActions.loadProcess(uuid));
await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
dispatch<any>(setProcessBreadcrumbs(uuid));
- dispatch(loadDetailsPanel(uuid));
+ dispatch<any>(loadDetailsPanel(uuid));
});
export const updateProcess = (data: processUpdateActions.ProcessUpdateFormDialogData) =>
dispatch<any>(openCollectionFilesContextMenu(event, isWritable));
},
onFileClick: (id) => {
- dispatch(openDetailsPanel(id));
+ dispatch<any>(openDetailsPanel(id));
},
});
import { CollectionResource } from '~/models/collection';
import { DetailsData } from "./details-data";
import { CollectionDetailsAttributes } from '~/views/collection-panel/collection-panel';
+import { RootState } from '~/store/store';
+import { filterResources, getResource } from '~/store/resources/resources';
+import { connect } from 'react-redux';
+import { Grid, ListItem, StyleRulesCallback, Typography, withStyles, WithStyles } from '@material-ui/core';
+import { formatDate, formatFileSize } from '~/common/formatters';
+import { Dispatch } from 'redux';
+import { navigateTo } from '~/store/navigation/navigation-action';
+
+export type CssRules = 'versionBrowserHeader' | 'selectedVersion';
+
+const styles: StyleRulesCallback<CssRules> = theme => ({
+ versionBrowserHeader: {
+ textAlign: 'center',
+ fontWeight: 'bold'
+ },
+ selectedVersion: {
+ fontWeight: 'bold'
+ }
+});
export class CollectionDetails extends DetailsData<CollectionResource> {
}
private getVersionBrowser() {
- return <div />;
+ return <CollectionVersionBrowser />;
}
}
+
+interface CollectionVersionBrowserProps {
+ currentCollection: CollectionResource | undefined;
+ versions: CollectionResource[];
+}
+
+interface CollectionVersionBrowserDispatchProps {
+ showVersion: (c: CollectionResource) => void;
+}
+
+const mapStateToProps = (state: RootState): CollectionVersionBrowserProps => {
+ const currentCollection = getResource<CollectionResource>(state.detailsPanel.resourceUuid)(state.resources);
+ const versions = currentCollection
+ && filterResources(rsc =>
+ (rsc as CollectionResource).currentVersionUuid === currentCollection.currentVersionUuid)(state.resources)
+ .sort((a: CollectionResource, b: CollectionResource) => b.version - a.version) as CollectionResource[]
+ || [];
+ return { currentCollection, versions };
+};
+
+const mapDispatchToProps = () =>
+ (dispatch: Dispatch): CollectionVersionBrowserDispatchProps => ({
+ showVersion: (collection) => dispatch<any>(navigateTo(collection.uuid)),
+ });
+
+const CollectionVersionBrowser = withStyles(styles)(
+ connect(mapStateToProps, mapDispatchToProps)(
+ ({ currentCollection, versions, showVersion, classes }: CollectionVersionBrowserProps & CollectionVersionBrowserDispatchProps & WithStyles<CssRules>) => {
+ return <>
+ <Grid container justify="space-between">
+ <Typography variant="caption" className={classes.versionBrowserHeader}>
+ Version
+ </Typography>
+ <Typography variant="caption" className={classes.versionBrowserHeader}>
+ Size
+ </Typography>
+ <Typography variant="caption" className={classes.versionBrowserHeader}>
+ Date
+ </Typography>
+ </Grid>
+ { versions.map(item => {
+ const isSelectedVersion = !!(currentCollection && currentCollection.uuid === item.uuid);
+ return (
+ <ListItem button
+ className={isSelectedVersion ? 'selectedVersion' : ''}
+ key={item.version}
+ onClick={e => showVersion(item)}
+ selected={isSelectedVersion}>
+ <Grid container justify="space-between">
+ <Typography variant="caption">
+ {item.version}
+ </Typography>
+ <Typography variant="caption">
+ {formatFileSize(item.fileSizeTotal)}
+ </Typography>
+ <Typography variant="caption">
+ {formatDate(item.modifiedAt)}
+ </Typography>
+ </Grid>
+ </ListItem>
+ );
+ })}
+ </>;
+ }));
\ No newline at end of file
}
handleRowClick = (uuid: string) => {
- this.props.dispatch(loadDetailsPanel(uuid));
+ this.props.dispatch<any>(loadDetailsPanel(uuid));
}
render() {
const { item } = this.props;
if (item) {
e.stopPropagation();
- this.props.dispatch(openDetailsPanel(item.uuid));
+ this.props.dispatch<any>(openDetailsPanel(item.uuid));
}
}
}
handleRowClick = (uuid: string) => {
- this.props.dispatch(loadDetailsPanel(uuid));
+ this.props.dispatch<any>(loadDetailsPanel(uuid));
}
render() {
}
handleRowClick = (uuid: string) => {
- this.props.dispatch(loadDetailsPanel(uuid));
+ this.props.dispatch<any>(loadDetailsPanel(uuid));
}
}
}
handleRowClick = (uuid: string) => {
- this.props.dispatch(loadDetailsPanel(uuid));
+ this.props.dispatch<any>(loadDetailsPanel(uuid));
}
}
)
}
handleRowClick = (uuid: string) => {
- this.props.dispatch(loadDetailsPanel(uuid));
+ this.props.dispatch<any>(loadDetailsPanel(uuid));
}
}
)