Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

[Web Portal] Update home page to support dedicated vc #2995

Merged
merged 5 commits into from
Jun 27, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/webportal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"prop-types": "^15.7.2",
"randomcolor": "^0.5.4",
"raw-loader": "~0.5.1",
"react": "^16.8.3",
"react-dom": "^16.8.3",
Expand Down
6 changes: 5 additions & 1 deletion src/webportal/src/app/home/home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ const Home = () => {
</ResponsiveItem>
<ResponsiveGap />
<ResponsiveItem>
<GpuChart gpuPerNode={gpuPerNode} style={{height: '100%'}} />
<GpuChart
style={{height: '100%'}}
gpuPerNode={gpuPerNode}
virtualClusters={virtualClusters}
/>
</ResponsiveItem>
</ResponsiveFlexBox>
</Stack.Item>
Expand Down
92 changes: 67 additions & 25 deletions src/webportal/src/app/home/home/gpu-chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,68 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import Chart from 'chart.js';
import 'chartjs-plugin-datalabels'; // This plugin registers itself globally
import c from 'classnames';
import {range} from 'lodash';
import PropTypes from 'prop-types';
import {Stack, FontClassNames} from 'office-ui-fabric-react';
import React, {useEffect, useRef} from 'react';
import React, {useEffect, useRef, useMemo} from 'react';

import Card from './card';
import {statusColor} from '../../components/theme';

import t from '../../components/tachyons.scss';
import {getVirtualClusterColor} from './util';

const GpuChart = ({style, gpuPerNode}) => {
const maxVal = Math.max(...Object.values(gpuPerNode));
const data = Array(maxVal).fill(0);
for (const key of Object.keys(gpuPerNode)) {
if (gpuPerNode[key] > 0) {
data[gpuPerNode[key] - 1] += 1;
const GpuChart = ({style, gpuPerNode, virtualClusters}) => {
const maxVal = useMemo(() => {
return Math.max(...Object.values(gpuPerNode));
}, [gpuPerNode]);

const dataset = useMemo(() => {
const processed = {};
const result = [];
// dedicated
for (const [name, vc] of Object.entries(virtualClusters)) {
if (vc.dedicated && vc.nodeList) {
const data = Array(maxVal).fill(0);
for (const node of vc.nodeList) {
if (gpuPerNode[node] > 0) {
data[gpuPerNode[node] - 1] += 1;
processed[node] = true;
}
}
result.push({
backgroundColor: getVirtualClusterColor(name, vc),
hoverBackgroundColor: getVirtualClusterColor(name, vc),
label: `${name} (dedicated)`,
data: data,
});
}
}
}
// shared_vc
const data = Array(maxVal).fill(0);
for (const key of Object.keys(gpuPerNode)) {
if (gpuPerNode[key] > 0 && !processed[key]) {
data[gpuPerNode[key] - 1] += 1;
}
}
result.push({
backgroundColor: getVirtualClusterColor(),
hoverBackgroundColor: getVirtualClusterColor(),
label: 'shared_vc',
data: data,
});
return result;
}, [virtualClusters, gpuPerNode]);

const stackedData = dataset.reduce((prev, x) => {
for (let i = 0; i < maxVal; i++) {
if (x.data[i]) {
prev[i] += x.data[i];
}
}
return prev;
}, Array(maxVal).fill(0));
const height = Math.max(...stackedData) + 1;

const chartRef = useRef(null);

Expand All @@ -44,11 +86,7 @@ const GpuChart = ({style, gpuPerNode}) => {
type: 'bar',
data: {
labels: range(1, maxVal + 1),
datasets: [{
backgroundColor: statusColor.succeeded,
label: 'nodeCount',
data: data,
}],
datasets: dataset,
},
options: {
responsive: true,
Expand All @@ -57,10 +95,17 @@ const GpuChart = ({style, gpuPerNode}) => {
display: false,
},
tooltips: {
enabled: false,
enabled: true,
mode: 'index',
callbacks: {
title: (item, data) => (
`#GPU: ${item[0].label}`
),
},
},
scales: {
xAxes: [{
stacked: true,
scaleLabel: {
display: true,
labelString: '#GPU',
Expand All @@ -70,25 +115,21 @@ const GpuChart = ({style, gpuPerNode}) => {
},
}],
yAxes: [{
stacked: true,
scaleLabel: {
display: true,
labelString: '#Node',
},
ticks: {
max: Math.max(...data) * 1.2,
display: false,
max: height,
display: true,
precision: 0,
},
gridLines: {
display: false,
display: true,
},
}],
},
plugins: {
datalabels: {
anchor: 'end',
align: 'end',
},
},
},
});
});
Expand All @@ -114,6 +155,7 @@ const GpuChart = ({style, gpuPerNode}) => {
GpuChart.propTypes = {
style: PropTypes.object,
gpuPerNode: PropTypes.object.isRequired,
virtualClusters: PropTypes.object.isRequired,
};

export default GpuChart;
29 changes: 29 additions & 0 deletions src/webportal/src/app/home/home/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import randomColor from 'randomcolor';
import {statusColor} from '../../components/theme';

export const DEFAULT_COLOR = statusColor.succeeded;

export function getVirtualClusterColor(name, info) {
if (!info || !info.dedicated) {
return DEFAULT_COLOR;
} else {
return randomColor({seed: name, luminosity: 'bright'});
}
}
36 changes: 14 additions & 22 deletions src/webportal/src/app/home/home/virtual-cluster-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,14 @@ import {Stack, ColorClassNames, FontClassNames, PersonaCoin, getTheme} from 'off
import React from 'react';

import Card from './card';
import {statusColor} from '../../components/theme';
import {getVirtualClusterColor} from './util';

import t from '../../components/tachyons.scss';

const VirtualClusterItem = ({name, info}) => {
const availableGpu = Math.floor(info.resourcesTotal.GPUs - info.resourcesUsed.GPUs);
const percentage = availableGpu / info.resourcesTotal.GPUs;
let color;
if (availableGpu === 0) {
color = statusColor.failed;
} else {
color = statusColor.succeeded;
}
const percentage = info.resourcesTotal.GPUs === 0 ? 0 : availableGpu / info.resourcesTotal.GPUs;
const color = getVirtualClusterColor(name, info);

const {spacing} = getTheme();

Expand Down Expand Up @@ -83,20 +78,17 @@ const VirtualClusterItem = ({name, info}) => {
marginRight: spacing.m,
}}
>
{availableGpu === 0
? <div style={{backgroundColor: color, width: '100%'}}></div>
: (
<div className={c(t.w100, t.h100, t.flex)}>
<div
style={{backgroundColor: color, width: `${percentage * 100}%`}}
></div>
<div
className={c(ColorClassNames.neutralLightBackground)}
style={{width: `${(1 - percentage) * 100}%`}}
></div>
</div>
)
}
{(
<div className={c(t.w100, t.h100, t.flex)}>
<div
style={{backgroundColor: color, width: `${percentage * 100}%`}}
></div>
<div
className={c(ColorClassNames.neutralLightBackground)}
style={{width: `${(1 - percentage) * 100}%`}}
></div>
</div>
)}
</div>
</div>
</Stack.Item>
Expand Down
5 changes: 5 additions & 0 deletions src/webportal/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7216,6 +7216,11 @@ randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
dependencies:
safe-buffer "^5.1.0"

randomcolor@^0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/randomcolor/-/randomcolor-0.5.4.tgz#df615b13f25b89ea58c5f8f72647f0a6f07adcc3"
integrity sha512-nYd4nmTuuwMFzHL6W+UWR5fNERGZeVauho8mrJDUSXdNDbao4rbrUwhuLgKC/j8VCS5+34Ria8CsTDuBjrIrQA==

randomfill@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
Expand Down