From d63d24c2ac7a88a83939e9fbaaf589540848ef7a Mon Sep 17 00:00:00 2001 From: Stephen Smith Date: Mon, 31 Oct 2022 13:10:12 -0400 Subject: [PATCH] 19319: Add container / workflow cost details Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- src/common/formatters.test.ts | 22 ++++++++++++++++--- src/common/formatters.ts | 14 ++++++++++++ src/models/container-request.ts | 1 + src/models/container.ts | 1 + .../process-details-attributes.tsx | 20 ++++++++++++++--- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/common/formatters.test.ts b/src/common/formatters.test.ts index 83177e22..04877972 100644 --- a/src/common/formatters.test.ts +++ b/src/common/formatters.test.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0 -import { formatUploadSpeed } from "./formatters"; +import { formatUploadSpeed, formatContainerCost } from "./formatters"; describe('formatUploadSpeed', () => { it('should show speed less than 1MB/s', () => { @@ -25,5 +25,21 @@ describe('formatUploadSpeed', () => { // then expect(result).toBe('5.23 MB/s'); - }); -}); \ No newline at end of file + }); +}); + +describe('formatContainerCost', () => { + it('should correctly round to tenth of a cent', () => { + expect(formatContainerCost(0.0)).toBe('$0'); + expect(formatContainerCost(0.125)).toBe('$0.125'); + expect(formatContainerCost(0.1254)).toBe('$0.125'); + expect(formatContainerCost(0.1255)).toBe('$0.126'); + }); + + it('should round up any smaller value to 0.001', () => { + expect(formatContainerCost(0.0)).toBe('$0'); + expect(formatContainerCost(0.001)).toBe('$0.001'); + expect(formatContainerCost(0.0001)).toBe('$0.001'); + expect(formatContainerCost(0.00001)).toBe('$0.001'); + }); +}); diff --git a/src/common/formatters.ts b/src/common/formatters.ts index 6d0a7e49..b1646512 100644 --- a/src/common/formatters.ts +++ b/src/common/formatters.ts @@ -99,3 +99,17 @@ export const formatPropertyValue = (pv: PropertyValue, vocabulary?: Vocabulary) } return ""; }; + +export const formatContainerCost = (cost: number) => { + const decimalPlaces = 3; + + const factor = Math.pow(10, decimalPlaces); + const rounded = Math.round(cost*factor)/factor; + if (cost > 0 && rounded === 0) { + // Display min value of 0.001 + return `$${1/factor}`; + } else { + // Otherwise use rounded value to proper decimal places + return `$${rounded}`; + } +}; diff --git a/src/models/container-request.ts b/src/models/container-request.ts index 99ec4cf0..dc6bd84f 100644 --- a/src/models/container-request.ts +++ b/src/models/container-request.ts @@ -19,6 +19,7 @@ export interface ContainerRequestResource extends Resource, ResourceWithProperti description: string; state: ContainerRequestState; requestingContainerUuid: string | null; + cumulativeCost: number; containerUuid: string | null; containerCountMax: number; mounts: {[path: string]: MountType}; diff --git a/src/models/container.ts b/src/models/container.ts index d6e0e04a..c86f11ce 100644 --- a/src/models/container.ts +++ b/src/models/container.ts @@ -25,6 +25,7 @@ export interface ContainerResource extends Resource { environment: {}; cwd: string; command: string[]; + cost: number; outputPath: string; mounts: MountType[]; runtimeConstraints: RuntimeConstraints; diff --git a/src/views/process-panel/process-details-attributes.tsx b/src/views/process-panel/process-details-attributes.tsx index 6c20f967..01dafb3e 100644 --- a/src/views/process-panel/process-details-attributes.tsx +++ b/src/views/process-panel/process-details-attributes.tsx @@ -5,7 +5,7 @@ import React from "react"; import { Grid, StyleRulesCallback, withStyles } from "@material-ui/core"; import { Dispatch } from 'redux'; -import { formatDate } from "common/formatters"; +import { formatContainerCost, formatDate } from "common/formatters"; import { resourceLabel } from "common/labels"; import { DetailsAttribute } from "components/details-attribute/details-attribute"; import { ResourceKind } from "models/resource"; @@ -19,6 +19,8 @@ import { navigateToOutput, openWorkflow } from "store/process-panel/process-pane import { ArvadosTheme } from "common/custom-theme"; import { ProcessRuntimeStatus } from "views-components/process-runtime-status/process-runtime-status"; import { getPropertyChip } from "views-components/resource-properties-form/property-chip"; +import { ContainerRequestResource } from "models/container-request"; +import { filterResources } from "store/resources/resources"; type CssRules = 'link' | 'propertyTag'; @@ -37,8 +39,13 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ }); const mapStateToProps = (state: RootState, props: { request: ProcessResource }) => { + const process = getProcess(props.request.uuid)(state.resources); return { - container: getProcess(props.request.uuid)(state.resources)?.container, + container: process?.container, + subprocesses: filterResources((resource: ContainerRequestResource) => + resource.kind === ResourceKind.CONTAINER_REQUEST && + resource.requestingContainerUuid === process?.containerRequest.containerUuid + )(state.resources), }; }; @@ -54,9 +61,10 @@ const mapDispatchToProps = (dispatch: Dispatch): ProcessDetailsAttributesActionP export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })( connect(mapStateToProps, mapDispatchToProps)( - (props: { request: ProcessResource, container?: ContainerResource, twoCol?: boolean, hideProcessPanelRedundantFields?: boolean, classes: Record } & ProcessDetailsAttributesActionProps) => { + (props: { request: ProcessResource, container?: ContainerResource, subprocesses: ContainerRequestResource[], twoCol?: boolean, hideProcessPanelRedundantFields?: boolean, classes: Record } & ProcessDetailsAttributesActionProps) => { const containerRequest = props.request; const container = props.container; + const subprocesses = props.subprocesses; const classes = props.classes; const mdSize = props.twoCol ? 6 : 12; const filteredPropertyKeys = Object.keys(containerRequest.properties) @@ -119,6 +127,12 @@ export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })( } + {container && container.cost && + + } + {containerRequest && containerRequest.cumulativeCost && subprocesses.length > 0 && + + } {containerRequest.properties.template_uuid && props.openWorkflow(containerRequest.properties.template_uuid)}> -- 2.30.2