[ARVADOS-WORKBENCH2] created: 2.2.1-32-ge5dc88dd
Git user
git at public.arvados.org
Wed Jul 14 23:10:59 UTC 2021
at e5dc88dd1a6c54610d92854d527e5048543d93ec (commit)
commit e5dc88dd1a6c54610d92854d527e5048543d93ec
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Wed Jul 14 18:04:22 2021 -0300
17573: Adds storage selection checkboxes to edit dialog.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/store/collections/collection-update-actions.ts b/src/store/collections/collection-update-actions.ts
index 3f3b662f..a9077cfb 100644
--- a/src/store/collections/collection-update-actions.ts
+++ b/src/store/collections/collection-update-actions.ts
@@ -19,6 +19,7 @@ export interface CollectionUpdateFormDialogData {
uuid: string;
name: string;
description?: string;
+ storageClassesDesired?: string[];
}
export const COLLECTION_UPDATE_FORM_NAME = 'collectionUpdateFormName';
@@ -37,6 +38,7 @@ export const updateCollection = (collection: CollectionUpdateFormDialogData) =>
services.collectionService.update(uuid, {
name: collection.name,
+ storageClassesDesired: collection.storageClassesDesired,
description: collection.description }
).then(updatedCollection => {
dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: updatedCollection as CollectionResource }));
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index 038b31e2..556d83b4 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -39,6 +39,7 @@ export type ContextMenuResource = {
isEditable?: boolean;
outputUuid?: string;
workflowUuid?: string;
+ storageClassesDesired?: string[];
};
export const isKeyboardClick = (event: React.MouseEvent<HTMLElement>) => event.nativeEvent.detail === 0;
diff --git a/src/views-components/details-panel/collection-details.tsx b/src/views-components/details-panel/collection-details.tsx
index 0e747fed..c61b3340 100644
--- a/src/views-components/details-panel/collection-details.tsx
+++ b/src/views-components/details-panel/collection-details.tsx
@@ -87,6 +87,8 @@ const mapDispatchToProps = () =>
dispatch<any>(openContextMenu(event, {
name: collection.name,
uuid: collection.uuid,
+ description: collection.description,
+ storageClassesDesired: collection.storageClassesDesired,
ownerUuid: collection.ownerUuid,
isTrashed: collection.isTrashed,
kind: collection.kind,
diff --git a/src/views-components/dialog-forms/update-collection-dialog.ts b/src/views-components/dialog-forms/update-collection-dialog.ts
index 36e5cc39..e5d52f0b 100644
--- a/src/views-components/dialog-forms/update-collection-dialog.ts
+++ b/src/views-components/dialog-forms/update-collection-dialog.ts
@@ -2,19 +2,23 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { compose } from "redux";
+import { compose, Dispatch } from "redux";
import { reduxForm } from 'redux-form';
import { withDialog } from "store/dialog/with-dialog";
import { DialogCollectionUpdate } from 'views-components/dialog-update/dialog-collection-update';
-import { COLLECTION_UPDATE_FORM_NAME, CollectionUpdateFormDialogData, updateCollection } from 'store/collections/collection-update-actions';
+import {
+ COLLECTION_UPDATE_FORM_NAME,
+ CollectionUpdateFormDialogData,
+ updateCollection
+} from 'store/collections/collection-update-actions';
export const UpdateCollectionDialog = compose(
withDialog(COLLECTION_UPDATE_FORM_NAME),
reduxForm<CollectionUpdateFormDialogData>({
touchOnChange: true,
form: COLLECTION_UPDATE_FORM_NAME,
- onSubmit: (data, dispatch) => {
- dispatch(updateCollection(data));
+ onSubmit: (data: CollectionUpdateFormDialogData, dispatch: Dispatch) => {
+ dispatch<any>(updateCollection(data));
}
})
)(DialogCollectionUpdate);
\ No newline at end of file
diff --git a/src/views-components/dialog-update/dialog-collection-update.tsx b/src/views-components/dialog-update/dialog-collection-update.tsx
index c30ceaac..cce64d27 100644
--- a/src/views-components/dialog-update/dialog-collection-update.tsx
+++ b/src/views-components/dialog-update/dialog-collection-update.tsx
@@ -7,7 +7,11 @@ import { InjectedFormProps } from 'redux-form';
import { WithDialogProps } from 'store/dialog/with-dialog';
import { CollectionUpdateFormDialogData } from 'store/collections/collection-update-actions';
import { FormDialog } from 'components/form-dialog/form-dialog';
-import { CollectionNameField, CollectionDescriptionField } from 'views-components/form-fields/collection-form-fields';
+import {
+ CollectionNameField,
+ CollectionDescriptionField,
+ CollectionStorageClassesField
+} from 'views-components/form-fields/collection-form-fields';
type DialogCollectionProps = WithDialogProps<{}> & InjectedFormProps<CollectionUpdateFormDialogData>;
@@ -22,4 +26,5 @@ export const DialogCollectionUpdate = (props: DialogCollectionProps) =>
const CollectionEditFields = () => <span>
<CollectionNameField />
<CollectionDescriptionField />
+ <CollectionStorageClassesField />
</span>;
diff --git a/src/views-components/form-fields/collection-form-fields.tsx b/src/views-components/form-fields/collection-form-fields.tsx
index b882d684..db18f76d 100644
--- a/src/views-components/form-fields/collection-form-fields.tsx
+++ b/src/views-components/form-fields/collection-form-fields.tsx
@@ -13,6 +13,8 @@ import { ProjectTreePickerField, CollectionTreePickerField } from "views-compone
import { PickerIdProp } from 'store/tree-picker/picker-id';
import { connect } from "react-redux";
import { RootState } from "store/store";
+import { MultiCheckboxField } from "components/checkbox-field/checkbox-field";
+import { getStorageClasses } from "common/config";
interface CollectionNameFieldProps {
validate: Validator[];
@@ -55,3 +57,23 @@ export const CollectionPickerField = (props: PickerIdProp) =>
pickerId={props.pickerId}
component={CollectionTreePickerField}
validate={COLLECTION_PROJECT_VALIDATION} />;
+
+interface StorageClassesProps {
+ items: string[];
+}
+
+export const CollectionStorageClassesField = connect(
+ (state: RootState) => {
+ return {
+ items: getStorageClasses(state.auth.config)
+ };
+ })(
+ (props: StorageClassesProps) =>
+ <Field
+ name='storageClassesDesired'
+ label='Storage classes'
+ minSelection={1}
+ rowLayout={true}
+ helperText='At least one class should be selected'
+ component={MultiCheckboxField}
+ items={props.items} />);
\ No newline at end of file
diff --git a/src/views/collection-content-address-panel/collection-content-address-panel.tsx b/src/views/collection-content-address-panel/collection-content-address-panel.tsx
index 13e131b0..88638085 100644
--- a/src/views/collection-content-address-panel/collection-content-address-panel.tsx
+++ b/src/views/collection-content-address-panel/collection-content-address-panel.tsx
@@ -34,6 +34,9 @@ import {
ResourceLastModifiedDate,
ResourceStatus
} from 'views-components/data-explorer/renderers';
+import { getResource, ResourcesState } from 'store/resources/resources';
+import { RootState } from 'store/store';
+import { CollectionResource } from 'models/collection';
type CssRules = 'backLink' | 'backIcon' | 'card' | 'title' | 'iconHeader' | 'link';
@@ -110,18 +113,29 @@ export const collectionContentAddressPanelColumns: DataColumns<string> = [
}
];
-export interface CollectionContentAddressPanelActionProps {
- onContextMenu: (event: React.MouseEvent<any>, uuid: string) => void;
+interface CollectionContentAddressPanelActionProps {
+ onContextMenu: (resources: ResourcesState) => (event: React.MouseEvent<any>, uuid: string) => void;
onItemClick: (item: string) => void;
onItemDoubleClick: (item: string) => void;
}
+interface CollectionContentAddressPanelDataProps {
+ resources: ResourcesState;
+}
+
+const mapStateToProps = ({ resources }: RootState): CollectionContentAddressPanelDataProps => ({
+ resources
+})
+
const mapDispatchToProps = (dispatch: Dispatch): CollectionContentAddressPanelActionProps => ({
- onContextMenu: (event, resourceUuid) => {
+ onContextMenu: (resources: ResourcesState) => (event, resourceUuid) => {
+ const resource = getResource<CollectionResource>(resourceUuid)(resources);
const kind = dispatch<any>(resourceUuidToContextMenuKind(resourceUuid));
if (kind) {
dispatch<any>(openContextMenu(event, {
- name: '',
+ name: resource ? resource.name : '',
+ description: resource ? resource.description : '',
+ storageClassesDesired: resource ? resource.storageClassesDesired : [],
uuid: resourceUuid,
ownerUuid: '',
kind: ResourceKind.NONE,
@@ -145,8 +159,8 @@ interface CollectionContentAddressDataProps {
}
export const CollectionsContentAddressPanel = withStyles(styles)(
- connect(null, mapDispatchToProps)(
- class extends React.Component<CollectionContentAddressPanelActionProps & CollectionContentAddressDataProps & WithStyles<CssRules>> {
+ connect(mapStateToProps, mapDispatchToProps)(
+ class extends React.Component<CollectionContentAddressPanelActionProps & CollectionContentAddressPanelDataProps & CollectionContentAddressDataProps & WithStyles<CssRules>> {
render() {
return <Grid item xs={12}>
<Button
@@ -160,7 +174,7 @@ export const CollectionsContentAddressPanel = withStyles(styles)(
hideSearchInput
onRowClick={this.props.onItemClick}
onRowDoubleClick={this.props.onItemDoubleClick}
- onContextMenu={this.props.onContextMenu}
+ onContextMenu={this.props.onContextMenu(this.props.resources)}
contextMenuColumn={true}
title={`Content address: ${this.props.match.params.id}`}
dataTableDefaultView={
diff --git a/src/views/favorite-panel/favorite-panel.tsx b/src/views/favorite-panel/favorite-panel.tsx
index 82336b4a..404baeb9 100644
--- a/src/views/favorite-panel/favorite-panel.tsx
+++ b/src/views/favorite-panel/favorite-panel.tsx
@@ -39,6 +39,7 @@ import { GroupContentsResource } from 'services/groups-service/groups-service';
import { GroupClass, GroupResource } from 'models/group';
import { getProperty } from 'store/properties/properties';
import { PROJECT_PANEL_CURRENT_UUID } from 'store/project-panel/project-panel-action';
+import { CollectionResource } from 'models/collection';
type CssRules = "toolbar" | "button";
@@ -151,7 +152,7 @@ export const FavoritePanel = withStyles(styles)(
const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid, readonly));
- if (menuKind&& resource) {
+ if (menuKind && resource) {
this.props.dispatch<any>(openContextMenu(event, {
name: resource.name,
uuid: resource.uuid,
@@ -160,6 +161,7 @@ export const FavoritePanel = withStyles(styles)(
kind: resource.kind,
menuKind,
description: resource.description,
+ storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
}));
}
this.props.dispatch<any>(loadDetailsPanel(resourceUuid));
diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx
index ed8a706a..67264511 100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@ -45,6 +45,7 @@ import {
} from 'store/resource-type-filters/resource-type-filters';
import { GroupContentsResource } from 'services/groups-service/groups-service';
import { GroupClass, GroupResource } from 'models/group';
+import { CollectionResource } from 'models/collection';
type CssRules = 'root' | "button";
@@ -185,6 +186,7 @@ export const ProjectPanel = withStyles(styles)(
kind: resource.kind,
menuKind,
description: resource.description,
+ storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
}));
}
this.props.dispatch<any>(loadDetailsPanel(resourceUuid));
diff --git a/src/views/public-favorites-panel/public-favorites-panel.tsx b/src/views/public-favorites-panel/public-favorites-panel.tsx
index 1b7185de..ee09654a 100644
--- a/src/views/public-favorites-panel/public-favorites-panel.tsx
+++ b/src/views/public-favorites-panel/public-favorites-panel.tsx
@@ -37,6 +37,7 @@ import { PUBLIC_FAVORITE_PANEL_ID } from 'store/public-favorites-panel/public-fa
import { PublicFavoritesState } from 'store/public-favorites/public-favorites-reducer';
import { getResource, ResourcesState } from 'store/resources/resources';
import { GroupContentsResource } from 'services/groups-service/groups-service';
+import { CollectionResource } from 'models/collection';
type CssRules = "toolbar" | "button";
@@ -134,6 +135,7 @@ const mapDispatchToProps = (dispatch: Dispatch): PublicFavoritePanelActionProps
dispatch<any>(openContextMenu(event, {
name: resource.name,
description: resource.description,
+ storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
uuid: resourceUuid,
ownerUuid: '',
kind: ResourceKind.NONE,
commit ad956f33b83e55aadca7189d5352940aaeadd659
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Wed Jul 14 17:55:15 2021 -0300
17573: Adds redux-form controlled multi-checkbox selection component.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/components/checkbox-field/checkbox-field.tsx b/src/components/checkbox-field/checkbox-field.tsx
index 2b2a8a03..bfa3714a 100644
--- a/src/components/checkbox-field/checkbox-field.tsx
+++ b/src/components/checkbox-field/checkbox-field.tsx
@@ -4,7 +4,14 @@
import React from 'react';
import { WrappedFieldProps } from 'redux-form';
-import { FormControlLabel, Checkbox } from '@material-ui/core';
+import {
+ FormControlLabel,
+ Checkbox,
+ FormControl,
+ FormGroup,
+ FormLabel,
+ FormHelperText
+} from '@material-ui/core';
export const CheckboxField = (props: WrappedFieldProps & { label?: string }) =>
<FormControlLabel
@@ -15,5 +22,46 @@ export const CheckboxField = (props: WrappedFieldProps & { label?: string }) =>
disabled={props.meta.submitting}
color="primary" />
}
- label={props.label}
- />;
\ No newline at end of file
+ label={props.label}
+ />;
+
+type MultiCheckboxFieldProps = {
+ items: string[];
+ label?: string;
+ minSelection?: number;
+ maxSelection?: number;
+ helperText?: string;
+ rowLayout?: boolean;
+}
+
+export const MultiCheckboxField = (props: WrappedFieldProps & MultiCheckboxFieldProps) => {
+ const isValid = (items: string[]) => (items.length >= (props.minSelection || 0)) &&
+ (items.length <= (props.maxSelection || items.length));
+ return <FormControl error={!isValid(props.input.value)}>
+ <FormLabel component='label'>{props.label}</FormLabel>
+ <FormGroup row={props.rowLayout}>
+ { props.items.map((item, idx) =>
+ <FormControlLabel
+ control={
+ <Checkbox
+ key={idx}
+ name={`${props.input.name}[${idx}]`}
+ value={item}
+ checked={props.input.value.indexOf(item) !== -1}
+ onChange={e => {
+ const newValue = [...props.input.value];
+ if (e.target.checked) {
+ newValue.push(item);
+ } else {
+ newValue.splice(newValue.indexOf(item), 1);
+ }
+ if (!isValid(newValue)) { return; }
+ return props.input.onChange(newValue);
+ }}
+ disabled={props.meta.submitting}
+ color="primary" />
+ }
+ label={item} />) }
+ </FormGroup>
+ <FormHelperText>{props.helperText}</FormHelperText>
+ </FormControl> };
\ No newline at end of file
commit 40f03448780c8b22cba93d4eff9ca976cea45abf
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Wed Jul 14 17:52:54 2021 -0300
17573: Adds storage classes information to the collection panel.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/views/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx
index 94a5af33..4270cbbd 100644
--- a/src/views/collection-panel/collection-panel.tsx
+++ b/src/views/collection-panel/collection-panel.tsx
@@ -237,13 +237,14 @@ export const CollectionPanel = withStyles(styles)(
}
handleContextMenu = (event: React.MouseEvent<any>) => {
- const { uuid, ownerUuid, name, description, kind } = this.props.item;
+ const { uuid, ownerUuid, name, description, kind, storageClassesDesired } = this.props.item;
const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(uuid));
const resource = {
uuid,
ownerUuid,
name,
description,
+ storageClassesDesired,
kind,
menuKind,
};
@@ -341,5 +342,9 @@ export const CollectionDetailsAttributes = (props: { item: CollectionResource, t
<DetailsAttribute classLabel={classes.label} classValue={classes.value}
label='Content size' value={formatFileSize(item.fileSizeTotal)} />
</Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute classLabel={classes.label} classValue={classes.value}
+ label='Storage classes' value={item.storageClassesDesired.join(', ')} />
+ </Grid>
</Grid>;
};
commit 3556e5483957f8479c5747e36c626e91a655cc21
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Thu Jul 8 19:18:06 2021 -0300
17573: Adds Volumes config support.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/common/config.ts b/src/common/config.ts
index f3d06840..8a85ae00 100644
--- a/src/common/config.ts
+++ b/src/common/config.ts
@@ -91,6 +91,13 @@ export interface ClusterConfigJSON {
}
}
};
+ Volumes: {
+ [key: string]: {
+ StorageClasses: {
+ [key: string]: boolean;
+ }
+ }
+ };
}
export class Config {
@@ -130,6 +137,19 @@ export const buildConfig = (clusterConfig: ClusterConfigJSON): Config => {
return config;
};
+export const getStorageClasses = (config: Config): string[] => {
+ const classes: Set<string> = new Set();
+ const volumes = config.clusterConfig.Volumes;
+ Object.keys(volumes).forEach(v => {
+ Object.keys(volumes[v].StorageClasses).forEach(sc => {
+ if (volumes[v].StorageClasses[sc]) {
+ classes.add(sc);
+ }
+ });
+ });
+ return Array.from(classes);
+};
+
const getApiRevision = async (apiUrl: string) => {
try {
const dd = (await Axios.get<any>(`${apiUrl}/${DISCOVERY_DOC_PATH}`)).data;
@@ -252,6 +272,7 @@ export const mockClusterConfigJSON = (config: Partial<ClusterConfigJSON>): Clust
Collections: {
ForwardSlashNameSubstitution: "",
},
+ Volumes: {},
...config
});
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list