From: Eric Biagiotti Date: Wed, 4 Dec 2019 22:00:52 +0000 (-0500) Subject: 15672: subprocess view WIP X-Git-Tag: 2.0.0~15^2~24 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/da85f1807c0223ab3de12448ae75df5482a457d8 15672: subprocess view WIP Arvados-DCO-1.1-Signed-off-by: Eric Biagiotti --- diff --git a/src/store/resource-type-filters/resource-type-filters.ts b/src/store/resource-type-filters/resource-type-filters.ts index e1a1b835..8e856c94 100644 --- a/src/store/resource-type-filters/resource-type-filters.ts +++ b/src/store/resource-type-filters/resource-type-filters.ts @@ -11,6 +11,16 @@ import { getSelectedNodes } from '~/models/tree'; import { CollectionType } from '~/models/collection'; import { GroupContentsResourcePrefix } from '~/services/groups-service/groups-service'; +export enum ProcessStatusFilter { + ALL = 'All', + RUNNING = 'Running', + FAILED = 'Failed', + COMPLETED = 'Completed', + CANCELLED = 'Cancelled', + LOCKED = 'Locked', + QUEUED = 'Queued' +} + export enum ObjectTypeFilter { PROJECT = 'Project', PROCESS = 'Process', @@ -23,14 +33,14 @@ export enum CollectionTypeFilter { LOG_COLLECTION = 'Log', } -const initFilter = (name: string, parent = '') => +const initFilter = (name: string, parent = '', isSelected?: boolean) => setNode({ id: name, value: { name }, parent, children: [], active: false, - selected: true, + selected: isSelected !== undefined ? isSelected : true, expanded: false, status: TreeNodeStatus.LOADED, }); @@ -52,6 +62,17 @@ export const getInitialResourceTypeFilters = pipe( initFilter(CollectionTypeFilter.LOG_COLLECTION, ObjectTypeFilter.COLLECTION), ); +export const getInitialProcessStatusFilters = pipe( + (): DataTableFilters => createTree(), + initFilter(ProcessStatusFilter.ALL, '', true), + initFilter(ProcessStatusFilter.RUNNING, '', false), + initFilter(ProcessStatusFilter.FAILED, '', false), + initFilter(ProcessStatusFilter.COMPLETED, '', false), + initFilter(ProcessStatusFilter.CANCELLED, '', false), + initFilter(ProcessStatusFilter.QUEUED, '', false), + initFilter(ProcessStatusFilter.LOCKED, '', false), +); + export const getTrashPanelTypeFilters = pipe( (): DataTableFilters => createTree(), initFilter(ObjectTypeFilter.PROJECT), diff --git a/src/store/subprocess-panel/subprocess-panel-middleware-service.ts b/src/store/subprocess-panel/subprocess-panel-middleware-service.ts index 4655bd02..6f55bfa1 100644 --- a/src/store/subprocess-panel/subprocess-panel-middleware-service.ts +++ b/src/store/subprocess-panel/subprocess-panel-middleware-service.ts @@ -17,6 +17,9 @@ import { ProcessResource } from '~/models/process'; import { SubprocessPanelColumnNames } from '~/views/subprocess-panel/subprocess-panel-root'; import { FilterBuilder } from '~/services/api/filter-builder'; import { subprocessPanelActions } from './subprocess-panel-actions'; +/* import { getProcessStatus } from '../processes/process'; +import { ContainerRequestResource } from '~/models/container-request'; +import { ContainerResource } from '~/models/container';*/ export class SubprocessMiddlewareService extends DataExplorerMiddlewareService { constructor(private services: ServiceRepository, id: string) { @@ -28,48 +31,56 @@ export class SubprocessMiddlewareService extends DataExplorerMiddlewareService { const dataExplorer = getDataExplorer(state.dataExplorer, this.getId()); try { - const crUuid = state.processPanel.containerRequestUuid; - if (crUuid !== "") { - const containerRequest = await this.services.containerRequestService.get(crUuid); - if (containerRequest.containerUuid) { - const filters = new FilterBuilder().addEqual('requestingContainerUuid', containerRequest.containerUuid).getFilters(); - const containerRequests = await this.services.containerRequestService.list({ ...getParams(dataExplorer), filters }); - api.dispatch(updateResources(containerRequests.items)); - api.dispatch(setItems(containerRequests)); - - const containerUuids: string[] = containerRequests.items.reduce((uuids, { containerUuid }) => - containerUuid - ? [...uuids, containerUuid] - : uuids, []); - - if (containerUuids.length > 0) { - const filters = new FilterBuilder().addIn('uuid', containerUuids).getFilters(); - const containers = await this.services.containerService.list({ filters }); - api.dispatch(updateResources(containers.items)); + const parentContainerRequestUuid = state.processPanel.containerRequestUuid; + if (parentContainerRequestUuid === "") { return; } + + const parentContainerRequest = await this.services.containerRequestService.get(parentContainerRequestUuid); + if (!parentContainerRequest.containerUuid) { return; } + + // Get all the subprocess container requests and containers (not filtered based on the data explorer parameters). + // This lets us filter based on the combined status of the container request and its container, if it exists. + let filters = new FilterBuilder().addEqual('requestingContainerUuid', parentContainerRequest.containerUuid).getFilters(); + const containerRequests = await this.services.containerRequestService.list({ filters }); + if (containerRequests.items.length === 0) { return; } + console.log(containerRequests); + + const containerUuids: string[] = containerRequests.items.reduce((uuids, { containerUuid }) => + containerUuid + ? [...uuids, containerUuid] + : uuids, []); + filters = new FilterBuilder().addIn('uuid', containerUuids).getFilters(); + // const containers = await this.services.containerService.list({ filters }); + + // Find a container requests corresponding container if it exists and check if it should be displayed + const filteredContainerRequestUuids: string[] = []; + const filteredContainerUuids: string[] = []; + /* containerRequests.items.forEach( + (cr: ContainerRequestResource) => { + const c = containers.items.find((c: ContainerResource) => cr.containerUuid === c.uuid); + const process = c ? { containerRequest: cr, container: c } : { containerRequest: cr }; + + if (statusFilters === getProcessStatus(process)) { + filteredContainerRequestUuids.push(process.containerRequest.uuid); + if (process.container) { filteredContainerUuids.push(process.container.uuid); } } - } - } - // TODO: set filters based on process panel state + }); +*/ + // Requery with the data expolorer query paramaters to populate the actual user view + filters = new FilterBuilder().addIn('uuid', filteredContainerRequestUuids).getFilters(); + const containerRequestResources = await this.services.containerRequestService.list({ ...getParams(dataExplorer), filters }); + api.dispatch(updateResources(containerRequestResources.items)); + + filters = new FilterBuilder().addIn('uuid', filteredContainerUuids).getFilters(); + const containerResources = await this.services.containerService.list({ ...getParams(dataExplorer), filters }); + api.dispatch(updateResources(containerResources.items)); + api.dispatch(setItems(containerRequestResources)); } catch { api.dispatch(couldNotFetchSubprocesses()); } } } -/*export const getFilters = (processPanel: ProcessPanelState, processes: Process[]) => { - const grouppedProcesses = groupBy(processes, getProcessStatus); - return Object - .keys(processPanel.filters) - .map(filter => ({ - label: filter, - value: (grouppedProcesses[filter] || []).length, - checked: processPanel.filters[filter], - key: filter, - })); - }; -*/ - export const getParams = (dataExplorer: DataExplorer) => ({ ...dataExplorerToListParams(dataExplorer), order: getOrder(dataExplorer) diff --git a/src/views/subprocess-panel/subprocess-panel-root.tsx b/src/views/subprocess-panel/subprocess-panel-root.tsx index 770139e0..fac421bc 100644 --- a/src/views/subprocess-panel/subprocess-panel-root.tsx +++ b/src/views/subprocess-panel/subprocess-panel-root.tsx @@ -9,17 +9,19 @@ import { DataTableFilterItem } from '~/components/data-table-filters/data-table- import { ContainerRequestState } from '~/models/container-request'; import { SortDirection } from '~/components/data-table/data-column'; import { ResourceKind } from '~/models/resource'; -import { ResourceLastModifiedDate, ProcessStatus } from '~/views-components/data-explorer/renderers'; +import { ResourceCreatedAtDate, ProcessStatus, ContainerRunTime } from '~/views-components/data-explorer/renderers'; import { ProcessIcon } from '~/components/icon/icon'; import { ResourceName } from '~/views-components/data-explorer/renderers'; import { SUBPROCESS_PANEL_ID } from '~/store/subprocess-panel/subprocess-panel-actions'; import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view'; import { createTree } from '~/models/tree'; +import { getInitialProcessStatusFilters } from '~/store/resource-type-filters/resource-type-filters'; export enum SubprocessPanelColumnNames { NAME = "Name", STATUS = "Status", - LAST_MODIFIED = "Last modified" + CREATED_AT = "Created At", + RUNTIME = "Run Time" } export interface SubprocessPanelFilter extends DataTableFilterItem { @@ -36,36 +38,49 @@ export const subprocessPanelColumns: DataColumns = [ render: uuid => }, { - name: "Status", + name: SubprocessPanelColumnNames.STATUS, selected: true, configurable: true, - filters: createTree(), + mutuallyExclusiveFilters: true, + filters: getInitialProcessStatusFilters(), render: uuid => , }, { - name: SubprocessPanelColumnNames.LAST_MODIFIED, + name: SubprocessPanelColumnNames.CREATED_AT, selected: true, configurable: true, sortDirection: SortDirection.DESC, filters: createTree(), - render: uuid => + render: uuid => + }, + { + name: SubprocessPanelColumnNames.RUNTIME, + selected: true, + configurable: true, + filters: createTree(), + render: uuid => } ]; -export interface SubprocessActionProps { +export interface SubprocessPanelDataProps { + isAdmin: boolean; +} + +export interface SubprocessPanelActionProps { onItemClick: (item: string) => void; - onContextMenu: (event: React.MouseEvent, item: string) => void; + onContextMenu: (event: React.MouseEvent, item: string, isAdmin: boolean) => void; onItemDoubleClick: (item: string) => void; } -export const SubprocessPanelRoot = (props: SubprocessActionProps) => { +type SubprocessPanelProps = SubprocessPanelActionProps & SubprocessPanelDataProps; + +export const SubprocessPanelRoot = (props: SubprocessPanelProps) => { return props.onContextMenu(event, item, props.isAdmin)} contextMenuColumn={true} - hideColumnSelector dataTableDefaultView={ ({ - onContextMenu: (event, resourceUuid) => { +const mapDispatchToProps = (dispatch: Dispatch): SubprocessPanelActionProps => ({ + onContextMenu: (event, resourceUuid, isAdmin) => { const kind = resourceKindToContextMenuKind(resourceUuid); if (kind) { dispatch(openContextMenu(event, { @@ -25,4 +26,8 @@ const mapDispatchToProps = (dispatch: Dispatch): SubprocessActionProps => ({ onItemDoubleClick: uuid => { return; } }); -export const SubprocessPanel = connect(mapDispatchToProps)(SubprocessPanelRoot); \ No newline at end of file +const mapStateToProps = (state: RootState): SubprocessPanelDataProps => ({ + isAdmin: state.auth.user ? state.auth.user.isAdmin : false +}); + +export const SubprocessPanel = connect(mapStateToProps, mapDispatchToProps)(SubprocessPanelRoot); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 9ec7a215..bb1cf454 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6183,11 +6183,7 @@ just-extend@^4.0.2: resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" integrity sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw== -keycode@^2.1.9: - version "2.2.0" - resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04" - -killable@^1.0.0: +killable@^1.0.0, killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== @@ -6450,29 +6446,14 @@ lodash@4.17.13: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -lodash@^4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -log-symbols@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - loglevel@^1.4.1: version "1.6.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" -loglevelnext@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" - integrity sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A== - dependencies: - es6-symbol "^3.1.1" - object.assign "^4.1.0" +loglevel@^1.6.4: + version "1.6.6" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" + integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== lolex@^4.0.1, lolex@^4.1.0: version "4.2.0" @@ -6972,6 +6953,11 @@ next-tick@~1.0.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + nise@^1.4.10: version "1.5.2" resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.2.tgz#b6d29af10e48b321b307e10e065199338eeb2652" @@ -6983,11 +6969,6 @@ nise@^1.4.10: lolex "^4.1.0" path-to-regexp "^1.7.0" -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - no-case@^2.2.0: version "2.3.2" resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" @@ -9389,7 +9370,7 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-value@2.0.1: +set-value@2.0.1, set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== @@ -9399,15 +9380,6 @@ set-value@2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -10402,9 +10374,10 @@ type-detect@4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-is@~1.6.16: - version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" mime-types "~2.1.24"