From: Stephen Smith Date: Mon, 17 Apr 2023 19:39:53 +0000 (-0400) Subject: 20031: Add includeDirectories flag to ProjectsTreePicker and add collection/directory... X-Git-Tag: 2.7.0~20^2~28 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/bc0041ffcbc42f92edc6bde05c8ba3ce392873fc?ds=sidebyside 20031: Add includeDirectories flag to ProjectsTreePicker and add collection/directory only picker Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- diff --git a/src/models/collection-file.ts b/src/models/collection-file.ts index 91008d1f..3688557a 100644 --- a/src/models/collection-file.ts +++ b/src/models/collection-file.ts @@ -71,10 +71,10 @@ export const createCollectionFilesTree = (data: Array item.path - ? join('', [getCollectionId(item.id), item.path]) + ? join('', [getCollectionResourceCollectionUuid(item.id), item.path]) : item.path; -const getCollectionId = pipe( +export const getCollectionResourceCollectionUuid = pipe( split('/'), head, -); \ No newline at end of file +); diff --git a/src/store/collections/collection-partial-copy-actions.ts b/src/store/collections/collection-partial-copy-actions.ts index 359b6b83..2a3fd5de 100644 --- a/src/store/collections/collection-partial-copy-actions.ts +++ b/src/store/collections/collection-partial-copy-actions.ts @@ -25,7 +25,7 @@ export interface CollectionPartialCopyToNewCollectionFormData { } export interface CollectionPartialCopyToExistingCollectionFormData { - collectionUuid: string; + destination: {uuid: string, path?: string}; } export const openCollectionPartialCopyToNewCollectionDialog = () => @@ -102,7 +102,7 @@ export const openCollectionPartialCopyToExistingCollectionDialog = () => const currentCollection = getState().collectionPanel.item; if (currentCollection) { const initialData = { - collectionUuid: '' + destination: {uuid: '', destinationPath: ''} }; dispatch(initialize(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION, initialData)); dispatch(resetPickerProjectTree()); @@ -111,13 +111,13 @@ export const openCollectionPartialCopyToExistingCollectionDialog = () => } }; -export const copyCollectionPartialToExistingCollection = ({ collectionUuid }: CollectionPartialCopyToExistingCollectionFormData) => +export const copyCollectionPartialToExistingCollection = ({ destination }: CollectionPartialCopyToExistingCollectionFormData) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const state = getState(); // Get current collection const sourceCollection = state.collectionPanel.item; - if (sourceCollection) { + if (sourceCollection && destination.uuid) { try { dispatch(startSubmit(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION)); dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION)); @@ -126,7 +126,7 @@ export const copyCollectionPartialToExistingCollection = ({ collectionUuid }: Co .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), '')); // Copy files - const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, {uuid: collectionUuid}, '/', false); + const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, {uuid: destination.uuid}, destination.path || '/', false); dispatch(updateResources([updatedCollection])); dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION })); diff --git a/src/store/collections/collection-partial-move-actions.ts b/src/store/collections/collection-partial-move-actions.ts index de64d99a..6d3c45f3 100644 --- a/src/store/collections/collection-partial-move-actions.ts +++ b/src/store/collections/collection-partial-move-actions.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0 import { Dispatch } from "redux"; -import { initialize, startSubmit } from "redux-form"; +import { FormErrors, initialize, startSubmit, stopSubmit } from "redux-form"; import { CommonResourceServiceError, getCommonResourceServiceError } from "services/common-service/common-resource-service"; import { ServiceRepository } from "services/services"; import { filterCollectionFilesBySelection } from "store/collection-panel/collection-panel-files/collection-panel-files-state"; @@ -15,8 +15,8 @@ import { SnackbarKind, snackbarActions } from "store/snackbar/snackbar-actions"; import { RootState } from "store/store"; import { initProjectsTreePicker } from "store/tree-picker/tree-picker-actions"; -export const COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION = 'COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION_DIALOG'; -export const COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION = 'COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION_DIALOG'; +export const COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION = 'COLLECTION_PARTIAL_MOVE_TO_NEW_DIALOG'; +export const COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION = 'COLLECTION_PARTIAL_MOVE_TO_SELECTED_DIALOG'; export interface CollectionPartialMoveToNewCollectionFormData { name: string; @@ -25,7 +25,7 @@ export interface CollectionPartialMoveToNewCollectionFormData { } export interface CollectionPartialMoveToExistingCollectionFormData { - collectionUuid: string; + destination: {uuid: string, path?: string}; } export const openCollectionPartialMoveToNewCollectionDialog = () => @@ -98,7 +98,7 @@ export const openCollectionPartialMoveToExistingCollectionDialog = () => const currentCollection = getState().collectionPanel.item; if (currentCollection) { const initialData = { - collectionUuid: '' + destination: {uuid: '', path: ''} }; dispatch(initialize(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION, initialData)); dispatch(resetPickerProjectTree()); @@ -107,13 +107,13 @@ export const openCollectionPartialMoveToExistingCollectionDialog = () => } }; -export const moveCollectionPartialToExistingCollection = ({ collectionUuid }: CollectionPartialMoveToExistingCollectionFormData) => +export const moveCollectionPartialToExistingCollection = ({ destination }: CollectionPartialMoveToExistingCollectionFormData) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const state = getState(); // Get current collection const sourceCollection = state.collectionPanel.item; - if (sourceCollection) { + if (sourceCollection && destination.uuid) { try { dispatch(startSubmit(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION)); dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION)); @@ -122,7 +122,7 @@ export const moveCollectionPartialToExistingCollection = ({ collectionUuid }: Co .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), '')); // Move files - const updatedCollection = await services.collectionService.moveFiles(sourceCollection.uuid, sourceCollection.portableDataHash, paths, {uuid: collectionUuid}, '/', false); + const updatedCollection = await services.collectionService.moveFiles(sourceCollection.uuid, sourceCollection.portableDataHash, paths, {uuid: destination.uuid}, destination.path || '/', false); dispatch(updateResources([updatedCollection])); dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION })); diff --git a/src/store/tree-picker/tree-picker-actions.ts b/src/store/tree-picker/tree-picker-actions.ts index 460a23e3..b8003aa1 100644 --- a/src/store/tree-picker/tree-picker-actions.ts +++ b/src/store/tree-picker/tree-picker-actions.ts @@ -4,7 +4,7 @@ import { unionize, ofType, UnionOf } from "common/unionize"; import { TreeNode, initTreeNode, getNodeDescendants, TreeNodeStatus, getNode, TreePickerId, Tree } from 'models/tree'; -import { createCollectionFilesTree } from "models/collection-file"; +import { CollectionFileType, createCollectionFilesTree } from "models/collection-file"; import { Dispatch } from 'redux'; import { RootState } from 'store/store'; import { getUserUuid } from "common/getuser"; @@ -42,6 +42,7 @@ export type TreePickerAction = UnionOf; export interface LoadProjectParams { includeCollections?: boolean; + includeDirectories?: boolean; includeFiles?: boolean; includeFilterGroups?: boolean; options?: { showOnlyOwned: boolean; showOnlyWritable: boolean; }; @@ -123,7 +124,17 @@ interface LoadProjectParamsWithId extends LoadProjectParams { export const loadProject = (params: LoadProjectParamsWithId) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - const { id, pickerId, includeCollections = false, includeFiles = false, includeFilterGroups = false, loadShared = false, options, searchProjects = false } = params; + const { + id, + pickerId, + includeCollections = false, + includeDirectories = false, + includeFiles = false, + includeFilterGroups = false, + loadShared = false, + options, + searchProjects = false + } = params; dispatch(treePickerActions.LOAD_TREE_PICKER_NODE({ id, pickerId })); @@ -194,14 +205,14 @@ export const loadProject = (params: LoadProjectParamsWithId) => value: item, status: item.kind === ResourceKind.PROJECT ? TreeNodeStatus.INITIAL - : includeFiles + : includeDirectories || includeFiles ? TreeNodeStatus.INITIAL : TreeNodeStatus.LOADED }), })); }; -export const loadCollection = (id: string, pickerId: string) => +export const loadCollection = (id: string, pickerId: string, includeDirectories?: boolean, includeFiles?: boolean) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { dispatch(treePickerActions.LOAD_TREE_PICKER_NODE({ id, pickerId })); @@ -210,7 +221,11 @@ export const loadCollection = (id: string, pickerId: string) => const node = getNode(id)(picker); if (node && 'kind' in node.value && node.value.kind === ResourceKind.COLLECTION) { - const files = await services.collectionService.files(node.value.uuid); + const files = (await services.collectionService.files(node.value.uuid)) + .filter((file) => ( + (includeFiles) || + (includeDirectories && file.type === CollectionFileType.DIRECTORY) + )); const tree = createCollectionFilesTree(files); const sorted = sortFilesTree(tree); const filesTree = mapTreeValues(services.collectionService.extendFileURL)(sorted); @@ -244,11 +259,11 @@ export const initUserProject = (pickerId: string) => })); } }; -export const loadUserProject = (pickerId: string, includeCollections = false, includeFiles = false, options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }) => +export const loadUserProject = (pickerId: string, includeCollections = false, includeDirectories = false, includeFiles = false, options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const uuid = getUserUuid(getState()); if (uuid) { - dispatch(loadProject({ id: uuid, pickerId, includeCollections, includeFiles, options })); + dispatch(loadProject({ id: uuid, pickerId, includeCollections, includeDirectories, includeFiles, options })); } }; @@ -316,6 +331,7 @@ export const initSearchProject = (pickerId: string) => interface LoadFavoritesProjectParams { pickerId: string; includeCollections?: boolean; + includeDirectories?: boolean; includeFiles?: boolean; options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }; } @@ -323,7 +339,7 @@ interface LoadFavoritesProjectParams { export const loadFavoritesProject = (params: LoadFavoritesProjectParams, options: { showOnlyOwned: boolean, showOnlyWritable: boolean } = { showOnlyOwned: true, showOnlyWritable: false }) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - const { pickerId, includeCollections = false, includeFiles = false } = params; + const { pickerId, includeCollections = false, includeDirectories = false, includeFiles = false } = params; const uuid = getUserUuid(getState()); if (uuid) { const filters = pipe( @@ -354,7 +370,7 @@ export const loadFavoritesProject = (params: LoadFavoritesProjectParams, value: item, status: item.kind === ResourceKind.PROJECT ? TreeNodeStatus.INITIAL - : includeFiles + : includeDirectories || includeFiles ? TreeNodeStatus.INITIAL : TreeNodeStatus.LOADED }), @@ -364,7 +380,7 @@ export const loadFavoritesProject = (params: LoadFavoritesProjectParams, export const loadPublicFavoritesProject = (params: LoadFavoritesProjectParams) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - const { pickerId, includeCollections = false, includeFiles = false } = params; + const { pickerId, includeCollections = false, includeDirectories = false, includeFiles = false } = params; const uuidPrefix = getState().auth.config.uuidPrefix; const publicProjectUuid = `${uuidPrefix}-j7d0g-publicfavorites`; @@ -395,7 +411,7 @@ export const loadPublicFavoritesProject = (params: LoadFavoritesProjectParams) = value: item, status: item.headKind === ResourceKind.PROJECT ? TreeNodeStatus.INITIAL - : includeFiles + : includeDirectories || includeFiles ? TreeNodeStatus.INITIAL : TreeNodeStatus.LOADED }), diff --git a/src/views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection.tsx b/src/views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection.tsx index 1af9dfee..f6d4db21 100644 --- a/src/views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection.tsx +++ b/src/views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection.tsx @@ -9,7 +9,7 @@ import { WithDialogProps } from 'store/dialog/with-dialog'; import { InjectedFormProps } from 'redux-form'; import { CollectionPartialCopyToExistingCollectionFormData } from 'store/collections/collection-partial-copy-actions'; import { PickerIdProp } from "store/tree-picker/picker-id"; -import { CollectionPickerField } from 'views-components/form-fields/collection-form-fields'; +import { DirectoryPickerField } from 'views-components/form-fields/collection-form-fields'; type DialogCollectionPartialCopyProps = WithDialogProps & InjectedFormProps; @@ -25,5 +25,5 @@ const CollectionPartialCopyFields = memoize( (pickerId: string) => () => <> - + ); diff --git a/src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx b/src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx index e8081037..f95bd24f 100644 --- a/src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx +++ b/src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx @@ -9,7 +9,7 @@ import { WithDialogProps } from 'store/dialog/with-dialog'; import { InjectedFormProps } from 'redux-form'; import { CollectionPartialMoveToExistingCollectionFormData } from "store/collections/collection-partial-move-actions"; import { PickerIdProp } from "store/tree-picker/picker-id"; -import { CollectionPickerField } from 'views-components/form-fields/collection-form-fields'; +import { DirectoryPickerField } from 'views-components/form-fields/collection-form-fields'; type DialogCollectionPartialMoveProps = WithDialogProps & InjectedFormProps; @@ -25,5 +25,5 @@ const CollectionPartialMoveFields = memoize( (pickerId: string) => () => <> - + ); diff --git a/src/views-components/form-fields/collection-form-fields.tsx b/src/views-components/form-fields/collection-form-fields.tsx index 7e18111a..0faa59b5 100644 --- a/src/views-components/form-fields/collection-form-fields.tsx +++ b/src/views-components/form-fields/collection-form-fields.tsx @@ -9,12 +9,13 @@ import { COLLECTION_NAME_VALIDATION, COLLECTION_NAME_VALIDATION_ALLOW_SLASH, COLLECTION_DESCRIPTION_VALIDATION, COLLECTION_PROJECT_VALIDATION } from "validators/validators"; -import { ProjectTreePickerField, CollectionTreePickerField } from "views-components/projects-tree-picker/tree-picker-field"; +import { ProjectTreePickerField, CollectionTreePickerField, DirectoryTreePickerField } from "views-components/projects-tree-picker/tree-picker-field"; 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"; +import { ERROR_MESSAGE } from "validators/require"; interface CollectionNameFieldProps { validate: Validator[]; @@ -58,6 +59,15 @@ export const CollectionPickerField = (props: PickerIdProp) => component={CollectionTreePickerField} validate={COLLECTION_PROJECT_VALIDATION} />; +const validateDirectory = (val) => (val ? undefined : ERROR_MESSAGE); + +export const DirectoryPickerField = (props: PickerIdProp) => + ; + interface StorageClassesProps { items: string[]; defaultClasses?: string[]; @@ -78,4 +88,4 @@ export const CollectionStorageClassesField = connect( defaultValues={props.defaultClasses} helperText='At least one class should be selected' component={MultiCheckboxField} - items={props.items} />); \ No newline at end of file + items={props.items} />); diff --git a/src/views-components/projects-tree-picker/favorites-tree-picker.tsx b/src/views-components/projects-tree-picker/favorites-tree-picker.tsx index 6ab2b42d..7e63152b 100644 --- a/src/views-components/projects-tree-picker/favorites-tree-picker.tsx +++ b/src/views-components/projects-tree-picker/favorites-tree-picker.tsx @@ -11,7 +11,7 @@ import { loadFavoritesProject } from 'store/tree-picker/tree-picker-actions'; export const FavoritesTreePicker = connect(() => ({ rootItemIcon: FavoriteIcon, }), (dispatch: Dispatch): Pick => ({ - loadRootItem: (_, pickerId, includeCollections, includeFiles, options) => { - dispatch(loadFavoritesProject({ pickerId, includeCollections, includeFiles }, options)); + loadRootItem: (_, pickerId, includeCollections, includeDirectories, includeFiles, options) => { + dispatch(loadFavoritesProject({ pickerId, includeCollections, includeDirectories, includeFiles }, options)); }, -}))(ProjectsTreePicker); \ No newline at end of file +}))(ProjectsTreePicker); diff --git a/src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx b/src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx index 11b51caa..1ed2a551 100644 --- a/src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx +++ b/src/views-components/projects-tree-picker/generic-projects-tree-picker.tsx @@ -22,6 +22,7 @@ type PickedTreePickerProps = Pick, 'onCo export interface ProjectsTreePickerDataProps { includeCollections?: boolean; + includeDirectories?: boolean; includeFiles?: boolean; rootItemIcon: IconType; showSelection?: boolean; @@ -29,7 +30,7 @@ export interface ProjectsTreePickerDataProps { disableActivation?: string[]; options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }; loadRootItem: (item: TreeItem, pickerId: string, - includeCollections?: boolean, includeFiles?: boolean, options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }) => void; + includeCollections?: boolean, includeDirectories?: boolean, includeFiles?: boolean, options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }) => void; } export type ProjectsTreePickerProps = ProjectsTreePickerDataProps & Partial; @@ -39,7 +40,7 @@ const mapStateToProps = (_: any, { rootItemIcon, showSelection }: ProjectsTreePi showSelection: isSelectionVisible(showSelection), }); -const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollections, includeFiles, relatedTreePickers, options, ...props }: ProjectsTreePickerProps): PickedTreePickerProps => ({ +const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollections, includeDirectories, includeFiles, relatedTreePickers, options, ...props }: ProjectsTreePickerProps): PickedTreePickerProps => ({ onContextMenu: () => { return; }, toggleItemActive: (event, item, pickerId) => { @@ -59,11 +60,11 @@ const mapDispatchToProps = (dispatch: Dispatch, { loadRootItem, includeCollectio if ('kind' in data) { dispatch( data.kind === ResourceKind.COLLECTION - ? loadCollection(id, pickerId) - : loadProject({ id, pickerId, includeCollections, includeFiles, options }) + ? loadCollection(id, pickerId, includeDirectories, includeFiles) + : loadProject({ id, pickerId, includeCollections, includeDirectories, includeFiles, options }) ); } else if (!('type' in data) && loadRootItem) { - loadRootItem(item as TreeItem, pickerId, includeCollections, includeFiles, options); + loadRootItem(item as TreeItem, pickerId, includeCollections, includeDirectories, includeFiles, options); } } else if (status === TreeItemStatus.LOADED) { dispatch(treePickerActions.TOGGLE_TREE_PICKER_NODE_COLLAPSE({ id, pickerId })); diff --git a/src/views-components/projects-tree-picker/home-tree-picker.tsx b/src/views-components/projects-tree-picker/home-tree-picker.tsx index 3133c5db..3f71a58e 100644 --- a/src/views-components/projects-tree-picker/home-tree-picker.tsx +++ b/src/views-components/projects-tree-picker/home-tree-picker.tsx @@ -11,7 +11,7 @@ import { ProjectsIcon } from 'components/icon/icon'; export const HomeTreePicker = connect(() => ({ rootItemIcon: ProjectsIcon, }), (dispatch: Dispatch): Pick => ({ - loadRootItem: (_, pickerId, includeCollections, includeFiles, options) => { - dispatch(loadUserProject(pickerId, includeCollections, includeFiles, options)); + loadRootItem: (_, pickerId, includeCollections, includeDirectories, includeFiles, options) => { + dispatch(loadUserProject(pickerId, includeCollections, includeDirectories, includeFiles, options)); }, }))(ProjectsTreePicker); diff --git a/src/views-components/projects-tree-picker/projects-tree-picker.tsx b/src/views-components/projects-tree-picker/projects-tree-picker.tsx index 9ac0b64f..1f036829 100644 --- a/src/views-components/projects-tree-picker/projects-tree-picker.tsx +++ b/src/views-components/projects-tree-picker/projects-tree-picker.tsx @@ -25,6 +25,7 @@ import { ArvadosTheme } from 'common/custom-theme'; export interface ToplevelPickerProps { pickerId: string; includeCollections?: boolean; + includeDirectories?: boolean; includeFiles?: boolean; showSelection?: boolean; options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }; @@ -55,6 +56,7 @@ const mapDispatchToProps = (dispatch: Dispatch, props: ToplevelPickerProps): (Pr const { home, shared, favorites, publicFavorites, search } = getProjectsTreePickerIds(props.pickerId); const params = { includeCollections: props.includeCollections, + includeDirectories: props.includeDirectories, includeFiles: props.includeFiles, options: props.options }; @@ -133,6 +135,7 @@ export const ProjectsTreePicker = connect(mapStateToProps, mapDispatchToProps)( const relatedTreePickers = getRelatedTreePickers(pickerId); const p = { includeCollections: this.props.includeCollections, + includeDirectories: this.props.includeDirectories, includeFiles: this.props.includeFiles, showSelection: this.props.showSelection, options: this.props.options, diff --git a/src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx b/src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx index 91551c9a..ca03f728 100644 --- a/src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx +++ b/src/views-components/projects-tree-picker/public-favorites-tree-picker.tsx @@ -11,7 +11,7 @@ import { loadPublicFavoritesProject } from 'store/tree-picker/tree-picker-action export const PublicFavoritesTreePicker = connect(() => ({ rootItemIcon: PublicFavoriteIcon, }), (dispatch: Dispatch): Pick => ({ - loadRootItem: (_, pickerId, includeCollections, includeFiles, options) => { - dispatch(loadPublicFavoritesProject({ pickerId, includeCollections, includeFiles, options })); + loadRootItem: (_, pickerId, includeCollections, includeDirectories, includeFiles, options) => { + dispatch(loadPublicFavoritesProject({ pickerId, includeCollections, includeDirectories, includeFiles, options })); }, -}))(ProjectsTreePicker); \ No newline at end of file +}))(ProjectsTreePicker); diff --git a/src/views-components/projects-tree-picker/search-projects-picker.tsx b/src/views-components/projects-tree-picker/search-projects-picker.tsx index 7bad8ef7..2888050b 100644 --- a/src/views-components/projects-tree-picker/search-projects-picker.tsx +++ b/src/views-components/projects-tree-picker/search-projects-picker.tsx @@ -12,7 +12,7 @@ import { SEARCH_PROJECT_ID } from 'store/tree-picker/tree-picker-actions'; export const SearchProjectsPicker = connect(() => ({ rootItemIcon: SearchIcon, }), (dispatch: Dispatch): Pick => ({ - loadRootItem: (_, pickerId, includeCollections, includeFiles, options) => { - dispatch(loadProject({ id: SEARCH_PROJECT_ID, pickerId, includeCollections, includeFiles, searchProjects: true, options })); + loadRootItem: (_, pickerId, includeCollections, includeDirectories, includeFiles, options) => { + dispatch(loadProject({ id: SEARCH_PROJECT_ID, pickerId, includeCollections, includeDirectories, includeFiles, searchProjects: true, options })); }, }))(ProjectsTreePicker); diff --git a/src/views-components/projects-tree-picker/shared-tree-picker.tsx b/src/views-components/projects-tree-picker/shared-tree-picker.tsx index c15df6ba..1914cd9d 100644 --- a/src/views-components/projects-tree-picker/shared-tree-picker.tsx +++ b/src/views-components/projects-tree-picker/shared-tree-picker.tsx @@ -12,7 +12,7 @@ import { SHARED_PROJECT_ID } from 'store/tree-picker/tree-picker-actions'; export const SharedTreePicker = connect(() => ({ rootItemIcon: ShareMeIcon, }), (dispatch: Dispatch): Pick => ({ - loadRootItem: (_, pickerId, includeCollections, includeFiles, options) => { - dispatch(loadProject({ id: SHARED_PROJECT_ID, pickerId, includeCollections, includeFiles, loadShared: true, options })); + loadRootItem: (_, pickerId, includeCollections, includeDirectories, includeFiles, options) => { + dispatch(loadProject({ id: SHARED_PROJECT_ID, pickerId, includeCollections, includeDirectories, includeFiles, loadShared: true, options })); }, }))(ProjectsTreePicker); diff --git a/src/views-components/projects-tree-picker/tree-picker-field.tsx b/src/views-components/projects-tree-picker/tree-picker-field.tsx index 2afa606e..1414d18f 100644 --- a/src/views-components/projects-tree-picker/tree-picker-field.tsx +++ b/src/views-components/projects-tree-picker/tree-picker-field.tsx @@ -9,6 +9,8 @@ import { WrappedFieldProps } from 'redux-form'; import { ProjectsTreePicker } from 'views-components/projects-tree-picker/projects-tree-picker'; import { ProjectsTreePickerItem } from 'store/tree-picker/tree-picker-middleware'; import { PickerIdProp } from 'store/tree-picker/picker-id'; +import { CollectionFileType, getCollectionResourceCollectionUuid } from "models/collection-file"; +import { ResourceKind } from "models/resource"; export const ProjectTreePickerField = (props: WrappedFieldProps & PickerIdProp) =>
@@ -42,3 +44,36 @@ export const CollectionTreePickerField = (props: WrappedFieldProps & PickerIdPro }
; + +const handleDirectoryChange = (props: WrappedFieldProps) => + (_: any, data: TreeItem) => { + if ('kind' in data.data && data.data.kind === ResourceKind.COLLECTION) { + props.input.onChange({ + uuid: data.data.uuid, + path: '/' + }); + } else if ('type' in data.data && data.data.type === CollectionFileType.DIRECTORY) { + props.input.onChange({ + uuid: getCollectionResourceCollectionUuid(data.data.id), + path: [data.data.path, data.data.name].join('/') + }); + } else { + props.input.onChange(''); + } + } + +export const DirectoryTreePickerField = (props: WrappedFieldProps & PickerIdProp) => +
+
+ + {props.meta.dirty && props.meta.error && + + {props.meta.error} + } +
+
; diff --git a/src/views/run-process-panel/inputs/file-array-input.tsx b/src/views/run-process-panel/inputs/file-array-input.tsx index a2f884e3..1e1a4299 100644 --- a/src/views/run-process-panel/inputs/file-array-input.tsx +++ b/src/views/run-process-panel/inputs/file-array-input.tsx @@ -254,6 +254,7 @@ const FileArrayInputComponent = connect(mapStateToProps)(