import { PropertyValue } from 'models/search-bar';
import {
- Vocabulary,
- getTagKeyLabel,
- getTagValueLabel,
+ Vocabulary,
+ getTagKeyLabel,
+ getTagValueLabel,
} from 'models/vocabulary';
export const formatDate = (isoDate?: string | null, utc: boolean = false) => {
- if (isoDate) {
- const date = new Date(isoDate);
- let text: string;
- if (utc) {
- text = date.toUTCString();
- } else {
- text = date.toLocaleString();
+ if (isoDate) {
+ const date = new Date(isoDate);
+ let text: string;
+ if (utc) {
+ text = date.toUTCString();
+ } else {
+ text = date.toLocaleString();
+ }
+ return text === 'Invalid Date' ? '(none)' : text;
}
- return text === 'Invalid Date' ? '(none)' : text;
- }
- return '-';
+ return '-';
};
export const formatFileSize = (size?: number | string) => {
- if (typeof size === 'number') {
- if (size === 0) {
- return '0 B';
- }
+ if (typeof size === 'number') {
+ if (size === 0) {
+ return '0 B';
+ }
- for (const { base, unit } of FILE_SIZES) {
- if (size >= base) {
- return `${(size / base).toFixed()} ${unit}`;
- }
+ for (const { base, unit } of FILE_SIZES) {
+ if (size >= base) {
+ return `${(size / base).toFixed(base === 1 ? 0 : 1)} ${unit}`;
+ }
+ }
}
- }
- if ((typeof size === 'string' && size === '') || size === undefined) {
- return '-';
- }
- return '0 B';
+ if ((typeof size === 'string' && size === '') || size === undefined) {
+ return '-';
+ }
+ return '0 B';
};
export const formatTime = (time: number, seconds?: boolean) => {
- const minutes = Math.floor((time / (1000 * 60)) % 60).toFixed(0);
- const hours = Math.floor(time / (1000 * 60 * 60)).toFixed(0);
+ const minutes = Math.floor((time / (1000 * 60)) % 60).toFixed(0);
+ const hours = Math.floor(time / (1000 * 60 * 60)).toFixed(0);
- if (seconds) {
- const seconds = Math.floor((time / 1000) % 60).toFixed(0);
- return hours + 'h ' + minutes + 'm ' + seconds + 's';
- }
+ if (seconds) {
+ const seconds = Math.floor((time / 1000) % 60).toFixed(0);
+ return hours + 'h ' + minutes + 'm ' + seconds + 's';
+ }
- return hours + 'h ' + minutes + 'm';
+ return hours + 'h ' + minutes + 'm';
};
export const getTimeDiff = (endTime: string, startTime: string) => {
- return new Date(endTime).getTime() - new Date(startTime).getTime();
+ return new Date(endTime).getTime() - new Date(startTime).getTime();
};
export const formatProgress = (loaded: number, total: number) => {
- const progress = loaded >= 0 && total > 0 ? (loaded * 100) / total : 0;
- return `${progress.toFixed(2)}%`;
+ const progress = loaded >= 0 && total > 0 ? (loaded * 100) / total : 0;
+ return `${progress.toFixed(2)}%`;
};
export function formatUploadSpeed(
- prevLoaded: number,
- loaded: number,
- prevTime: number,
- currentTime: number
+ prevLoaded: number,
+ loaded: number,
+ prevTime: number,
+ currentTime: number
) {
- const speed =
- loaded > prevLoaded && currentTime > prevTime
- ? (loaded - prevLoaded) / (currentTime - prevTime)
- : 0;
+ const speed =
+ loaded > prevLoaded && currentTime > prevTime
+ ? (loaded - prevLoaded) / (currentTime - prevTime)
+ : 0;
- return `${(speed / 1000).toFixed(2)} MB/s`;
+ return `${(speed / 1000).toFixed(2)} MB/s`;
}
const FILE_SIZES = [
- {
- base: 1099511627776,
- unit: 'TB',
- },
- {
- base: 1073741824,
- unit: 'GB',
- },
- {
- base: 1048576,
- unit: 'MB',
- },
- {
- base: 1024,
- unit: 'KB',
- },
- {
- base: 1,
- unit: 'B',
- },
+ {
+ base: 1099511627776,
+ unit: 'TiB',
+ },
+ {
+ base: 1073741824,
+ unit: 'GiB',
+ },
+ {
+ base: 1048576,
+ unit: 'MiB',
+ },
+ {
+ base: 1024,
+ unit: 'KiB',
+ },
+ {
+ base: 1,
+ unit: 'B',
+ },
];
export const formatPropertyValue = (
- pv: PropertyValue,
- vocabulary?: Vocabulary
+ pv: PropertyValue,
+ vocabulary?: Vocabulary
) => {
- if (vocabulary && pv.keyID && pv.valueID) {
- return `${getTagKeyLabel(pv.keyID, vocabulary)}: ${getTagValueLabel(
- pv.keyID,
- pv.valueID!,
- vocabulary
- )}`;
- }
- if (pv.key) {
- return pv.value ? `${pv.key}: ${pv.value}` : pv.key;
- }
- return '';
+ if (vocabulary && pv.keyID && pv.valueID) {
+ return `${getTagKeyLabel(pv.keyID, vocabulary)}: ${getTagValueLabel(
+ pv.keyID,
+ pv.valueID!,
+ vocabulary
+ )}`;
+ }
+ if (pv.key) {
+ return pv.value ? `${pv.key}: ${pv.value}` : pv.key;
+ }
+ return '';
};
export const formatContainerCost = (cost: number): string => {
- const decimalPlaces = 3;
+ 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}`;
- }
+ 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}`;
+ }
};
//
// SPDX-License-Identifier: AGPL-3.0
+export interface CUDAParameters {
+ device_count: number;
+ driver_version: string;
+ hardware_capability: string;
+}
+
export interface RuntimeConstraints {
ram: number;
vcpus: number;
keep_cache_ram?: number;
+ keep_cache_disk?: number;
API: boolean;
+ cuda?: CUDAParameters;
}
return;
};
try {
- const propsOutputs = getRawOutputs(containerRequest);
const filesPromise = services.collectionService.files(containerRequest.logUuid);
const collectionPromise = services.collectionService.get(containerRequest.logUuid);
const [files, collection] = await Promise.all([filesPromise, collectionPromise]);
let nodeData = nodeFile ? await services.collectionService.getFileContents(nodeFile) : undefined;
if (nodeData && (nodeData = JSON.parse(nodeData))) {
dispatch<ProcessPanelAction>(processPanelActions.SET_NODE_INFO({
- nodeInfo: CommonService.mapKeys(camelCase)(nodeData) as NodeInstanceType
+ nodeInfo: nodeData as NodeInstanceType
}));
} else {
dispatch<ProcessPanelAction>(processPanelActions.SET_NODE_INFO(noLog));
}
export interface CUDAFeatures {
- driverVersion: string;
- hardwareCapability: string;
- deviceCount: number;
+ DriverVersion: string;
+ HardwareCapability: string;
+ DeviceCount: number;
}
export interface NodeInstanceType {
- name: string;
- providerType: string;
+ Name: string;
+ ProviderType: string;
VCPUs: number;
RAM: number;
- scratch: number;
- includedScratch: number;
- addedScratch: number;
- price: number;
- preemptible: boolean;
+ Scratch: number;
+ IncludedScratch: number;
+ AddedScratch: number;
+ Price: number;
+ Preemptible: boolean;
CUDA: CUDAFeatures;
};
import { Process } from 'store/processes/process';
import { NodeInstanceType } from 'store/process-panel/process-panel';
import { DefaultView } from 'components/default-view/default-view';
+import { DetailsAttribute } from "components/details-attribute/details-attribute";
+import { formatFileSize } from "common/formatters";
+import { InputCollectionMount } from 'store/processes/processes-actions';
+import { MountKind, TemporaryDirectoryMount } from 'models/mount-types';
interface ProcessResourceCardDataProps {
process: Process;
nodeInfo: NodeInstanceType | null;
}
-type CssRules = "card" | "header" | "title" | "avatar" | "iconHeader" | "content";
+type CssRules = "card" | "header" | "title" | "avatar" | "iconHeader" | "content" | "sectionH3";
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
- card: {},
- header: {},
+ card: {
+ height: '100%'
+ },
+ header: {
+ paddingBottom: "0px"
+ },
title: {},
avatar: {},
iconHeader: {},
- content: {}
+ content: {
+ paddingTop: "0px",
+ maxHeight: `calc(100% - ${theme.spacing.unit * 4.5}px)`,
+ overflow: "auto"
+ },
+ sectionH3: {
+ margin: "0.5em"
+ }
});
type ProcessResourceCardProps = ProcessResourceCardDataProps & WithStyles<CssRules> & MPVPanelProps;
export const ProcessResourceCard = withStyles(styles)(connect()(
({ classes, nodeInfo, doHidePanel, doMaximizePanel, doUnMaximizePanel, panelMaximized, panelName, process, }: ProcessResourceCardProps) => {
- const loading = nodeInfo === null;
+ const loading = false;
+
+ let diskRequest = 0;
+ if (process.container?.mounts) {
+ for (const mnt in process.container.mounts) {
+ const mp = process.container.mounts[mnt];
+ if (mp.kind === MountKind.TEMPORARY_DIRECTORY) {
+ diskRequest += mp.capacity;
+ }
+ }
+ }
return <Card className={classes.card} data-cy="process-resources-card">
<CardHeader
</div>
} />
<CardContent className={classes.content}>
- <>
- {/* raw is undefined until params are loaded */}
- {loading && <Grid container item alignItems='center' justify='center'>
- <CircularProgress />
- </Grid>}
- {/* Once loaded, either raw or params may still be empty
- * Raw when all params are empty
- * Params when raw is provided by containerRequest properties but workflow mount is absent for preview
- */}
- {!loading &&
- <>
- <div>
- stuff
- </div>
- </>}
- {!loading && <Grid container item alignItems='center' justify='center'>
- <DefaultView messages={["No parameters found"]} />
- </Grid>}
- </>
+ <Grid container>
+ <Grid item xs={4}>
+ <h3 className={classes.sectionH3}>Requested resources</h3>
+ <Grid container>
+ <Grid item xs={12}>
+ <DetailsAttribute label="cores" value={process.container?.runtimeConstraints.vcpus} />
+ </Grid>
+ <Grid item xs={12}>
+ <DetailsAttribute label="RAM" value={formatFileSize(process.container?.runtimeConstraints.ram)} />
+ </Grid>
+ <Grid item xs={12}>
+ <DetailsAttribute label="Disk" value={formatFileSize(diskRequest)} />
+ </Grid>
+ <Grid item xs={12}>
+ <DetailsAttribute label="API access" value={process.container?.runtimeConstraints.API.toString()} />
+ </Grid>
+
+ {process.container?.runtimeConstraints.keep_cache_ram &&
+ process.container?.runtimeConstraints.keep_cache_ram > 0 ?
+ <Grid item xs={12}>
+ <DetailsAttribute label="Keep cache (RAM)" value={formatFileSize(process.container?.runtimeConstraints.keep_cache_ram)} />
+ </Grid> : null}
+
+ {process.container?.runtimeConstraints.keep_cache_disk &&
+ process.container?.runtimeConstraints.keep_cache_disk > 0 ?
+ <Grid item xs={12}>
+ <DetailsAttribute label="Keep cache (disk)" value={formatFileSize(process.container?.runtimeConstraints.keep_cache_disk)} />
+ </Grid> : null}
+
+ {process.container?.runtimeConstraints.cuda &&
+ process.container?.runtimeConstraints.cuda.device_count > 0 ?
+ <>
+ <Grid item xs={12}>
+ <DetailsAttribute label="CUDA devices" value={process.container?.runtimeConstraints.cuda.device_count} />
+ </Grid>
+ <Grid item xs={12}>
+ <DetailsAttribute label="CUDA driver version" value={process.container?.runtimeConstraints.cuda.driver_version} />
+ </Grid>
+ <Grid item xs={12}>
+ <DetailsAttribute label="CUDA hardware capability" value={process.container?.runtimeConstraints.cuda.hardware_capability} />
+ </Grid>
+ </> : null}
+ </Grid>
+ </Grid>
+
+
+ <Grid item xs={8}>
+ <h3 className={classes.sectionH3}>Assigned instance type</h3>
+ {nodeInfo === null ? <Grid item xs={8}>
+ No instance type recorded
+ </Grid>
+ :
+ <Grid container>
+ <Grid item xs={6}>
+ <DetailsAttribute label="cores" value={nodeInfo.VCPUs} />
+ </Grid>
+
+ <Grid item xs={6}>
+ <DetailsAttribute label="Provider type" value={nodeInfo.ProviderType} />
+ </Grid>
+
+ <Grid item xs={6}>
+ <DetailsAttribute label="RAM" value={formatFileSize(nodeInfo.RAM)} />
+ </Grid>
+
+ <Grid item xs={6}>
+ <DetailsAttribute label="Price" value={"$" + nodeInfo.Price.toString()} />
+ </Grid>
+
+ <Grid item xs={6}>
+ <DetailsAttribute label="Included scratch disk" value={formatFileSize(nodeInfo.IncludedScratch)} />
+ </Grid>
+
+ <Grid item xs={6}>
+ <DetailsAttribute label="Preemptible" value={nodeInfo.Preemptible.toString()} />
+ </Grid>
+
+ <Grid item xs={6}>
+ <DetailsAttribute label="Added scratch disk" value={formatFileSize(nodeInfo.AddedScratch)} />
+ </Grid>
+
+ {nodeInfo.CUDA.DeviceCount > 0 &&
+ <>
+ <Grid item xs={6}>
+ <DetailsAttribute label="CUDA devices" value={formatFileSize(nodeInfo.CUDA.DeviceCount)} />
+ </Grid>
+ <Grid item xs={6}>
+ <DetailsAttribute label="CUDA driver version" value={formatFileSize(nodeInfo.CUDA.DriverVersion)} />
+ </Grid>
+ <Grid item xs={6}>
+ <DetailsAttribute label="CUDA hardware capability" value={formatFileSize(nodeInfo.CUDA.HardwareCapability)} />
+ </Grid>
+ </>
+ }
+ </Grid>}
+ </Grid>
+ </Grid>
</CardContent>
- </Card>;
+ </Card >;
}
));