There's too much code duplication. Some might be simple to avoid.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>
// SPDX-License-Identifier: AGPL-3.0
import { Dispatch } from "redux";
-import { reset, startSubmit, stopSubmit, initialize, FormErrors } from 'redux-form';
+import { reset, startSubmit, stopSubmit, initialize, FormErrors, change, formValueSelector } from 'redux-form';
import { RootState } from 'store/store';
import { getUserUuid } from "common/getuser";
import { dialogActions } from "store/dialog/dialog-actions";
import { isProjectOrRunProcessRoute } from 'store/projects/project-create-actions';
import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
import { CollectionResource } from "models/collection";
+import { ResourcePropertiesFormData } from "views-components/resource-properties-form/resource-properties-form";
+import { addProperty, deleteProperty } from "lib/resource-properties";
export interface CollectionCreateFormDialogData {
ownerUuid: string;
name: string;
description: string;
storageClassesDesired: string[];
+ properties: CollectionProperties;
+}
+
+export interface CollectionProperties {
+ [key: string]: string | string[];
}
export const COLLECTION_CREATE_FORM_NAME = "collectionCreateFormName";
+export const COLLECTION_CREATE_PROPERTIES_FORM_NAME = "collectionCreatePropertiesFormName";
+export const COLLECTION_CREATE_FORM_SELECTOR = formValueSelector(COLLECTION_CREATE_FORM_NAME);
export const openCollectionCreateDialog = (ownerUuid: string) =>
(dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_CREATE_FORM_NAME));
}
};
+
+export const addPropertyToCreateCollectionForm = (data: ResourcePropertiesFormData) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const properties = { ...COLLECTION_CREATE_FORM_SELECTOR(getState(), 'properties') };
+ const key = data.keyID || data.key;
+ const value = data.valueID || data.value;
+ dispatch(change(
+ COLLECTION_CREATE_FORM_NAME,
+ 'properties',
+ addProperty(properties, key, value)));
+ };
+
+export const removePropertyFromCreateCollectionForm = (key: string, value: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const properties = { ...COLLECTION_CREATE_FORM_SELECTOR(getState(), 'properties') };
+ dispatch(change(
+ COLLECTION_CREATE_FORM_NAME,
+ 'properties',
+ deleteProperty(properties, key, value)));
+ };
// SPDX-License-Identifier: AGPL-3.0
import { Dispatch } from "redux";
-import { FormErrors, initialize, startSubmit, stopSubmit } from 'redux-form';
+import {
+ change,
+ FormErrors,
+ formValueSelector,
+ initialize,
+ startSubmit,
+ stopSubmit
+} from 'redux-form';
import { RootState } from "store/store";
import { collectionPanelActions } from "store/collection-panel/collection-panel-action";
import { dialogActions } from "store/dialog/dialog-actions";
import { updateResources } from "../resources/resources-actions";
import { loadDetailsPanel } from "../details-panel/details-panel-action";
import { getResource } from "store/resources/resources";
+import { CollectionProperties } from "./collection-create-actions";
+import { ResourcePropertiesFormData } from "views-components/resource-properties-form/resource-properties-form";
+import { addProperty, deleteProperty } from "lib/resource-properties";
export interface CollectionUpdateFormDialogData {
uuid: string;
name: string;
description?: string;
storageClassesDesired?: string[];
+ properties?: CollectionProperties;
}
export const COLLECTION_UPDATE_FORM_NAME = 'collectionUpdateFormName';
+export const COLLECTION_UPDATE_PROPERTIES_FORM_NAME = "collectionCreatePropertiesFormName";
+export const COLLECTION_UPDATE_FORM_SELECTOR = formValueSelector(COLLECTION_UPDATE_FORM_NAME);
export const openCollectionUpdateDialog = (resource: CollectionUpdateFormDialogData) =>
(dispatch: Dispatch) => {
services.collectionService.update(uuid, {
name: collection.name,
storageClassesDesired: collection.storageClassesDesired,
- description: collection.description }
+ description: collection.description,
+ properties: collection.properties }
).then(updatedCollection => {
updatedCollection = {...cachedCollection, ...updatedCollection};
dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: updatedCollection as CollectionResource }));
}
);
};
+
+export const addPropertyToUpdateCollectionForm = (data: ResourcePropertiesFormData) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const properties = { ...COLLECTION_UPDATE_FORM_SELECTOR(getState(), 'properties') };
+ const key = data.keyID || data.key;
+ const value = data.valueID || data.value;
+ dispatch(change(
+ COLLECTION_UPDATE_FORM_NAME,
+ 'properties',
+ addProperty(properties, key, value)));
+ };
+
+export const removePropertyFromUpdateCollectionForm = (key: string, value: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const properties = { ...COLLECTION_UPDATE_FORM_SELECTOR(getState(), 'properties') };
+ dispatch(change(
+ COLLECTION_UPDATE_FORM_NAME,
+ 'properties',
+ deleteProperty(properties, key, value)));
+ };
outputUuid?: string;
workflowUuid?: string;
storageClassesDesired?: string[];
+ properties?: { [key: string]: string | string[] };
};
export const isKeyboardClick = (event: React.MouseEvent<HTMLElement>) => event.nativeEvent.detail === 0;
// SPDX-License-Identifier: AGPL-3.0
import { Dispatch } from "redux";
-import { FormErrors, initialize, reset, startSubmit, stopSubmit } from 'redux-form';
+import {
+ change,
+ FormErrors,
+ formValueSelector,
+ initialize,
+ reset,
+ startSubmit,
+ stopSubmit
+} from 'redux-form';
import { RootState } from "store/store";
import { dialogActions } from "store/dialog/dialog-actions";
-import { getCommonResourceServiceError, CommonResourceServiceError } from "services/common-service/common-resource-service";
+import {
+ getCommonResourceServiceError,
+ CommonResourceServiceError
+} from "services/common-service/common-resource-service";
import { ServiceRepository } from "services/services";
import { projectPanelActions } from 'store/project-panel/project-panel-action';
import { GroupClass } from "models/group";
import { Participant } from "views-components/sharing-dialog/participant-select";
+import { ResourcePropertiesFormData } from "views-components/resource-properties-form/resource-properties-form";
+import { addProperty, deleteProperty } from "lib/resource-properties";
+import { ProjectProperties } from "./project-create-actions";
export interface ProjectUpdateFormDialogData {
uuid: string;
name: string;
users?: Participant[];
description?: string;
+ properties?: ProjectProperties;
}
export const PROJECT_UPDATE_FORM_NAME = 'projectUpdateFormName';
+export const PROJECT_UPDATE_PROPERTIES_FORM_NAME = 'projectUpdatePropertiesFormName';
+export const PROJECT_UPDATE_FORM_SELECTOR = formValueSelector(PROJECT_UPDATE_FORM_NAME);
export const openProjectUpdateDialog = (resource: ProjectUpdateFormDialogData) =>
(dispatch: Dispatch, getState: () => RootState) => {
const uuid = project.uuid || '';
dispatch(startSubmit(PROJECT_UPDATE_FORM_NAME));
try {
- const updatedProject = await services.projectService.update(uuid, { name: project.name, description: project.description });
+ const updatedProject = await services.projectService.update(
+ uuid,
+ {
+ name: project.name,
+ description: project.description,
+ properties: project.properties,
+ });
dispatch(projectPanelActions.REQUEST_ITEMS());
dispatch(reset(PROJECT_UPDATE_FORM_NAME));
dispatch(dialogActions.CLOSE_DIALOG({ id: PROJECT_UPDATE_FORM_NAME }));
return ;
}
};
+
+export const addPropertyToUpdateProjectForm = (data: ResourcePropertiesFormData) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const properties = { ...PROJECT_UPDATE_FORM_SELECTOR(getState(), 'properties') };
+ const key = data.keyID || data.key;
+ const value = data.valueID || data.value;
+ dispatch(change(
+ PROJECT_UPDATE_FORM_NAME,
+ 'properties',
+ addProperty(properties, key, value)));
+ };
+
+export const removePropertyFromUpdateProjectForm = (key: string, value: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const properties = { ...PROJECT_UPDATE_FORM_SELECTOR(getState(), 'properties') };
+ dispatch(change(
+ PROJECT_UPDATE_FORM_NAME,
+ 'properties',
+ deleteProperty(properties, key, value)));
+ };
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { reduxForm, reset } from 'redux-form';
+import { withStyles } from '@material-ui/core';
+import {
+ COLLECTION_CREATE_PROPERTIES_FORM_NAME,
+ addPropertyToCreateCollectionForm
+} from 'store/collections/collection-create-actions';
+import {
+ ResourcePropertiesForm,
+ ResourcePropertiesFormData
+} from 'views-components/resource-properties-form/resource-properties-form';
+
+const Form = withStyles(
+ ({ spacing }) => (
+ { container:
+ {
+ paddingTop: spacing.unit,
+ margin: 0,
+ }
+ })
+ )(ResourcePropertiesForm);
+
+export const CreateCollectionPropertiesForm = reduxForm<ResourcePropertiesFormData>({
+ form: COLLECTION_CREATE_PROPERTIES_FORM_NAME,
+ onSubmit: (data, dispatch) => {
+ dispatch(addPropertyToCreateCollectionForm(data));
+ dispatch(reset(COLLECTION_CREATE_PROPERTIES_FORM_NAME));
+ }
+})(Form);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import {
+ withStyles,
+ StyleRulesCallback,
+ WithStyles,
+} from '@material-ui/core';
+import { RootState } from 'store/store';
+import {
+ removePropertyFromCreateCollectionForm,
+ COLLECTION_CREATE_FORM_SELECTOR,
+ CollectionProperties
+} from 'store/collections/collection-create-actions';
+import { ArvadosTheme } from 'common/custom-theme';
+import { getPropertyChip } from '../resource-properties-form/property-chip';
+
+type CssRules = 'tag';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ tag: {
+ marginRight: theme.spacing.unit,
+ marginBottom: theme.spacing.unit
+ }
+});
+
+interface CreateCollectionPropertiesListDataProps {
+ properties: CollectionProperties;
+}
+
+interface CreateCollectionPropertiesListActionProps {
+ handleDelete: (key: string, value: string) => void;
+}
+
+const mapStateToProps = (state: RootState): CreateCollectionPropertiesListDataProps => {
+ const properties = COLLECTION_CREATE_FORM_SELECTOR(state, 'properties');
+ return { properties };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch): CreateCollectionPropertiesListActionProps => ({
+ handleDelete: (key: string, value: string) => dispatch<any>(removePropertyFromCreateCollectionForm(key, value))
+});
+
+type CreateCollectionPropertiesListProps = CreateCollectionPropertiesListDataProps &
+ CreateCollectionPropertiesListActionProps & WithStyles<CssRules>;
+
+const List = withStyles(styles)(
+ ({ classes, handleDelete, properties }: CreateCollectionPropertiesListProps) =>
+ <div>
+ {properties &&
+ Object.keys(properties).map(k =>
+ Array.isArray(properties[k])
+ ? (properties[k] as string[]).map((v: string) =>
+ getPropertyChip(
+ k, v,
+ () => handleDelete(k, v),
+ classes.tag))
+ : getPropertyChip(
+ k, (properties[k] as string),
+ () => handleDelete(k, (properties[k] as string)),
+ classes.tag))
+ }
+ </div>
+);
+
+export const CreateCollectionPropertiesList = connect(mapStateToProps, mapDispatchToProps)(List);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { reduxForm, reset } from 'redux-form';
+import { withStyles } from '@material-ui/core';
+import {
+ addPropertyToUpdateCollectionForm,
+ COLLECTION_UPDATE_PROPERTIES_FORM_NAME
+} from 'store/collections/collection-update-actions';
+import {
+ ResourcePropertiesForm,
+ ResourcePropertiesFormData
+} from 'views-components/resource-properties-form/resource-properties-form';
+
+const Form = withStyles(
+ ({ spacing }) => (
+ { container:
+ {
+ paddingTop: spacing.unit,
+ margin: 0,
+ }
+ })
+ )(ResourcePropertiesForm);
+
+export const UpdateCollectionPropertiesForm = reduxForm<ResourcePropertiesFormData>({
+ form: COLLECTION_UPDATE_PROPERTIES_FORM_NAME,
+ onSubmit: (data, dispatch) => {
+ dispatch(addPropertyToUpdateCollectionForm(data));
+ dispatch(reset(COLLECTION_UPDATE_PROPERTIES_FORM_NAME));
+ }
+})(Form);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import {
+ withStyles,
+ StyleRulesCallback,
+ WithStyles,
+} from '@material-ui/core';
+import { RootState } from 'store/store';
+import {
+ removePropertyFromUpdateCollectionForm,
+ COLLECTION_UPDATE_FORM_SELECTOR,
+} from 'store/collections/collection-update-actions';
+import { ArvadosTheme } from 'common/custom-theme';
+import { getPropertyChip } from '../resource-properties-form/property-chip';
+import { CollectionProperties } from 'store/collections/collection-create-actions';
+
+type CssRules = 'tag';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ tag: {
+ marginRight: theme.spacing.unit,
+ marginBottom: theme.spacing.unit
+ }
+});
+
+interface UpdateCollectionPropertiesListDataProps {
+ properties: CollectionProperties;
+}
+
+interface UpdateCollectionPropertiesListActionProps {
+ handleDelete: (key: string, value: string) => void;
+}
+
+const mapStateToProps = (state: RootState): UpdateCollectionPropertiesListDataProps => {
+ const properties = COLLECTION_UPDATE_FORM_SELECTOR(state, 'properties');
+ return { properties };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch): UpdateCollectionPropertiesListActionProps => ({
+ handleDelete: (key: string, value: string) => dispatch<any>(removePropertyFromUpdateCollectionForm(key, value))
+});
+
+type UpdateCollectionPropertiesListProps = UpdateCollectionPropertiesListDataProps &
+ UpdateCollectionPropertiesListActionProps & WithStyles<CssRules>;
+
+const List = withStyles(styles)(
+ ({ classes, handleDelete, properties }: UpdateCollectionPropertiesListProps) =>
+ <div>
+ {properties &&
+ Object.keys(properties).map(k =>
+ Array.isArray(properties[k])
+ ? (properties[k] as string[]).map((v: string) =>
+ getPropertyChip(
+ k, v,
+ () => handleDelete(k, v),
+ classes.tag))
+ : getPropertyChip(
+ k, (properties[k] as string),
+ () => handleDelete(k, (properties[k] as string)),
+ classes.tag))
+ }
+ </div>
+);
+
+export const UpdateCollectionPropertiesList = connect(mapStateToProps, mapDispatchToProps)(List);
\ No newline at end of file
} from 'views-components/form-fields/collection-form-fields';
import { FileUploaderField } from '../file-uploader/file-uploader';
import { ResourceParentField } from '../form-fields/resource-form-fields';
+import { CreateCollectionPropertiesList } from 'views-components/collection-properties/create-collection-properties-list';
+import { CreateCollectionPropertiesForm } from 'views-components/collection-properties/create-collection-properties-form';
+import { FormGroup, FormLabel } from '@material-ui/core';
type DialogCollectionProps = WithDialogProps<{}> & InjectedFormProps<CollectionCreateFormDialogData>;
<ResourceParentField />
<CollectionNameField />
<CollectionDescriptionField />
+ <FormLabel>Properties</FormLabel>
+ <FormGroup>
+ <CreateCollectionPropertiesForm />
+ <CreateCollectionPropertiesList />
+ </FormGroup>
<CollectionStorageClassesField defaultClasses={['default']} />
<Field
name='files'
import { CreateProjectPropertiesForm } from 'views-components/project-properties/create-project-properties-form';
import { CreateProjectPropertiesList } from 'views-components/project-properties/create-project-properties-list';
import { ResourceParentField } from '../form-fields/resource-form-fields';
+import { FormGroup, FormLabel } from '@material-ui/core';
type DialogProjectProps = WithDialogProps<{}> & InjectedFormProps<ProjectCreateFormDialogData>;
<ResourceParentField />
<ProjectNameField />
<ProjectDescriptionField />
- <CreateProjectPropertiesForm />
- <CreateProjectPropertiesList />
+ <FormLabel>Properties</FormLabel>
+ <FormGroup>
+ <CreateProjectPropertiesForm />
+ <CreateProjectPropertiesList />
+ </FormGroup>
</span>;
onSubmit: (data, dispatch) => {
// Somehow an extra field called 'files' gets added, copy
// the data object to get rid of it.
- dispatch(createCollection({ ownerUuid: data.ownerUuid, name: data.name, description: data.description, storageClassesDesired: data.storageClassesDesired }));
+ dispatch(createCollection({
+ ownerUuid: data.ownerUuid,
+ name: data.name,
+ description: data.description,
+ storageClassesDesired: data.storageClassesDesired,
+ properties: data.properties,
+ }));
}
})
)(DialogCollectionCreate);
CollectionDescriptionField,
CollectionStorageClassesField
} from 'views-components/form-fields/collection-form-fields';
+import { UpdateCollectionPropertiesForm } from 'views-components/collection-properties/update-collection-properties-form';
+import { UpdateCollectionPropertiesList } from 'views-components/collection-properties/update-collection-properties-list';
+import { FormGroup, FormLabel } from '@material-ui/core';
type DialogCollectionProps = WithDialogProps<{}> & InjectedFormProps<CollectionUpdateFormDialogData>;
const CollectionEditFields = () => <span>
<CollectionNameField />
<CollectionDescriptionField />
+ <FormLabel>Properties</FormLabel>
+ <FormGroup>
+ <UpdateCollectionPropertiesForm />
+ <UpdateCollectionPropertiesList />
+ </FormGroup>
<CollectionStorageClassesField />
</span>;
import { FormDialog } from 'components/form-dialog/form-dialog';
import { ProjectNameField, ProjectDescriptionField, UsersField } from 'views-components/form-fields/project-form-fields';
import { GroupClass } from 'models/group';
+import { FormGroup, FormLabel } from '@material-ui/core';
+import { UpdateProjectPropertiesForm } from 'views-components/project-properties/update-project-properties-form';
+import { UpdateProjectPropertiesList } from 'views-components/project-properties/update-project-properties-list';
type DialogProjectProps = WithDialogProps<{sourcePanel: GroupClass, create?: boolean}> & InjectedFormProps<ProjectUpdateFormDialogData>;
const ProjectEditFields = () => <span>
<ProjectNameField />
<ProjectDescriptionField />
+ <FormLabel>Properties</FormLabel>
+ <FormGroup>
+ <UpdateProjectPropertiesForm />
+ <UpdateProjectPropertiesList />
+ </FormGroup>
</span>;
const GroupAddFields = () => <span>
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { reduxForm, reset } from 'redux-form';
+import { withStyles } from '@material-ui/core';
+import {
+ PROJECT_UPDATE_PROPERTIES_FORM_NAME,
+ addPropertyToUpdateProjectForm
+} from 'store/projects/project-update-actions';
+import {
+ ResourcePropertiesForm,
+ ResourcePropertiesFormData
+} from 'views-components/resource-properties-form/resource-properties-form';
+
+const Form = withStyles(
+ ({ spacing }) => (
+ { container:
+ {
+ paddingTop: spacing.unit,
+ margin: 0,
+ }
+ })
+ )(ResourcePropertiesForm);
+
+export const UpdateProjectPropertiesForm = reduxForm<ResourcePropertiesFormData>({
+ form: PROJECT_UPDATE_PROPERTIES_FORM_NAME,
+ onSubmit: (data, dispatch) => {
+ dispatch(addPropertyToUpdateProjectForm(data));
+ dispatch(reset(PROJECT_UPDATE_PROPERTIES_FORM_NAME));
+ }
+})(Form);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import {
+ withStyles,
+ StyleRulesCallback,
+ WithStyles,
+} from '@material-ui/core';
+import { RootState } from 'store/store';
+import {
+ removePropertyFromUpdateProjectForm,
+ PROJECT_UPDATE_FORM_SELECTOR,
+} from 'store/projects/project-update-actions';
+import { ArvadosTheme } from 'common/custom-theme';
+import { getPropertyChip } from '../resource-properties-form/property-chip';
+import { ProjectProperties } from 'store/projects/project-create-actions';
+
+type CssRules = 'tag';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ tag: {
+ marginRight: theme.spacing.unit,
+ marginBottom: theme.spacing.unit
+ }
+});
+
+interface UpdateProjectPropertiesListDataProps {
+ properties: ProjectProperties;
+}
+
+interface UpdateProjectPropertiesListActionProps {
+ handleDelete: (key: string, value: string) => void;
+}
+
+const mapStateToProps = (state: RootState): UpdateProjectPropertiesListDataProps => {
+ const properties = PROJECT_UPDATE_FORM_SELECTOR(state, 'properties');
+ return { properties };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch): UpdateProjectPropertiesListActionProps => ({
+ handleDelete: (key: string, value: string) => dispatch<any>(removePropertyFromUpdateProjectForm(key, value))
+});
+
+type UpdateProjectPropertiesListProps = UpdateProjectPropertiesListDataProps &
+ UpdateProjectPropertiesListActionProps & WithStyles<CssRules>;
+
+const List = withStyles(styles)(
+ ({ classes, handleDelete, properties }: UpdateProjectPropertiesListProps) =>
+ <div>
+ {properties &&
+ Object.keys(properties).map(k =>
+ Array.isArray(properties[k])
+ ? (properties[k] as string[]).map((v: string) =>
+ getPropertyChip(
+ k, v,
+ () => handleDelete(k, v),
+ classes.tag))
+ : getPropertyChip(
+ k, (properties[k] as string),
+ () => handleDelete(k, (properties[k] as string)),
+ classes.tag))
+ }
+ </div>
+);
+
+export const UpdateProjectPropertiesList = connect(mapStateToProps, mapDispatchToProps)(List);
\ No newline at end of file
}
handleContextMenu = (event: React.MouseEvent<any>) => {
- const { uuid, ownerUuid, name, description, kind, storageClassesDesired } = this.props.item;
+ const { uuid, ownerUuid, name, description,
+ kind, storageClassesDesired, properties } = this.props.item;
const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(uuid));
const resource = {
uuid,
storageClassesDesired,
kind,
menuKind,
+ properties,
};
// Avoid expanding/collapsing the panel
event.stopPropagation();
menuKind,
description: resource.description,
storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
+ properties: ('properties' in resource) ? resource.properties : {},
}));
}
this.props.dispatch<any>(loadDetailsPanel(resourceUuid));