[ARVADOS-WORKBENCH2] created: 2.4.0-14-ga5750c26
Git user
git at public.arvados.org
Fri Apr 8 15:44:04 UTC 2022
at a5750c261be0991d8ebbe107115c9c5b01236f8d (commit)
commit a5750c261be0991d8ebbe107115c9c5b01236f8d
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Fri Apr 8 11:28:00 2022 -0300
18881: Adds integration test for error & warning runtime status indicators.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/cypress/integration/process.spec.js b/cypress/integration/process.spec.js
index 75c318db..3234f7c4 100644
--- a/cypress/integration/process.spec.js
+++ b/cypress/integration/process.spec.js
@@ -191,4 +191,58 @@ describe('Process tests', function() {
});
});
});
+
+ it('should show runtime status indicators', function() {
+ // Setup running container with runtime_status error & warning messages
+ createContainerRequest(
+ activeUser,
+ 'test_container_request',
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .as('containerRequest')
+ .then(function(containerRequest) {
+ expect(containerRequest.state).to.equal('Committed');
+ expect(containerRequest.container_uuid).not.to.be.equal('');
+
+ cy.getContainer(activeUser.token, containerRequest.container_uuid)
+ .then(function(queuedContainer) {
+ expect(queuedContainer.state).to.be.equal('Queued');
+ });
+ cy.updateContainer(adminUser.token, containerRequest.container_uuid, {
+ state: 'Locked'
+ }).then(function(lockedContainer) {
+ expect(lockedContainer.state).to.be.equal('Locked');
+
+ cy.updateContainer(adminUser.token, lockedContainer.uuid, {
+ state: 'Running',
+ runtime_status: {
+ error: 'Something went wrong',
+ errorDetail: 'Process exited with status 1',
+ warning: 'Free disk space is low',
+ }
+ })
+ .as('runningContainer')
+ .then(function(runningContainer) {
+ expect(runningContainer.state).to.be.equal('Running');
+ expect(runningContainer.runtime_status).to.be.deep.equal({
+ 'error': 'Something went wrong',
+ 'errorDetail': 'Process exited with status 1',
+ 'warning': 'Free disk space is low',
+ });
+ });
+ })
+ });
+ // Test that the UI shows the error and warning messages
+ cy.getAll('@containerRequest', '@runningContainer').then(function([containerRequest]) {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-runtime-status-error]')
+ .should('contain', 'Something went wrong')
+ .and('contain', 'Process exited with status 1');
+ cy.get('[data-cy=process-runtime-status-warning]')
+ .should('contain', 'Free disk space is low')
+ .and('contain', 'No additional warning details available');
+ });
+ });
});
\ No newline at end of file
diff --git a/src/views-components/process-runtime-status/process-runtime-status.tsx b/src/views-components/process-runtime-status/process-runtime-status.tsx
index fdd635d2..26e0459d 100644
--- a/src/views-components/process-runtime-status/process-runtime-status.tsx
+++ b/src/views-components/process-runtime-status/process-runtime-status.tsx
@@ -55,7 +55,7 @@ export const ProcessRuntimeStatus = withStyles(styles)(
({ runtimeStatus, classes }: ProcessRuntimeStatusProps) => {
return <>
{ runtimeStatus?.error &&
- <ExpansionPanel className={classes.error} elevation={0}>
+ <div data-cy='process-runtime-status-error'><ExpansionPanel className={classes.error} elevation={0}>
<ExpansionPanelSummary className={classes.summary} expandIcon={<ExpandMoreIcon />}>
<Typography className={classNames(classes.heading, classes.errorColor)}>
{`Error: ${runtimeStatus.error }`}
@@ -66,10 +66,10 @@ export const ProcessRuntimeStatus = withStyles(styles)(
{runtimeStatus?.errorDetail || 'No additional error details available'}
</Typography>
</ExpansionPanelDetails>
- </ExpansionPanel>
+ </ExpansionPanel></div>
}
{ runtimeStatus?.warning &&
- <ExpansionPanel className={classes.warning} elevation={0}>
+ <div data-cy='process-runtime-status-warning' ><ExpansionPanel className={classes.warning} elevation={0}>
<ExpansionPanelSummary className={classes.summary} expandIcon={<ExpandMoreIcon />}>
<Typography className={classNames(classes.heading, classes.warningColor)}>
{`Warning: ${runtimeStatus.warning }`}
@@ -80,7 +80,7 @@ export const ProcessRuntimeStatus = withStyles(styles)(
{runtimeStatus?.warningDetail || 'No additional warning details available'}
</Typography>
</ExpansionPanelDetails>
- </ExpansionPanel>
+ </ExpansionPanel></div>
}
</>
});
\ No newline at end of file
commit 0d61292f1ce718f5cc252f45d6e220c70246c922
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Fri Apr 8 11:27:30 2022 -0300
18881: Improves & expands resource handling commands.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 5a2428b2..a28308e3 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -135,11 +135,7 @@ Cypress.Commands.add(
Cypress.Commands.add(
"getCollection", (token, uuid) => {
- return cy.doRequest('GET', `/arvados/v1/collections/${uuid}`, null, {}, token)
- .its('body')
- .then(function (theCollection) {
- return theCollection;
- })
+ return cy.getResource(token, 'collections', uuid)
}
)
@@ -160,6 +156,20 @@ Cypress.Commands.add(
}
)
+Cypress.Commands.add(
+ "getContainer", (token, uuid) => {
+ return cy.getResource(token, 'containers', uuid)
+ }
+)
+
+Cypress.Commands.add(
+ "updateContainer", (token, uuid, data) => {
+ return cy.updateResource(token, 'containers', uuid, {
+ container: JSON.stringify(data)
+ })
+ }
+)
+
Cypress.Commands.add(
'createContainerRequest', (token, data) => {
return cy.createResource(token, 'container_requests', {
@@ -212,13 +222,23 @@ Cypress.Commands.add(
}
)
+Cypress.Commands.add(
+ "getResource", (token, suffix, uuid) => {
+ return cy.doRequest('GET', `/arvados/v1/${suffix}/${uuid}`, null, {}, token)
+ .its('body')
+ .then(function (resource) {
+ return resource;
+ })
+ }
+)
+
Cypress.Commands.add(
"createResource", (token, suffix, data) => {
return cy.doRequest('POST', '/arvados/v1/' + suffix, data, null, token, true)
- .its('body').as('resource')
- .then(function () {
- createdResources.push({suffix, uuid: this.resource.uuid});
- return this.resource;
+ .its('body')
+ .then(function (resource) {
+ createdResources.push({suffix, uuid: resource.uuid});
+ return resource;
})
}
)
@@ -226,19 +246,19 @@ Cypress.Commands.add(
Cypress.Commands.add(
"deleteResource", (token, suffix, uuid, failOnStatusCode = true) => {
return cy.doRequest('DELETE', '/arvados/v1/' + suffix + '/' + uuid, null, null, token, false, true, failOnStatusCode)
- .its('body').as('resource')
- .then(function () {
- return this.resource;
+ .its('body')
+ .then(function (resource) {
+ return resource;
})
}
)
Cypress.Commands.add(
"updateResource", (token, suffix, uuid, data) => {
- return cy.doRequest('PUT', '/arvados/v1/' + suffix + '/' + uuid, data, null, token, true)
- .its('body').as('resource')
- .then(function () {
- return this.resource;
+ return cy.doRequest('PATCH', '/arvados/v1/' + suffix + '/' + uuid, data, null, token, true)
+ .its('body')
+ .then(function (resource) {
+ return resource;
})
}
)
commit b812133ea0d9c9a4c52b200731deaba1045478e3
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Thu Apr 7 18:15:33 2022 -0300
18881: Adds runtime_status indicator to the process info card.
Also, improves a bit the layout and reclaims some padding space.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/common/custom-theme.ts b/src/common/custom-theme.ts
index cff18538..b0703237 100644
--- a/src/common/custom-theme.ts
+++ b/src/common/custom-theme.ts
@@ -23,7 +23,10 @@ export interface ArvadosTheme extends Theme {
interface Colors {
green700: string;
+ yellow100: string;
yellow700: string;
+ yellow900: string;
+ red100: string;
red900: string;
blue500: string;
grey500: string;
@@ -43,7 +46,10 @@ export const themeOptions: ArvadosThemeOptions = {
customs: {
colors: {
green700: green["700"],
+ yellow100: yellow["100"],
yellow700: yellow["700"],
+ yellow900: yellow["900"],
+ red100: red["100"],
red900: red['900'],
blue500: blue['500'],
grey500: grey500,
diff --git a/src/views-components/process-runtime-status/process-runtime-status.tsx b/src/views-components/process-runtime-status/process-runtime-status.tsx
new file mode 100644
index 00000000..fdd635d2
--- /dev/null
+++ b/src/views-components/process-runtime-status/process-runtime-status.tsx
@@ -0,0 +1,86 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import {
+ ExpansionPanel,
+ ExpansionPanelDetails,
+ ExpansionPanelSummary,
+ StyleRulesCallback,
+ Typography,
+ withStyles,
+ WithStyles
+} from "@material-ui/core";
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { RuntimeStatus } from "models/runtime-status";
+import { ArvadosTheme } from 'common/custom-theme';
+import classNames from 'classnames';
+
+type CssRules = 'heading' | 'summary' | 'details' | 'error' | 'errorColor' | 'warning' | 'warningColor';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ heading: {
+ fontSize: '1rem',
+ },
+ summary: {
+ paddingLeft: theme.spacing.unit * 1,
+ paddingRight: theme.spacing.unit * 1,
+ },
+ details: {
+ paddingLeft: theme.spacing.unit * 1,
+ paddingRight: theme.spacing.unit * 1,
+ },
+ errorColor: {
+ color: theme.customs.colors.red900,
+ },
+ error: {
+ backgroundColor: theme.customs.colors.red100,
+
+ },
+ warning: {
+ backgroundColor: theme.customs.colors.yellow100,
+ },
+ warningColor: {
+ color: theme.customs.colors.yellow900,
+ },
+});
+export interface ProcessRuntimeStatusDataProps {
+ runtimeStatus: RuntimeStatus | undefined;
+}
+
+type ProcessRuntimeStatusProps = ProcessRuntimeStatusDataProps & WithStyles<CssRules>;
+
+export const ProcessRuntimeStatus = withStyles(styles)(
+ ({ runtimeStatus, classes }: ProcessRuntimeStatusProps) => {
+ return <>
+ { runtimeStatus?.error &&
+ <ExpansionPanel className={classes.error} elevation={0}>
+ <ExpansionPanelSummary className={classes.summary} expandIcon={<ExpandMoreIcon />}>
+ <Typography className={classNames(classes.heading, classes.errorColor)}>
+ {`Error: ${runtimeStatus.error }`}
+ </Typography>
+ </ExpansionPanelSummary>
+ <ExpansionPanelDetails className={classes.details}>
+ <Typography className={classes.errorColor}>
+ {runtimeStatus?.errorDetail || 'No additional error details available'}
+ </Typography>
+ </ExpansionPanelDetails>
+ </ExpansionPanel>
+ }
+ { runtimeStatus?.warning &&
+ <ExpansionPanel className={classes.warning} elevation={0}>
+ <ExpansionPanelSummary className={classes.summary} expandIcon={<ExpandMoreIcon />}>
+ <Typography className={classNames(classes.heading, classes.warningColor)}>
+ {`Warning: ${runtimeStatus.warning }`}
+ </Typography>
+ </ExpansionPanelSummary>
+ <ExpansionPanelDetails className={classes.details}>
+ <Typography className={classes.warningColor}>
+ {runtimeStatus?.warningDetail || 'No additional warning details available'}
+ </Typography>
+ </ExpansionPanelDetails>
+ </ExpansionPanel>
+ }
+ </>
+});
\ No newline at end of file
diff --git a/src/views/process-panel/process-information-card.tsx b/src/views/process-panel/process-information-card.tsx
index fc34a31c..8f16db70 100644
--- a/src/views/process-panel/process-information-card.tsx
+++ b/src/views/process-panel/process-information-card.tsx
@@ -16,6 +16,7 @@ import { formatDate } from 'common/formatters';
import classNames from 'classnames';
import { ContainerState } from 'models/container';
import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
+import { ProcessRuntimeStatus } from 'views-components/process-runtime-status/process-runtime-status';
type CssRules = 'card' | 'iconHeader' | 'label' | 'value' | 'chip' | 'link' | 'content' | 'title' | 'avatar' | 'cancelButton' | 'header';
@@ -37,7 +38,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
},
label: {
display: 'flex',
- justifyContent: 'flex-end',
+ justifyContent: 'flex-start',
fontSize: '0.875rem',
marginRight: theme.spacing.unit * 3,
paddingRight: theme.spacing.unit
@@ -61,8 +62,11 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
borderRadius: theme.spacing.unit * 0.625,
},
content: {
+ paddingTop: '0px',
+ paddingLeft: theme.spacing.unit * 1,
+ paddingRight: theme.spacing.unit * 1,
'&:last-child': {
- paddingBottom: theme.spacing.unit * 2,
+ paddingBottom: theme.spacing.unit * 1,
}
},
title: {
@@ -123,27 +127,28 @@ export const ProcessInformationCard = withStyles(styles, { withTheme: true })(
</Tooltip> }
</div>
}
- title={
- <Tooltip title={process.containerRequest.name} placement="bottom-start">
- <Typography noWrap variant='h6' color='inherit'>
- {process.containerRequest.name}
- </Typography>
- </Tooltip>
+ title={ !!process.containerRequest.name &&
+ <Typography noWrap variant='h6' color='inherit'>
+ {process.containerRequest.name}
+ </Typography>
}
subheader={
- <Tooltip title={getDescription(process)} placement="bottom-start">
- <Typography noWrap variant='body1' color='inherit'>
- {getDescription(process)}
- </Typography>
- </Tooltip>} />
+ <Typography noWrap variant='body1' color='inherit'>
+ {process.containerRequest.description}
+ </Typography>
+ }
+ />
<CardContent className={classes.content}>
<Grid container>
+ <Grid item xs={12}>
+ <ProcessRuntimeStatus runtimeStatus={process.container?.runtimeStatus} />
+ </Grid>
<Grid item xs={6}>
<DetailsAttribute classLabel={classes.label} classValue={classes.value}
- label='From'
+ label='Started at'
value={startedAt} />
<DetailsAttribute classLabel={classes.label} classValue={classes.value}
- label='To'
+ label='Finished at'
value={finishedAt} />
{process.containerRequest.properties.workflowUuid &&
<span onClick={() => openWorkflow(process.containerRequest.properties.workflowUuid)}>
@@ -164,6 +169,3 @@ export const ProcessInformationCard = withStyles(styles, { withTheme: true })(
</Card>;
}
);
-
-const getDescription = (process: Process) =>
- process.containerRequest.description || '(no-description)';
commit 5de4c8e78a96433482063a53dfce0056902da654
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Wed Apr 6 18:08:27 2022 -0300
18881: Improves process filtering by status. Adds tests.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/store/processes/process.ts b/src/store/processes/process.ts
index 37cdd2b3..b72a0c2b 100644
--- a/src/store/processes/process.ts
+++ b/src/store/processes/process.ts
@@ -92,36 +92,40 @@ export const getProcessStatusColor = (status: string, { customs }: ArvadosTheme)
export const getProcessStatus = ({ containerRequest, container }: Process): ProcessStatus => {
switch (true) {
+ case containerRequest.state === ContainerRequestState.FINAL &&
+ container?.state !== ContainerState.COMPLETE:
+ // Request was finalized before its container started (or the
+ // container was cancelled)
+ return ProcessStatus.CANCELLED;
+
case containerRequest.state === ContainerRequestState.UNCOMMITTED:
return ProcessStatus.DRAFT;
- case containerRequest.priority === 0:
- return ProcessStatus.ONHOLD;
-
- case container && container.state === ContainerState.COMPLETE && container.exitCode === 0:
- return ProcessStatus.COMPLETED;
+ case container?.state === ContainerState.COMPLETE:
+ if (container?.exitCode === 0) {
+ return ProcessStatus.COMPLETED;
+ }
+ return ProcessStatus.FAILED;
- case container && container.state === ContainerState.CANCELLED:
+ case container?.state === ContainerState.CANCELLED:
return ProcessStatus.CANCELLED;
- case container && (container.state === ContainerState.QUEUED ||
- container.state === ContainerState.LOCKED):
+ case container?.state === ContainerState.QUEUED ||
+ container?.state === ContainerState.LOCKED:
+ if (containerRequest.priority === 0) {
+ return ProcessStatus.ONHOLD;
+ }
return ProcessStatus.QUEUED;
- case container && container.state === ContainerState.RUNNING &&
- !!container.runtimeStatus.error:
- return ProcessStatus.FAILING;
-
- case container && container.state === ContainerState.RUNNING &&
- !!container.runtimeStatus.warning:
- return ProcessStatus.WARNING;
-
- case container && container.state === ContainerState.RUNNING:
+ case container?.state === ContainerState.RUNNING:
+ if (!!container?.runtimeStatus.error) {
+ return ProcessStatus.FAILING;
+ }
+ if (!!container?.runtimeStatus.warning) {
+ return ProcessStatus.WARNING;
+ }
return ProcessStatus.RUNNING;
- case container && container.state === ContainerState.COMPLETE && container.exitCode !== 0:
- return ProcessStatus.FAILED;
-
default:
return ProcessStatus.UNKNOWN;
}
diff --git a/src/store/project-panel/project-panel-middleware-service.ts b/src/store/project-panel/project-panel-middleware-service.ts
index be569b49..ccfa4fff 100644
--- a/src/store/project-panel/project-panel-middleware-service.ts
+++ b/src/store/project-panel/project-panel-middleware-service.ts
@@ -17,7 +17,11 @@ import { OrderBuilder, OrderDirection } from "services/api/order-builder";
import { FilterBuilder, joinFilters } from "services/api/filter-builder";
import { GroupContentsResource, GroupContentsResourcePrefix } from "services/groups-service/groups-service";
import { updateFavorites } from "store/favorites/favorites-actions";
-import { IS_PROJECT_PANEL_TRASHED, projectPanelActions, getProjectPanelCurrentUuid } from 'store/project-panel/project-panel-action';
+import {
+ IS_PROJECT_PANEL_TRASHED,
+ projectPanelActions,
+ getProjectPanelCurrentUuid
+} from 'store/project-panel/project-panel-action';
import { Dispatch, MiddlewareAPI } from "redux";
import { ProjectResource } from "models/project";
import { updateResources } from "store/resources/resources-actions";
@@ -29,7 +33,10 @@ import { ListResults } from 'services/common-service/common-service';
import { loadContainers } from 'store/processes/processes-actions';
import { ResourceKind } from 'models/resource';
import { getSortColumn } from "store/data-explorer/data-explorer-reducer";
-import { serializeResourceTypeFilters, ProcessStatusFilter } from 'store/resource-type-filters/resource-type-filters';
+import {
+ serializeResourceTypeFilters,
+ buildProcessStatusFilters
+} from 'store/resource-type-filters/resource-type-filters';
import { updatePublicFavorites } from 'store/public-favorites/public-favorites-actions';
export class ProjectPanelMiddlewareService extends DataExplorerMiddlewareService {
@@ -116,27 +123,10 @@ export const getFilters = (dataExplorer: DataExplorer) => {
.getFilters();
// Filter by container status
- const fb = new FilterBuilder();
- switch (activeStatusFilter) {
- case ProcessStatusFilter.COMPLETED: {
- fb.addEqual('container.state', 'Complete', GroupContentsResourcePrefix.PROCESS);
- fb.addEqual('container.exit_code', '0', GroupContentsResourcePrefix.PROCESS);
- break;
- }
- case ProcessStatusFilter.FAILED: {
- fb.addEqual('container.state', 'Complete', GroupContentsResourcePrefix.PROCESS);
- fb.addDistinct('container.exit_code', '0', GroupContentsResourcePrefix.PROCESS);
- break;
- }
- case ProcessStatusFilter.CANCELLED:
- case ProcessStatusFilter.LOCKED:
- case ProcessStatusFilter.QUEUED:
- case ProcessStatusFilter.RUNNING: {
- fb.addEqual('container.state', activeStatusFilter, GroupContentsResourcePrefix.PROCESS);
- break;
- }
- }
- const statusFilters = fb.getFilters();
+ const statusFilters = buildProcessStatusFilters(
+ new FilterBuilder(),
+ activeStatusFilter || '',
+ GroupContentsResourcePrefix.PROCESS).getFilters();
return joinFilters(
statusFilters,
diff --git a/src/store/resource-type-filters/resource-type-filters.test.ts b/src/store/resource-type-filters/resource-type-filters.test.ts
index 71b00b2e..698515bd 100644
--- a/src/store/resource-type-filters/resource-type-filters.test.ts
+++ b/src/store/resource-type-filters/resource-type-filters.test.ts
@@ -2,10 +2,29 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { getInitialResourceTypeFilters, serializeResourceTypeFilters, ObjectTypeFilter, CollectionTypeFilter, ProcessTypeFilter, GroupTypeFilter } from './resource-type-filters';
+import { getInitialResourceTypeFilters, serializeResourceTypeFilters, ObjectTypeFilter, CollectionTypeFilter, ProcessTypeFilter, GroupTypeFilter, buildProcessStatusFilters, ProcessStatusFilter } from './resource-type-filters';
import { ResourceKind } from 'models/resource';
import { deselectNode } from 'models/tree';
import { pipe } from 'lodash/fp';
+import { FilterBuilder } from 'services/api/filter-builder';
+
+describe("buildProcessStatusFilters", () => {
+ [
+ [ProcessStatusFilter.ALL, ""],
+ [ProcessStatusFilter.ONHOLD, `["state","!=","Final"],["priority","=","0"],["container.state","in",["Queued","Locked"]]`],
+ [ProcessStatusFilter.COMPLETED, `["container.state","=","Complete"],["container.exit_code","=","0"]`],
+ [ProcessStatusFilter.FAILED, `["container.state","=","Complete"],["container.exit_code","!=","0"]`],
+ [ProcessStatusFilter.QUEUED, `["container.state","=","Queued"],["priority","!=","0"]`],
+ [ProcessStatusFilter.CANCELLED, `["container.state","=","Cancelled"]`],
+ [ProcessStatusFilter.RUNNING, `["container.state","=","Running"]`],
+ ].forEach(([status, expected]) => {
+ it(`can filter "${status}" processes`, () => {
+ const filters = buildProcessStatusFilters(new FilterBuilder(), status);
+ expect(filters.getFilters())
+ .toEqual(expected);
+ })
+ });
+});
describe("serializeResourceTypeFilters", () => {
it("should serialize all filters", () => {
diff --git a/src/store/resource-type-filters/resource-type-filters.ts b/src/store/resource-type-filters/resource-type-filters.ts
index e42a16d8..a39807d5 100644
--- a/src/store/resource-type-filters/resource-type-filters.ts
+++ b/src/store/resource-type-filters/resource-type-filters.ts
@@ -11,6 +11,7 @@ import { getSelectedNodes } from 'models/tree';
import { CollectionType } from 'models/collection';
import { GroupContentsResourcePrefix } from 'services/groups-service/groups-service';
import { ContainerState } from 'models/container';
+import { ContainerRequestState } from 'models/container-request';
export enum ProcessStatusFilter {
ALL = 'All',
@@ -18,7 +19,7 @@ export enum ProcessStatusFilter {
FAILED = 'Failed',
COMPLETED = 'Completed',
CANCELLED = 'Cancelled',
- LOCKED = 'Locked',
+ ONHOLD = 'On hold',
QUEUED = 'Queued'
}
@@ -95,12 +96,12 @@ export const getInitialProcessStatusFilters = pipe(
(): DataTableFilters => createTree<DataTableFilterItem>(),
pipe(
initFilter(ProcessStatusFilter.ALL, '', true),
+ initFilter(ProcessStatusFilter.ONHOLD, '', false),
+ initFilter(ProcessStatusFilter.QUEUED, '', false),
initFilter(ProcessStatusFilter.RUNNING, '', false),
- initFilter(ProcessStatusFilter.FAILED, '', false),
initFilter(ProcessStatusFilter.COMPLETED, '', false),
initFilter(ProcessStatusFilter.CANCELLED, '', false),
- initFilter(ProcessStatusFilter.QUEUED, '', false),
- initFilter(ProcessStatusFilter.LOCKED, '', false),
+ initFilter(ProcessStatusFilter.FAILED, '', false),
),
);
@@ -272,27 +273,32 @@ export const serializeSimpleObjectTypeFilters = (filters: Tree<DataTableFilterIt
.map(objectTypeToResourceKind);
};
-export const buildProcessStatusFilters = ( fb:FilterBuilder, activeStatusFilter:string ): FilterBuilder => {
+export const buildProcessStatusFilters = ( fb: FilterBuilder, activeStatusFilter: string, resourcePrefix?: string ): FilterBuilder => {
switch (activeStatusFilter) {
+ case ProcessStatusFilter.ONHOLD: {
+ fb.addDistinct('state', ContainerRequestState.FINAL, resourcePrefix);
+ fb.addEqual('priority', '0', resourcePrefix);
+ fb.addIn('container.state', [ContainerState.QUEUED, ContainerState.LOCKED], resourcePrefix);
+ break;
+ }
case ProcessStatusFilter.COMPLETED: {
- fb.addEqual('container.state', ContainerState.COMPLETE);
- fb.addEqual('container.exit_code', '0');
+ fb.addEqual('container.state', ContainerState.COMPLETE, resourcePrefix);
+ fb.addEqual('container.exit_code', '0', resourcePrefix);
break;
}
case ProcessStatusFilter.FAILED: {
- fb.addEqual('container.state', ContainerState.COMPLETE);
- fb.addDistinct('container.exit_code', '0');
+ fb.addEqual('container.state', ContainerState.COMPLETE, resourcePrefix);
+ fb.addDistinct('container.exit_code', '0', resourcePrefix);
break;
}
case ProcessStatusFilter.QUEUED: {
- fb.addEqual('container.state', ContainerState.QUEUED);
- fb.addDistinct('container.priority', '0');
+ fb.addEqual('container.state', ContainerState.QUEUED, resourcePrefix);
+ fb.addDistinct('priority', '0', resourcePrefix);
break;
}
case ProcessStatusFilter.CANCELLED:
- case ProcessStatusFilter.LOCKED:
case ProcessStatusFilter.RUNNING: {
- fb.addEqual('container.state', activeStatusFilter);
+ fb.addEqual('container.state', activeStatusFilter, resourcePrefix);
break;
}
}
commit dec2560060035f165662cff34b3a8916927a7ee6
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Fri Apr 1 12:20:40 2022 -0300
18881: Fixes process state indicator, with tests.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/common/custom-theme.ts b/src/common/custom-theme.ts
index 74dee7f6..cff18538 100644
--- a/src/common/custom-theme.ts
+++ b/src/common/custom-theme.ts
@@ -26,10 +26,12 @@ interface Colors {
yellow700: string;
red900: string;
blue500: string;
+ grey500: string;
purple: string;
}
const arvadosPurple = '#361336';
+const grey500 = grey["500"];
const grey600 = grey["600"];
const grey700 = grey["700"];
const grey900 = grey["900"];
@@ -44,6 +46,7 @@ export const themeOptions: ArvadosThemeOptions = {
yellow700: yellow["700"],
red900: red['900'],
blue500: blue['500'],
+ grey500: grey500,
purple: arvadosPurple
}
},
diff --git a/src/store/process-panel/process-panel-actions.ts b/src/store/process-panel/process-panel-actions.ts
index 962f5dfc..e77c300d 100644
--- a/src/store/process-panel/process-panel-actions.ts
+++ b/src/store/process-panel/process-panel-actions.ts
@@ -56,6 +56,8 @@ export const initProcessPanelFilters = processPanelActions.SET_PROCESS_PANEL_FIL
ProcessStatus.COMPLETED,
ProcessStatus.FAILED,
ProcessStatus.RUNNING,
- ProcessStatus.LOCKED,
+ ProcessStatus.ONHOLD,
+ ProcessStatus.FAILING,
+ ProcessStatus.WARNING,
ProcessStatus.CANCELLED
]);
diff --git a/src/store/processes/process.ts b/src/store/processes/process.ts
index 60505be0..37cdd2b3 100644
--- a/src/store/processes/process.ts
+++ b/src/store/processes/process.ts
@@ -19,10 +19,12 @@ export enum ProcessStatus {
CANCELLED = 'Cancelled',
COMPLETED = 'Completed',
DRAFT = 'Draft',
+ FAILING = 'Failing',
FAILED = 'Failed',
- LOCKED = 'Locked',
+ ONHOLD = 'On hold',
QUEUED = 'Queued',
RUNNING = 'Running',
+ WARNING = 'Warning',
UNKNOWN = 'Unknown',
}
@@ -71,17 +73,20 @@ export const getProcessRuntime = ({ container }: Process) => {
}
};
-export const getProcessStatusColor = (status: string, { customs, palette }: ArvadosTheme) => {
+export const getProcessStatusColor = (status: string, { customs }: ArvadosTheme) => {
switch (status) {
case ProcessStatus.RUNNING:
return customs.colors.blue500;
case ProcessStatus.COMPLETED:
return customs.colors.green700;
+ case ProcessStatus.WARNING:
+ return customs.colors.yellow700;
+ case ProcessStatus.FAILING:
case ProcessStatus.CANCELLED:
case ProcessStatus.FAILED:
return customs.colors.red900;
default:
- return palette.grey["500"];
+ return customs.colors.grey500;
}
};
@@ -90,18 +95,26 @@ export const getProcessStatus = ({ containerRequest, container }: Process): Proc
case containerRequest.state === ContainerRequestState.UNCOMMITTED:
return ProcessStatus.DRAFT;
+ case containerRequest.priority === 0:
+ return ProcessStatus.ONHOLD;
+
case container && container.state === ContainerState.COMPLETE && container.exitCode === 0:
return ProcessStatus.COMPLETED;
- case containerRequest.priority === 0:
case container && container.state === ContainerState.CANCELLED:
return ProcessStatus.CANCELLED;
- case container && container.state === ContainerState.QUEUED:
+ case container && (container.state === ContainerState.QUEUED ||
+ container.state === ContainerState.LOCKED):
return ProcessStatus.QUEUED;
- case container && container.state === ContainerState.LOCKED:
- return ProcessStatus.LOCKED;
+ case container && container.state === ContainerState.RUNNING &&
+ !!container.runtimeStatus.error:
+ return ProcessStatus.FAILING;
+
+ case container && container.state === ContainerState.RUNNING &&
+ !!container.runtimeStatus.warning:
+ return ProcessStatus.WARNING;
case container && container.state === ContainerState.RUNNING:
return ProcessStatus.RUNNING;
diff --git a/src/views-components/data-explorer/renderers.test.tsx b/src/views-components/data-explorer/renderers.test.tsx
index f0efdf74..fc9325bd 100644
--- a/src/views-components/data-explorer/renderers.test.tsx
+++ b/src/views-components/data-explorer/renderers.test.tsx
@@ -4,11 +4,14 @@
import React from 'react';
import { mount, configure } from 'enzyme';
-import { ResourceFileSize } from './renderers';
+import { ProcessStatus, ResourceFileSize } from './renderers';
import Adapter from "enzyme-adapter-react-16";
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store'
import { ResourceKind } from '../../models/resource';
+import { ContainerRequestState as CR } from '../../models/container-request';
+import { ContainerState as C } from '../../models/container';
+import { ProcessStatus as PS } from '../../store/processes/process';
const middlewares = [];
const mockStore = configureMockStore(middlewares);
@@ -18,6 +21,65 @@ configure({ adapter: new Adapter() });
describe('renderers', () => {
let props = null;
+ describe('ProcessStatus', () => {
+ props = {
+ uuid: 'zzzzz-xvhdp-zzzzzzzzzzzzzzz',
+ theme: {
+ customs: {
+ colors: {
+ // Color values are arbitrary, but they should be
+ // representative of the colors used in the UI.
+ blue500: 'rgb(0, 0, 255)',
+ green700: 'rgb(0, 255, 0)',
+ yellow700: 'rgb(255, 255, 0)',
+ red900: 'rgb(255, 0, 0)',
+ grey500: 'rgb(128, 128, 128)',
+ }
+ }
+ },
+ };
+
+ [
+ // CR Status ; Priority ; C Status ; Exit Code ; C RuntimeStatus ; Expected label ; Expected Color
+ [CR.COMMITTED, 1, C.RUNNING, null, {}, PS.RUNNING, props.theme.customs.colors.blue500],
+ [CR.COMMITTED, 1, C.RUNNING, null, {error: 'whoops'}, PS.FAILING, props.theme.customs.colors.red900],
+ [CR.COMMITTED, 1, C.RUNNING, null, {warning: 'watch out!'}, PS.WARNING, props.theme.customs.colors.yellow700],
+ [CR.FINAL, 1, C.CANCELLED, null, {}, PS.CANCELLED, props.theme.customs.colors.red900],
+ [CR.FINAL, 1, C.COMPLETE, 137, {}, PS.FAILED, props.theme.customs.colors.red900],
+ [CR.FINAL, 1, C.COMPLETE, 0, {}, PS.COMPLETED, props.theme.customs.colors.green700],
+ [CR.COMMITTED, 0, C.LOCKED, null, {}, PS.ONHOLD, props.theme.customs.colors.grey500],
+ [CR.COMMITTED, 0, C.QUEUED, null, {}, PS.ONHOLD, props.theme.customs.colors.grey500],
+ [CR.COMMITTED, 1, C.LOCKED, null, {}, PS.QUEUED, props.theme.customs.colors.grey500],
+ [CR.COMMITTED, 1, C.QUEUED, null, {}, PS.QUEUED, props.theme.customs.colors.grey500],
+ ].forEach(([crState, crPrio, cState, exitCode, rs, eLabel, eColor]) => {
+ it(`should render the state label '${eLabel}' and color '${eColor}' for CR state=${crState}, priority=${crPrio}, C state=${cState}, exitCode=${exitCode} and RuntimeStatus=${JSON.stringify(rs)}`, () => {
+ const containerUuid = 'zzzzz-dz642-zzzzzzzzzzzzzzz';
+ const store = mockStore({ resources: {
+ [props.uuid]: {
+ kind: ResourceKind.CONTAINER_REQUEST,
+ state: crState,
+ containerUuid: containerUuid,
+ priority: crPrio,
+ },
+ [containerUuid]: {
+ kind: ResourceKind.CONTAINER,
+ state: cState,
+ runtimeStatus: rs,
+ exitCode: exitCode,
+ },
+ }});
+
+ const wrapper = mount(<Provider store={store}>
+ <ProcessStatus {...props} />
+ </Provider>);
+
+ expect(wrapper.text()).toEqual(eLabel);
+ expect(getComputedStyle(wrapper.getDOMNode())
+ .getPropertyValue('color')).toEqual(eColor);
+ });
+ })
+ });
+
describe('ResourceFileSize', () => {
beforeEach(() => {
props = {
commit 890f88cf8828ae1d8dde8cb8c104226837187353
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date: Fri Apr 1 12:10:32 2022 -0300
18881: Adds runtime_status support on container model.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>
diff --git a/src/models/container.ts b/src/models/container.ts
index e931c4bf..127c2508 100644
--- a/src/models/container.ts
+++ b/src/models/container.ts
@@ -6,6 +6,7 @@ import { Resource, ResourceKind } from "./resource";
import { MountType } from 'models/mount-types';
import { RuntimeConstraints } from "models/runtime-constraints";
import { SchedulingParameters } from './scheduling-parameters';
+import { RuntimeStatus } from "./runtime-status";
export enum ContainerState {
QUEUED = 'Queued',
@@ -27,6 +28,7 @@ export interface ContainerResource extends Resource {
outputPath: string;
mounts: MountType[];
runtimeConstraints: RuntimeConstraints;
+ runtimeStatus: RuntimeStatus;
schedulingParameters: SchedulingParameters;
output: string | null;
containerImage: string;
diff --git a/src/models/runtime-status.ts b/src/models/runtime-status.ts
new file mode 100644
index 00000000..c659930d
--- /dev/null
+++ b/src/models/runtime-status.ts
@@ -0,0 +1,11 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export interface RuntimeStatus {
+ error?: string;
+ warning?: string;
+ activity?: string;
+ errorDetail?: string;
+ warningDetail?: string;
+}
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list