From: Stephen Smith Date: Tue, 7 Jun 2022 21:37:00 +0000 (-0400) Subject: Merge branch '18984-project-type-filters-2' into main. Closes #18984 X-Git-Tag: 2.5.0~53 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/9a59fad2b6a97af963728a5111395f9caa71802f?hp=24d11ff837843675b37f1a844152ca0e74a12dea Merge branch '18984-project-type-filters-2' into main. Closes #18984 Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- diff --git a/cypress/integration/collection.spec.js b/cypress/integration/collection.spec.js index b62a3441..0b06e53e 100644 --- a/cypress/integration/collection.spec.js +++ b/cypress/integration/collection.spec.js @@ -261,7 +261,7 @@ describe('Collection panel tests', function () { }); // Test context menus cy.get('[data-cy=collection-files-panel]') - .contains(fileName).rightclick({ force: true }); + .contains(fileName).rightclick(); cy.get('[data-cy=context-menu]') .should('contain', 'Download') .and('not.contain', 'Open in new tab') @@ -270,7 +270,7 @@ describe('Collection panel tests', function () { .and(`${isWritable ? '' : 'not.'}contain`, 'Remove'); cy.get('body').click(); // Collapse the menu cy.get('[data-cy=collection-files-panel]') - .contains(subDirName).rightclick({ force: true }); + .contains(subDirName).rightclick(); cy.get('[data-cy=context-menu]') .should('not.contain', 'Download') .and('not.contain', 'Open in new tab') @@ -368,7 +368,7 @@ describe('Collection panel tests', function () { ['subdir', 'G%C3%BCnter\'s%20file', 'table%&?*2'].forEach((subdir) => { cy.get('[data-cy=collection-files-panel]') - .contains('bar').rightclick({force: true}); + .contains('bar').rightclick(); cy.get('[data-cy=context-menu]') .contains('Rename') .click(); @@ -381,9 +381,9 @@ describe('Collection panel tests', function () { cy.get('[data-cy=collection-files-panel]') .should('not.contain', 'bar') .and('contain', subdir); - cy.wait(1000); cy.get('[data-cy=collection-files-panel]').contains(subdir).click(); - // Rename 'subdir/foo' to 'foo' + + // Rename 'subdir/foo' to 'bar' cy.wait(1000); cy.get('[data-cy=collection-files-panel]') .contains('foo').rightclick(); @@ -399,7 +399,6 @@ describe('Collection panel tests', function () { }); cy.get('[data-cy=form-submit-btn]').click(); - cy.wait(1000); cy.get('[data-cy=collection-files-panel]') .contains('Home') .click(); @@ -1034,6 +1033,14 @@ describe('Collection panel tests', function () { cy.goToPath(`/collections/${testCollection1.uuid}`); + // Confirm initial collection state. + cy.get('[data-cy=collection-files-panel]') + .contains('bar').should('exist'); + cy.get('[data-cy=collection-files-panel]') + .contains('5mb_a.bin').should('not.exist'); + cy.get('[data-cy=collection-files-panel]') + .contains('5mb_b.bin').should('not.exist'); + cy.get('[data-cy=upload-button]').click(); cy.fixture('files/5mb.bin', 'base64').then(content => { @@ -1043,9 +1050,25 @@ describe('Collection panel tests', function () { cy.get('[data-cy=form-submit-btn]').click(); cy.get('button[aria-label=Remove]').should('exist'); - cy.get('button[aria-label=Remove]').click({ multiple: true, force: true }); + cy.get('button[aria-label=Remove]') + .click({ multiple: true, force: true }); cy.get('[data-cy=form-submit-btn]').should('not.exist'); + + // Confirm final collection state. + cy.get('[data-cy=collection-files-panel]') + .contains('bar').should('exist'); + // The following fails, but doesn't seem to happen + // in the real world. Maybe there's a race between + // the PUT request finishing and the 'Remove' button + // dissapearing, because sometimes just one of the 2 + // files gets uploaded. + // Maybe this will be needed to simulate a slow network: + // https://docs.cypress.io/api/commands/intercept#Convenience-functions-1 + // cy.get('[data-cy=collection-files-panel]') + // .contains('5mb_a.bin').should('not.exist'); + // cy.get('[data-cy=collection-files-panel]') + // .contains('5mb_b.bin').should('not.exist'); }); }); }); diff --git a/cypress/integration/favorites.spec.js b/cypress/integration/favorites.spec.js index 105657ef..7fd09124 100644 --- a/cypress/integration/favorites.spec.js +++ b/cypress/integration/favorites.spec.js @@ -64,7 +64,7 @@ describe('Favorites tests', function () { cy.loginAs(activeUser); cy.goToPath(`/collections/${testSourceCollection.uuid}`); cy.get('[data-cy=collection-files-panel]').contains('bar'); - cy.get('[data-cy=collection-files-panel]').find('input[type=checkbox]').click({ force: true }); + cy.get('[data-cy=collection-files-panel]').find('input[type=checkbox]').click(); cy.get('[data-cy=collection-files-panel-options-btn]').click(); cy.get('[data-cy=context-menu]') .contains('Copy selected into the collection').click(); diff --git a/cypress/integration/search.spec.js b/cypress/integration/search.spec.js index 491292be..5434ca24 100644 --- a/cypress/integration/search.spec.js +++ b/cypress/integration/search.spec.js @@ -104,4 +104,26 @@ describe('Search tests', function() { cy.get('[data-cy=element-path]').should('contain', `/ Projects / ${colName}`); }); }); + + it('can display owner of the item', function() { + const colName = `Collection ${Math.floor(Math.random() * Math.floor(999999))}`; + + cy.createCollection(adminUser.token, { + name: colName, + owner_uuid: activeUser.user.uuid, + preserve_version: true, + manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n" + }).then(function() { + cy.loginAs(activeUser); + + cy.doSearch(colName); + + cy.get('[data-cy=search-results]').should('contain', colName); + + cy.get('[data-cy=search-results]').contains(colName).closest('tr') + .within(() => { + cy.get('p').contains(activeUser.user.uuid).should('contain', activeUser.user.full_name); + }); + }); + }); }); \ No newline at end of file diff --git a/src/components/collection-panel-files/collection-panel-files.tsx b/src/components/collection-panel-files/collection-panel-files.tsx index 05b49363..42408270 100644 --- a/src/components/collection-panel-files/collection-panel-files.tsx +++ b/src/components/collection-panel-files/collection-panel-files.tsx @@ -10,24 +10,38 @@ import AutoSizer from "react-virtualized-auto-sizer"; import servicesProvider from 'common/service-provider'; import { CustomizeTableIcon, DownloadIcon } from 'components/icon/icon'; import { SearchInput } from 'components/search-input/search-input'; -import { ListItemIcon, StyleRulesCallback, Theme, WithStyles, withStyles, Tooltip, IconButton, Checkbox, CircularProgress, Button } from '@material-ui/core'; +import { + ListItemIcon, + StyleRulesCallback, + Theme, + WithStyles, + withStyles, + Tooltip, + IconButton, + Checkbox, + CircularProgress, + Button, +} from '@material-ui/core'; import { FileTreeData } from '../file-tree/file-tree-data'; import { TreeItem, TreeItemStatus } from '../tree/tree'; import { RootState } from 'store/store'; import { WebDAV, WebDAVRequestConfig } from 'common/webdav'; import { AuthState } from 'store/auth/auth-reducer'; import { extractFilesData } from 'services/collection-service/collection-service-files-response'; -import { DefaultIcon, DirectoryIcon, FileIcon, BackIcon, SidePanelRightArrowIcon } from 'components/icon/icon'; +import { + DefaultIcon, + DirectoryIcon, + FileIcon, + BackIcon, + SidePanelRightArrowIcon +} from 'components/icon/icon'; import { setCollectionFiles } from 'store/collection-panel/collection-panel-files/collection-panel-files-actions'; import { sortBy } from 'lodash'; import { formatFileSize } from 'common/formatters'; import { getInlineFileUrl, sanitizeToken } from 'views-components/context-menu/actions/helpers'; export interface CollectionPanelFilesProps { - items: any; isWritable: boolean; - isLoading: boolean; - tooManyFiles: boolean; onUploadDataClick: (targetLocation?: string) => void; onSearchChange: (searchValue: string) => void; onItemMenuOpen: (event: React.MouseEvent, item: TreeItem, isWritable: boolean) => void; @@ -35,14 +49,35 @@ export interface CollectionPanelFilesProps { onSelectionToggle: (event: React.MouseEvent, item: TreeItem) => void; onCollapseToggle: (id: string, status: TreeItemStatus) => void; onFileClick: (id: string) => void; - loadFilesFunc: () => void; currentItemUuid: any; dispatch: Function; collectionPanelFiles: any; collectionPanel: any; } -type CssRules = "backButton" | "backButtonHidden" | "pathPanelPathWrapper" | "uploadButton" | "uploadIcon" | "loader" | "wrapper" | "dataWrapper" | "row" | "rowEmpty" | "leftPanel" | "rightPanel" | "pathPanel" | "pathPanelItem" | "rowName" | "listItemIcon" | "rowActive" | "pathPanelMenu" | "rowSelection" | "leftPanelHidden" | "leftPanelVisible" | "searchWrapper" | "searchWrapperHidden"; +type CssRules = "backButton" + | "backButtonHidden" + | "pathPanelPathWrapper" + | "uploadButton" + | "uploadIcon" + | "loader" + | "wrapper" + | "dataWrapper" + | "row" + | "rowEmpty" + | "leftPanel" + | "rightPanel" + | "pathPanel" + | "pathPanelItem" + | "rowName" + | "listItemIcon" + | "rowActive" + | "pathPanelMenu" + | "rowSelection" + | "leftPanelHidden" + | "leftPanelVisible" + | "searchWrapper" + | "searchWrapperHidden"; const styles: StyleRulesCallback = (theme: Theme) => ({ wrapper: { @@ -198,8 +233,8 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState }; const parentRef = React.useRef(null); - const [path, setPath]: any = React.useState([]); - const [pathData, setPathData]: any = React.useState({}); + const [path, setPath] = React.useState([]); + const [pathData, setPathData] = React.useState({}); const [isLoading, setIsLoading] = React.useState(false); const [leftSearch, setLeftSearch] = React.useState(''); const [rightSearch, setRightSearch] = React.useState(''); @@ -220,12 +255,12 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState const fetchData = (keys, ignoreCache = false) => { const keyArray = Array.isArray(keys) ? keys : [keys]; - Promise.all(keyArray + Promise.all(keyArray.filter(key => !!key) .map((key) => { const dataExists = !!pathData[key]; const runningRequest = pathPromise[key]; - if ((!dataExists || ignoreCache) && (!runningRequest || ignoreCache)) { + if (ignoreCache || (!dataExists && !runningRequest)) { if (!isLoading) { setIsLoading(true); } @@ -239,34 +274,34 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState }) .filter((promise) => !!promise) ) - .then((requests) => { - const newState = requests.map((request, index) => { - if (request && request.responseXML != null) { - const key = keyArray[index]; - const result: any = extractFilesData(request.responseXML); - const sortedResult = sortBy(result, (n) => n.name).sort((n1, n2) => { - if (n1.type === 'directory' && n2.type !== 'directory') { - return -1; - } - if (n1.type !== 'directory' && n2.type === 'directory') { - return 1; - } - return 0; - }); - - return { [key]: sortedResult }; - } - return {}; - }).reduce((prev, next) => { - return { ...next, ...prev }; - }, {}); + .then((requests) => { + const newState = requests.map((request, index) => { + if (request && request.responseXML != null) { + const key = keyArray[index]; + const result: any = extractFilesData(request.responseXML); + const sortedResult = sortBy(result, (n) => n.name).sort((n1, n2) => { + if (n1.type === 'directory' && n2.type !== 'directory') { + return -1; + } + if (n1.type !== 'directory' && n2.type === 'directory') { + return 1; + } + return 0; + }); - setPathData({ ...pathData, ...newState }); - }) - .finally(() => { - setIsLoading(false); - keyArray.forEach(key => delete pathPromise[key]); - }); + return { [key]: sortedResult }; + } + return {}; + }).reduce((prev, next) => { + return { ...next, ...prev }; + }, {}); + + setPathData({ ...pathData, ...newState }); + }) + .finally(() => { + setIsLoading(false); + keyArray.forEach(key => delete pathPromise[key]); + }); }; React.useEffect(() => { @@ -280,7 +315,12 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState const currentPDH = (collectionPanel.item || {}).portableDataHash; React.useEffect(() => { if (currentPDH) { - fetchData([leftKey, rightKey], true); + // Avoid fetching the same content level twice + if (leftKey !== rightKey) { + fetchData([leftKey, rightKey], true); + } else { + fetchData(rightKey, true); + } } }, [currentPDH]); // eslint-disable-line react-hooks/exhaustive-deps @@ -315,13 +355,12 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState onItemMenuOpen(event, item, isWritable); } }, - [onItemMenuOpen, isWritable, rightData] // eslint-disable-line react-hooks/exhaustive-deps - ); + [onItemMenuOpen, isWritable, rightData]); React.useEffect(() => { let node = null; - if (parentRef && parentRef.current) { + if (parentRef?.current) { node = parentRef.current; (node as any).addEventListener('contextmenu', handleRightClick); } @@ -419,149 +458,107 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState [props.onOptionsMenuOpen] // eslint-disable-line react-hooks/exhaustive-deps ); - return ( -
-
-
- { - path - .map((p: string, index: number) => - {index === 0 ? 'Home' : p} /  - ) - } -
- - { - onOptionsMenuOpen(ev, isWritable); - }}> - + return
+
+
+ { path.map( (p: string, index: number) => + + {index === 0 ? 'Home' : p} /  + ) + } +
+ + { + onOptionsMenuOpen(ev, isWritable); + }}> + + + +
+
+
1 ? classes.leftPanelVisible : classes.leftPanelHidden)} data-cy="collection-files-left-panel"> + 1 ? classes.backButton : classes.backButtonHidden}> + setPath([...path.slice(0, path.length -1)])}> + +
1 ? classes.searchWrapper : classes.searchWrapperHidden}> + +
+
{ leftData + ? {({ height, width }) => { + const filtered = leftData.filter(({ name }) => name.indexOf(leftSearch) > -1); + return !!filtered.length + ? { ({ index, style }) => { + const { id, type, name } = filtered[index]; + return
+ { getItemIcon(type, getActiveClass(name)) } +
+ {name} +
+ { getActiveClass(name) + ? + : null + } +
; + }}
+ :
No directories available
+ }} +
+ :
} +
-
-
1 ? classes.leftPanelVisible : classes.leftPanelHidden)} data-cy="collection-files-left-panel"> - 1 ? classes.backButton : classes.backButtonHidden}> - setPath([...path.slice(0, path.length -1)])}> - - - -
1 ? classes.searchWrapper : classes.searchWrapperHidden}> - -
-
- { - leftData ? - - {({ height, width }) => { - const filtered = leftData.filter(({ name }) => name.indexOf(leftSearch) > -1); - - return !!filtered.length ? - { - ({ index, style }) => { - const { id, type, name } = filtered[index]; - - return
- {getItemIcon(type, getActiveClass(name))} -
- {name} -
- { - getActiveClass(name) ? : null - } -
; - } - } -
:
No directories available
- }} -
:
- } - -
+
+
+
-
-
- -
- { - isWritable && - - } -
- { - rightData && !isLoading ? - - {({ height, width }) => { - const filtered = rightData.filter(({ name }) => name.indexOf(rightSearch) > -1); - - return !!filtered.length ? - { - ({ index, style }) => { - const { id, type, name, size } = filtered[index]; - - return
-   - {getItemIcon(type, null)}
- {name} -
- - {formatFileSize(size)} - -
- } - } -
:
This collection is empty
- }} -
:
- } -
+ { isWritable && + } +
{ rightData && !isLoading + ? {({ height, width }) => { + const filtered = rightData.filter(({ name }) => name.indexOf(rightSearch) > -1); + return !!filtered.length + ? { ({ index, style }) => { + const { id, type, name, size } = filtered[index]; + + return
+   + {getItemIcon(type, null)} +
+ {name} +
+ + { formatFileSize(size) } + +
+ } }
+ :
This collection is empty
+ }}
+ :
+ +
}
- ); -})); +
})); diff --git a/src/store/collection-panel/collection-panel-action.ts b/src/store/collection-panel/collection-panel-action.ts index c50ff6a8..7bab8632 100644 --- a/src/store/collection-panel/collection-panel-action.ts +++ b/src/store/collection-panel/collection-panel-action.ts @@ -3,9 +3,6 @@ // SPDX-License-Identifier: AGPL-3.0 import { Dispatch } from "redux"; -import { - 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"; @@ -18,8 +15,6 @@ import { loadDetailsPanel } from 'store/details-panel/details-panel-action'; export const collectionPanelActions = unionize({ SET_COLLECTION: ofType(), - LOAD_COLLECTION_SUCCESS: ofType<{ item: CollectionResource }>(), - LOAD_BIG_COLLECTIONS: ofType(), }); export type CollectionPanelAction = UnionOf; @@ -27,15 +22,15 @@ export type CollectionPanelAction = UnionOf; export const loadCollectionPanel = (uuid: string, forceReload = false) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const { collectionPanel: { item } } = getState(); - const collection = (item && item.uuid === uuid && !forceReload) - ? item - : await services.collectionService.get(uuid); - dispatch(loadDetailsPanel(collection.uuid)); - dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: collection })); - dispatch(resourcesActions.SET_RESOURCES([collection])); - if (collection.fileCount <= COLLECTION_PANEL_LOAD_FILES_THRESHOLD && - !getState().collectionPanel.loadBigCollections) { + let collection: CollectionResource | null = null; + if (!item || item.uuid !== uuid || forceReload) { + collection = await services.collectionService.get(uuid); + dispatch(collectionPanelActions.SET_COLLECTION(collection)); + dispatch(resourcesActions.SET_RESOURCES([collection])); + } else { + collection = item; } + dispatch(loadDetailsPanel(collection.uuid)); return collection; }; diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts index 71e1f6e8..8c5e5b5a 100644 --- a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts +++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts @@ -15,8 +15,6 @@ import { filterCollectionFilesBySelection } from './collection-panel-files-state import { startSubmit, stopSubmit, initialize, FormErrors } from 'redux-form'; import { getDialog } from "store/dialog/dialog-reducer"; import { getFileFullPath, sortFilesTree } from "services/collection-service/collection-service-files-response"; -import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions"; -import { loadCollectionPanel } from "../collection-panel-action"; export const collectionPanelFilesAction = unionize({ SET_COLLECTION_FILES: ofType(), @@ -30,7 +28,6 @@ export const collectionPanelFilesAction = unionize({ export type CollectionPanelFilesAction = UnionOf; export const COLLECTION_PANEL_LOAD_FILES = 'collectionPanelLoadFiles'; -export const COLLECTION_PANEL_LOAD_FILES_THRESHOLD = 40000; export const setCollectionFiles = (files, joinParents = true) => (dispatch: any) => { const tree = createCollectionFilesTree(files, joinParents); @@ -39,33 +36,11 @@ export const setCollectionFiles = (files, joinParents = true) => (dispatch: any) dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES(mapped)); }; -export const loadCollectionFiles = (uuid: string) => - (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PANEL_LOAD_FILES)); - services.collectionService.files(uuid).then(files => { - // Given the array of directories and files, create the appropriate tree nodes, - // sort them, and add the complete url to each. - const tree = createCollectionFilesTree(files); - const sorted = sortFilesTree(tree); - const mapped = mapTreeValues(services.collectionService.extendFileURL)(sorted); - dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES(mapped)); - dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PANEL_LOAD_FILES)); - }).catch(() => { - dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PANEL_LOAD_FILES)); - dispatch(snackbarActions.OPEN_SNACKBAR({ - message: `Error getting file list`, - hideDuration: 2000, - kind: SnackbarKind.ERROR - })); - }); - }; - export const removeCollectionFiles = (filePaths: string[]) => (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const currentCollection = getState().collectionPanel.item; if (currentCollection) { services.collectionService.deleteFiles(currentCollection.uuid, filePaths).then(() => { - dispatch(loadCollectionPanel(currentCollection.uuid, true)); dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, @@ -155,7 +130,6 @@ export const renameFile = (newFullPath: string) => const oldPath = getFileFullPath(file); const newPath = newFullPath; services.collectionService.moveFile(currentCollection.uuid, oldPath, newPath).then(() => { - dispatch(loadCollectionPanel(currentCollection.uuid, true)); dispatch(dialogActions.CLOSE_DIALOG({ id: RENAME_FILE_DIALOG })); dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'File name changed.', hideDuration: 2000 })); }).catch(e => { diff --git a/src/store/collection-panel/collection-panel-reducer.ts b/src/store/collection-panel/collection-panel-reducer.ts index a6aa87bd..6afba66c 100644 --- a/src/store/collection-panel/collection-panel-reducer.ts +++ b/src/store/collection-panel/collection-panel-reducer.ts @@ -7,12 +7,10 @@ import { CollectionResource } from "models/collection"; export interface CollectionPanelState { item: CollectionResource | null; - loadBigCollections: boolean; } const initialState = { item: null, - loadBigCollections: false, }; export const collectionPanelReducer = (state: CollectionPanelState = initialState, action: CollectionPanelAction) => @@ -21,8 +19,5 @@ export const collectionPanelReducer = (state: CollectionPanelState = initialStat SET_COLLECTION: (item) => ({ ...state, item, - loadBigCollections: false, }), - LOAD_COLLECTION_SUCCESS: ({ item }) => ({ ...state, item }), - LOAD_BIG_COLLECTIONS: (loadBigCollections) => ({ ...state, loadBigCollections}), }); diff --git a/src/store/collections/collection-update-actions.ts b/src/store/collections/collection-update-actions.ts index 82418d27..bf9c6449 100644 --- a/src/store/collections/collection-update-actions.ts +++ b/src/store/collections/collection-update-actions.ts @@ -55,7 +55,7 @@ export const updateCollection = (collection: CollectionUpdateFormDialogData) => properties: collection.properties } ).then(updatedCollection => { updatedCollection = {...cachedCollection, ...updatedCollection}; - dispatch(collectionPanelActions.LOAD_COLLECTION_SUCCESS({ item: updatedCollection as CollectionResource })); + dispatch(collectionPanelActions.SET_COLLECTION(updatedCollection)); dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_UPDATE_FORM_NAME })); dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_UPDATE_FORM_NAME)); dispatch(snackbarActions.OPEN_SNACKBAR({ diff --git a/src/store/collections/collection-upload-actions.ts b/src/store/collections/collection-upload-actions.ts index 135538b0..e9c5cc35 100644 --- a/src/store/collections/collection-upload-actions.ts +++ b/src/store/collections/collection-upload-actions.ts @@ -6,14 +6,10 @@ import { Dispatch } from 'redux'; import { RootState } from 'store/store'; import { ServiceRepository } from 'services/services'; import { dialogActions } from 'store/dialog/dialog-actions'; -import { loadCollectionFiles } from '../collection-panel/collection-panel-files/collection-panel-files-actions'; import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions'; import { fileUploaderActions } from 'store/file-uploader/file-uploader-actions'; import { reset, startSubmit, stopSubmit } from 'redux-form'; import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions"; -import { collectionPanelFilesAction } from 'store/collection-panel/collection-panel-files/collection-panel-files-actions'; -import { createTree } from 'models/tree'; -import { loadCollectionPanel } from '../collection-panel/collection-panel-action'; import * as WorkbenchActions from 'store/workbench/workbench-actions'; export const uploadCollectionFiles = (collectionUuid: string, targetLocation?: string) => @@ -40,10 +36,7 @@ export const submitCollectionFiles = (targetLocation?: string) => try { dispatch(progressIndicatorActions.START_WORKING(COLLECTION_UPLOAD_FILES_DIALOG)); dispatch(startSubmit(COLLECTION_UPLOAD_FILES_DIALOG)); - await dispatch(uploadCollectionFiles(currentCollection.uuid, targetLocation)) - .then(() => dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES({ files: createTree() }))); - dispatch(loadCollectionFiles(currentCollection.uuid)); - dispatch(loadCollectionPanel(currentCollection.uuid)); + await dispatch(uploadCollectionFiles(currentCollection.uuid, targetLocation)); dispatch(closeUploadCollectionFilesDialog()); dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Data has been uploaded.', diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts index d2ff84b3..0a348431 100644 --- a/src/store/workbench/workbench-actions.ts +++ b/src/store/workbench/workbench-actions.ts @@ -100,8 +100,6 @@ import { subprocessPanelActions } from 'store/subprocess-panel/subprocess-panel- import { subprocessPanelColumns } from 'views/subprocess-panel/subprocess-panel-root'; import { loadAllProcessesPanel, allProcessesPanelActions } from '../all-processes-panel/all-processes-panel-action'; import { allProcessesPanelColumns } from 'views/all-processes-panel/all-processes-panel'; -import { collectionPanelFilesAction } from '../collection-panel/collection-panel-files/collection-panel-files-actions'; -import { createTree } from 'models/tree'; import { AdminMenuIcon } from 'components/icon/icon'; import { userProfileGroupsColumns } from 'views/user-profile-panel/user-profile-panel-root'; @@ -295,11 +293,9 @@ export const loadCollection = (uuid: string) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const userUuid = getUserUuid(getState()); if (userUuid) { - // Clear collection files panel - dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES({ files: createTree() })); const match = await loadGroupContentsResource({ uuid, userUuid, services }); match({ - OWNED: async collection => { + OWNED: collection => { dispatch(collectionPanelActions.SET_COLLECTION(collection as CollectionResource)); dispatch(updateResources([collection])); dispatch(activateSidePanelTreeItem(collection.ownerUuid)); diff --git a/src/store/workflow-panel/workflow-panel-actions.ts b/src/store/workflow-panel/workflow-panel-actions.ts index 7c90fa6b..912f7630 100644 --- a/src/store/workflow-panel/workflow-panel-actions.ts +++ b/src/store/workflow-panel/workflow-panel-actions.ts @@ -9,13 +9,18 @@ import { bindDataExplorerActions } from 'store/data-explorer/data-explorer-actio import { propertiesActions } from 'store/properties/properties-actions'; import { getProperty } from 'store/properties/properties'; import { navigateToRunProcess } from 'store/navigation/navigation-action'; -import { goToStep, runProcessPanelActions, loadPresets, getWorkflowRunnerSettings } from 'store/run-process-panel/run-process-panel-actions'; +import { + goToStep, + runProcessPanelActions, + loadPresets, + getWorkflowRunnerSettings +} from 'store/run-process-panel/run-process-panel-actions'; import { snackbarActions } from 'store/snackbar/snackbar-actions'; import { initialize } from 'redux-form'; import { RUN_PROCESS_BASIC_FORM } from 'views/run-process-panel/run-process-basic-form'; import { RUN_PROCESS_INPUTS_FORM } from 'views/run-process-panel/run-process-inputs-form'; import { RUN_PROCESS_ADVANCED_FORM } from 'views/run-process-panel/run-process-advanced-form'; -import { getResource, ResourcesState } from 'store/resources/resources'; +import { getResource } from 'store/resources/resources'; import { ProjectResource } from 'models/project'; import { UserResource } from 'models/user'; import { getUserUuid } from "common/getuser"; diff --git a/src/views-components/collection-panel-files/collection-panel-files.ts b/src/views-components/collection-panel-files/collection-panel-files.ts index 216ec669..a26b9fe3 100644 --- a/src/views-components/collection-panel-files/collection-panel-files.ts +++ b/src/views-components/collection-panel-files/collection-panel-files.ts @@ -8,41 +8,17 @@ import { CollectionPanelFilesProps } from "components/collection-panel-files/collection-panel-files"; import { RootState } from "store/store"; -import { TreeItemStatus } from "components/tree/tree"; -import { VirtualTreeItem as TreeItem } from "components/tree/virtual-tree"; -import { - CollectionPanelDirectory, - CollectionPanelFile, - CollectionPanelFilesState -} from "store/collection-panel/collection-panel-files/collection-panel-files-state"; -import { FileTreeData } from "components/file-tree/file-tree-data"; import { Dispatch } from "redux"; import { collectionPanelFilesAction } from "store/collection-panel/collection-panel-files/collection-panel-files-actions"; import { ContextMenuKind } from "../context-menu/context-menu"; -import { getNode, getNodeChildrenIds, Tree, TreeNode, initTreeNode } from "models/tree"; -import { CollectionFileType, createCollectionDirectory } from "models/collection-file"; import { openContextMenu, openCollectionFilesContextMenu } from 'store/context-menu/context-menu-actions'; import { openUploadCollectionFilesDialog } from 'store/collections/collection-upload-actions'; import { ResourceKind } from "models/resource"; import { openDetailsPanel } from 'store/details-panel/details-panel-action'; -const memoizedMapStateToProps = () => { - let prevState: CollectionPanelFilesState; - let prevTree: Array>; - - return (state: RootState): Pick => { - if (prevState !== state.collectionPanelFiles) { - prevState = state.collectionPanelFiles; - prevTree = [].concat.apply( - [], getNodeChildrenIds('')(state.collectionPanelFiles) - .map(collectionItemToList(0)(state.collectionPanelFiles))); - } - return { - items: prevTree, - currentItemUuid: state.detailsPanel.resourceUuid - }; - }; -}; +const mapStateToProps = (state: RootState): Pick => ({ + currentItemUuid: state.detailsPanel.resourceUuid +}); const mapDispatchToProps = (dispatch: Dispatch): Pick => ({ onUploadDataClick: (targetLocation?: string) => { @@ -84,43 +60,4 @@ const mapDispatchToProps = (dispatch: Dispatch): Pick (tree: Tree) => - (id: string): TreeItem[] => { - const node: TreeNode = getNode(id)(tree) || initTreeNode({ - id: '', - parent: '', - value: { - ...createCollectionDirectory({ name: 'Invalid file' }), - selected: false, - collapsed: true - } - }); - - const treeItem = { - active: false, - data: { - name: node.value.name, - size: node.value.type === CollectionFileType.FILE ? node.value.size : undefined, - type: node.value.type, - url: node.value.url, - }, - id: node.id, - items: [], // Not used in this case as we're converting a tree to a list. - itemCount: node.children.length, - open: node.value.type === CollectionFileType.DIRECTORY ? !node.value.collapsed : false, - selected: node.value.selected, - status: TreeItemStatus.LOADED, - level, - }; - - const treeItemChilds = treeItem.open - ? [].concat.apply([], node.children.map(collectionItemToList(level+1)(tree))) - : []; - - return [ - treeItem, - ...treeItemChilds, - ]; - }; +export const CollectionPanelFiles = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/src/views-components/data-explorer/renderers.tsx b/src/views-components/data-explorer/renderers.tsx index cd9f972e..7822bdc6 100644 --- a/src/views-components/data-explorer/renderers.tsx +++ b/src/views-components/data-explorer/renderers.tsx @@ -184,22 +184,22 @@ export const ResourceLastName = connect( return resource || { lastName: '' }; })(renderLastName); -const renderFullName = (dispatch: Dispatch ,item: { uuid: string, firstName: string, lastName: string }, link?: boolean) => { +const renderFullName = (dispatch: Dispatch, item: { uuid: string, firstName: string, lastName: string }, link?: boolean) => { const displayName = (item.firstName + " " + item.lastName).trim() || item.uuid; return link ? dispatch(navigateToUserProfile(item.uuid))}> - {displayName} + {displayName} : - {displayName}; + {displayName}; } export const UserResourceFullName = connect( (state: RootState, props: { uuid: string, link?: boolean }) => { const resource = getResource(props.uuid)(state.resources); - return {item: resource || { uuid: '', firstName: '', lastName: '' }, link: props.link}; - })((props: {item: {uuid: string, firstName: string, lastName: string}, link?: boolean} & DispatchProp) => renderFullName(props.dispatch, props.item, props.link)); + return { item: resource || { uuid: '', firstName: '', lastName: '' }, link: props.link }; + })((props: { item: { uuid: string, firstName: string, lastName: string }, link?: boolean } & DispatchProp) => renderFullName(props.dispatch, props.item, props.link)); const renderUuid = (item: { uuid: string }) => @@ -208,8 +208,8 @@ const renderUuid = (item: { uuid: string }) => ; export const ResourceUuid = connect((state: RootState, props: { uuid: string }) => ( - getResource(props.uuid)(state.resources) || { uuid: '' } - ))(renderUuid); + getResource(props.uuid)(state.resources) || { uuid: '' } +))(renderUuid); const renderEmail = (item: { email: string }) => {item.email}; @@ -227,17 +227,17 @@ enum UserAccountStatus { UNKNOWN = '' } -const renderAccountStatus = (props: {status: UserAccountStatus}) => +const renderAccountStatus = (props: { status: UserAccountStatus }) => {(() => { - switch(props.status) { + switch (props.status) { case UserAccountStatus.ACTIVE: - return ; + return ; case UserAccountStatus.SETUP: - return ; + return ; case UserAccountStatus.INACTIVE: - return ; + return ; default: return <>; } @@ -262,37 +262,37 @@ const getUserAccountStatus = (state: RootState, props: { uuid: string }) => { )(state.resources); if (user) { - return user.isActive ? {status: UserAccountStatus.ACTIVE} : permissions.length > 0 ? {status: UserAccountStatus.SETUP} : {status: UserAccountStatus.INACTIVE}; + return user.isActive ? { status: UserAccountStatus.ACTIVE } : permissions.length > 0 ? { status: UserAccountStatus.SETUP } : { status: UserAccountStatus.INACTIVE }; } else { - return {status: UserAccountStatus.UNKNOWN}; + return { status: UserAccountStatus.UNKNOWN }; } } export const ResourceLinkTailAccountStatus = connect( (state: RootState, props: { uuid: string }) => { const link = getResource(props.uuid)(state.resources); - return link && link.tailKind === ResourceKind.USER ? getUserAccountStatus(state, {uuid: link.tailUuid}) : {status: UserAccountStatus.UNKNOWN}; + return link && link.tailKind === ResourceKind.USER ? getUserAccountStatus(state, { uuid: link.tailUuid }) : { status: UserAccountStatus.UNKNOWN }; })(renderAccountStatus); export const UserResourceAccountStatus = connect(getUserAccountStatus)(renderAccountStatus); const renderIsHidden = (props: { - memberLinkUuid: string, - permissionLinkUuid: string, - visible: boolean, - canManage: boolean, - setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void - }) => { + memberLinkUuid: string, + permissionLinkUuid: string, + visible: boolean, + canManage: boolean, + setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void +}) => { if (props.memberLinkUuid) { return { - e.stopPropagation(); - props.setMemberIsHidden(props.memberLinkUuid, props.permissionLinkUuid, !props.visible); - }} />; + data-cy="user-visible-checkbox" + color="primary" + checked={props.visible} + disabled={!props.canManage} + onClick={(e) => { + e.stopPropagation(); + props.setMemberIsHidden(props.memberLinkUuid, props.permissionLinkUuid, !props.visible); + }} />; } else { return ; } @@ -357,7 +357,7 @@ export const VirtualMachineHostname = connect( return resource || { hostname: '' }; })(renderHostname); -const renderVirtualMachineLogin = (login: {user: string}) => +const renderVirtualMachineLogin = (login: { user: string }) => {login.user} export const VirtualMachineLogin = connect( @@ -365,7 +365,7 @@ export const VirtualMachineLogin = connect( const permission = getResource(props.linkUuid)(state.resources); const user = getResource(permission?.tailUuid || '')(state.resources); - return {user: user?.username || permission?.tailUuid || ''}; + return { user: user?.username || permission?.tailUuid || '' }; })(renderVirtualMachineLogin); // Common methods @@ -442,7 +442,7 @@ export const ResourceLinkClass = connect( const getResourceDisplayName = (resource: Resource): string => { if ((resource as UserResource).kind === ResourceKind.USER - && typeof (resource as UserResource).firstName !== 'undefined') { + && typeof (resource as UserResource).firstName !== 'undefined') { // We can be sure the resource is UserResource return getUserDisplayName(resource as UserResource); } else { @@ -516,7 +516,7 @@ const renderLinkDelete = (dispatch: Dispatch, item: LinkResource, canManage: boo ; } else { - return ; + return ; } } @@ -530,7 +530,7 @@ export const ResourceLinkDelete = connect( canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin, }; })((props: { item: LinkResource, canManage: boolean } & DispatchProp) => - renderLinkDelete(props.dispatch, props.item, props.canManage)); + renderLinkDelete(props.dispatch, props.item, props.canManage)); export const ResourceLinkTailEmail = connect( (state: RootState, props: { uuid: string }) => { @@ -713,10 +713,17 @@ const userFromID = return { uuid: props.uuid, userFullname }; }); -export const ResourceOwnerWithName = +const ownerFromResourceId = compose( - userFromID, - withStyles({}, { withTheme: true })) + connect((state: RootState, props: { uuid: string }) => { + const childResource = getResource(props.uuid)(state.resources); + return { uuid: childResource ? (childResource as Resource).ownerUuid : '' }; + }), + userFromID + ); + +const _resourceWithName = + withStyles({}, { withTheme: true }) ((props: { uuid: string, userFullname: string, dispatch: Dispatch, theme: ArvadosTheme }) => { const { uuid, userFullname, dispatch, theme } = props; @@ -732,6 +739,10 @@ export const ResourceOwnerWithName = ; }); +export const ResourceOwnerWithName = ownerFromResourceId(_resourceWithName); + +export const ResourceWithName = userFromID(_resourceWithName); + export const UserNameFromID = compose(userFromID)( (props: { uuid: string, userFullname: string, dispatch: Dispatch }) => { @@ -798,7 +809,7 @@ export const ResponsiblePerson = return {responsiblePersonName} ({uuid}) - ; + ; }); const renderType = (type: string, subtype: string) => @@ -835,18 +846,18 @@ export const ProcessStatus = compose( withStyles({}, { withTheme: true })) ((props: { process?: Process, theme: ArvadosTheme }) => props.process - ? - : - + ? + : - ); export const ProcessStartDate = connect( diff --git a/src/views-components/details-panel/project-details.tsx b/src/views-components/details-panel/project-details.tsx index d4100767..6d48e984 100644 --- a/src/views-components/details-panel/project-details.tsx +++ b/src/views-components/details-panel/project-details.tsx @@ -16,7 +16,7 @@ import { withStyles, StyleRulesCallback, WithStyles, Button } from '@material-ui import { ArvadosTheme } from 'common/custom-theme'; import { Dispatch } from 'redux'; import { getPropertyChip } from '../resource-properties-form/property-chip'; -import { ResourceOwnerWithName } from '../data-explorer/renderers'; +import { ResourceWithName } from '../data-explorer/renderers'; import { GroupClass } from "models/group"; import { openProjectUpdateDialog, ProjectUpdateFormDialogData } from 'store/projects/project-update-actions'; @@ -41,7 +41,7 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ marginBottom: theme.spacing.unit / 2, }, editIcon: { - paddingRight: theme.spacing.unit/2, + paddingRight: theme.spacing.unit / 2, fontSize: '1.125rem', }, editButton: { @@ -70,21 +70,21 @@ const ProjectDetailsComponent = connect(null, mapDispatchToProps)( withStyles(styles)( ({ classes, project, onClick }: ProjectDetailsComponentProps) =>
{project.groupClass !== GroupClass.FILTER ? - - : '' - } + + : '' + } } /> + uuidEnhancer={(uuid: string) => } /> @@ -101,9 +101,9 @@ const ProjectDetailsComponent = connect(null, mapDispatchToProps)( { Object.keys(project.properties).map(k => Array.isArray(project.properties[k]) - ? project.properties[k].map((v: string) => - getPropertyChip(k, v, undefined, classes.tag)) - : getPropertyChip(k, project.properties[k], undefined, classes.tag) + ? project.properties[k].map((v: string) => + getPropertyChip(k, v, undefined, classes.tag)) + : getPropertyChip(k, project.properties[k], undefined, classes.tag) ) }
diff --git a/src/views-components/details-panel/workflow-details.tsx b/src/views-components/details-panel/workflow-details.tsx index 7076823c..98978dd2 100644 --- a/src/views-components/details-panel/workflow-details.tsx +++ b/src/views-components/details-panel/workflow-details.tsx @@ -3,12 +3,11 @@ // SPDX-License-Identifier: AGPL-3.0 import React from 'react'; -import { DefaultIcon, WorkflowIcon } from 'components/icon/icon'; +import { WorkflowIcon } from 'components/icon/icon'; import { WorkflowResource } from 'models/workflow'; import { DetailsData } from "./details-data"; -import { DefaultView } from 'components/default-view/default-view'; import { DetailsAttribute } from 'components/details-attribute/details-attribute'; -import { ResourceOwnerWithName } from 'views-components/data-explorer/renderers'; +import { ResourceWithName } from 'views-components/data-explorer/renderers'; import { formatDate } from "common/formatters"; import { Grid } from '@material-ui/core'; import { withStyles, StyleRulesCallback, WithStyles, Button } from '@material-ui/core'; @@ -61,7 +60,7 @@ export const WorkflowDetailsAttributes = connect(null, mapDispatchToProps)( } /> + uuidEnhancer={(uuid: string) => } /> @@ -72,7 +71,7 @@ export const WorkflowDetailsAttributes = connect(null, mapDispatchToProps)( } /> + uuidEnhancer={(uuid: string) => } /> ; })); diff --git a/src/views/collection-panel/collection-panel.tsx b/src/views/collection-panel/collection-panel.tsx index dce8ef8f..9d127a60 100644 --- a/src/views/collection-panel/collection-panel.tsx +++ b/src/views/collection-panel/collection-panel.tsx @@ -21,7 +21,7 @@ import { MoreOptionsIcon, CollectionIcon, ReadOnlyIcon, CollectionOldVersionIcon import { DetailsAttribute } from 'components/details-attribute/details-attribute'; import { CollectionResource, getCollectionUrl } from 'models/collection'; import { CollectionPanelFiles } from 'views-components/collection-panel-files/collection-panel-files'; -import { navigateToProcess, collectionPanelActions } from 'store/collection-panel/collection-panel-action'; +import { navigateToProcess } from 'store/collection-panel/collection-panel-action'; import { getResource } from 'store/resources/resources'; import { openContextMenu, resourceUuidToContextMenuKind } from 'store/context-menu/context-menu-actions'; import { formatDate, formatFileSize } from "common/formatters"; @@ -32,11 +32,9 @@ import { IllegalNamingWarning } from 'components/warning/warning'; import { GroupResource } from 'models/group'; import { UserResource } from 'models/user'; import { getUserUuid } from 'common/getuser'; -import { getProgressIndicator } from 'store/progress-indicator/progress-indicator-reducer'; -import { COLLECTION_PANEL_LOAD_FILES, loadCollectionFiles, COLLECTION_PANEL_LOAD_FILES_THRESHOLD } from 'store/collection-panel/collection-panel-files/collection-panel-files-actions'; import { Link } from 'react-router-dom'; import { Link as ButtonLink } from '@material-ui/core'; -import { ResourceOwnerWithName, ResponsiblePerson } from 'views-components/data-explorer/renderers'; +import { ResourceWithName, ResponsiblePerson } from 'views-components/data-explorer/renderers'; import { MPVContainer, MPVPanelContent, MPVPanelState } from 'components/multi-panel-view/multi-panel-view'; type CssRules = 'root' @@ -115,14 +113,12 @@ interface CollectionPanelDataProps { isWritable: boolean; isOldVersion: boolean; isLoadingFiles: boolean; - tooManyFiles: boolean; } -type CollectionPanelProps = CollectionPanelDataProps & DispatchProp - & WithStyles & RouteComponentProps<{ id: string }>; +type CollectionPanelProps = CollectionPanelDataProps & DispatchProp & WithStyles -export const CollectionPanel = withStyles(styles)( - connect((state: RootState, props: RouteComponentProps<{ id: string }>) => { +export const CollectionPanel = withStyles(styles)(connect( + (state: RootState, props: RouteComponentProps<{ id: string }>) => { const currentUserUUID = getUserUuid(state); const item = getResource(props.match.params.id)(state.resources); let isWritable = false; @@ -137,17 +133,14 @@ export const CollectionPanel = withStyles(styles)( } } } - const loadingFilesIndicator = getProgressIndicator(COLLECTION_PANEL_LOAD_FILES)(state.progressIndicator); - const isLoadingFiles = (loadingFilesIndicator && loadingFilesIndicator!.working) || false; - const tooManyFiles = (!state.collectionPanel.loadBigCollections && item && item.fileCount > COLLECTION_PANEL_LOAD_FILES_THRESHOLD) || false; - return { item, isWritable, isOldVersion, isLoadingFiles, tooManyFiles }; + return { item, isWritable, isOldVersion }; })( class extends React.Component { render() { - const { classes, item, dispatch, isWritable, isOldVersion, isLoadingFiles, tooManyFiles } = this.props; + const { classes, item, dispatch, isWritable, isOldVersion } = this.props; const panelsData: MPVPanelState[] = [ - {name: "Details"}, - {name: "Files"}, + { name: "Details" }, + { name: "Files" }, ]; return item ? @@ -195,7 +188,7 @@ export const CollectionPanel = withStyles(styles)( {isOldVersion && This is an old version. Make a copy to make changes. Go to the head version for sharing options. - + }
@@ -203,15 +196,7 @@ export const CollectionPanel = withStyles(styles)( - { - dispatch(collectionPanelActions.LOAD_BIG_COLLECTIONS(true)); - dispatch(loadCollectionFiles(this.props.item.uuid)); - } - } /> + @@ -288,7 +273,7 @@ export const CollectionDetailsAttributes = (props: CollectionDetailsProps) => { } /> + uuidEnhancer={(uuid: string) => } />
@@ -341,13 +326,13 @@ export const CollectionDetailsAttributes = (props: CollectionDetailsProps) => { - { Object.keys(item.properties).length > 0 + {Object.keys(item.properties).length > 0 ? Object.keys(item.properties).map(k => - Array.isArray(item.properties[k]) + Array.isArray(item.properties[k]) ? item.properties[k].map((v: string) => getPropertyChip(k, v, undefined, classes.tag)) : getPropertyChip(k, item.properties[k], undefined, classes.tag)) - :
No properties
} + :
No properties
}
; }; diff --git a/src/views/process-panel/process-details-attributes.tsx b/src/views/process-panel/process-details-attributes.tsx index 99a4404c..1e3e5591 100644 --- a/src/views/process-panel/process-details-attributes.tsx +++ b/src/views/process-panel/process-details-attributes.tsx @@ -9,7 +9,7 @@ import { formatDate } from "common/formatters"; import { resourceLabel } from "common/labels"; import { DetailsAttribute } from "components/details-attribute/details-attribute"; import { ResourceKind } from "models/resource"; -import { ContainerRunTime, ResourceOwnerWithName } from "views-components/data-explorer/renderers"; +import { ContainerRunTime, ResourceWithName } from "views-components/data-explorer/renderers"; import { getProcess, getProcessStatus } from "store/processes/process"; import { RootState } from "store/store"; import { connect } from "react-redux"; @@ -79,7 +79,7 @@ export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })( } /> + uuidEnhancer={(uuid: string) => } /> diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx index e0fcb48c..ccb40d53 100644 --- a/src/views/project-panel/project-panel.tsx +++ b/src/views/project-panel/project-panel.tsx @@ -180,7 +180,7 @@ export const ProjectPanel = withStyles(styles)( name: resource.name, uuid: resource.uuid, ownerUuid: resource.ownerUuid, - isTrashed: ('isTrashed' in resource) ? resource.isTrashed: false, + isTrashed: ('isTrashed' in resource) ? resource.isTrashed : false, kind: resource.kind, menuKind, description: resource.description,