summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui')
-rw-r--r--opendc-web/opendc-web-ui/src/api/users.js32
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppHeaderUser.js32
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js1
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js3
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js7
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js3
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js25
-rw-r--r--opendc-web/opendc-web-ui/src/data/query.js2
-rw-r--r--opendc-web/opendc-web-ui/src/data/user.js40
-rw-r--r--opendc-web/opendc-web-ui/src/util/available-metrics.js27
10 files changed, 145 insertions, 27 deletions
diff --git a/opendc-web/opendc-web-ui/src/api/users.js b/opendc-web/opendc-web-ui/src/api/users.js
new file mode 100644
index 00000000..12a9be05
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/api/users.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * 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 { request } from './index'
+
+/**
+ * Fetch information about the user from the web server.
+ *
+ * @param auth The authentication object.
+ */
+export function fetchUser(auth) {
+ return request(auth, `users/me`)
+}
diff --git a/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js b/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js
index e271accb..3a73d9ba 100644
--- a/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js
+++ b/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js
@@ -28,26 +28,44 @@ import {
DropdownItem,
DropdownGroup,
Avatar,
+ Progress,
+ ProgressSize,
+ DropdownSeparator,
} from '@patternfly/react-core'
import { useReducer } from 'react'
import { useAuth } from '../auth'
+import useUser from '../data/user'
export default function AppHeaderUser() {
const { logout, user, isAuthenticated, isLoading } = useAuth()
const username = isAuthenticated || isLoading ? user?.name : 'Anonymous'
const avatar = isAuthenticated || isLoading ? user?.picture : '/img/avatar.svg'
+ const { data } = useUser()
+ const simulationBudget = data?.accounting?.simulationTimeBudget ?? 3600
+ const simulationTime = data?.accounting?.simulationTime | 0
+
const [isDropdownOpen, toggleDropdown] = useReducer((t) => !t, false)
const userDropdownItems = [
- <DropdownGroup key="group 2">
- <DropdownItem
- key="group 2 logout"
- isDisabled={!isAuthenticated}
- onClick={() => logout({ returnTo: window.location.origin })}
- >
- Logout
+ <DropdownGroup key="budget" label="Monthly Simulation Budget">
+ <DropdownItem isDisabled>
+ <Progress
+ min={0}
+ max={simulationBudget}
+ value={simulationTime}
+ title={`${Math.ceil(simulationTime / 60)} of ${Math.ceil(simulationBudget / 60)} minutes`}
+ size={ProgressSize.sm}
+ />
</DropdownItem>
</DropdownGroup>,
+ <DropdownSeparator key="separator" />,
+ <DropdownItem
+ key="group 2 logout"
+ isDisabled={!isAuthenticated}
+ onClick={() => logout({ returnTo: window.location.origin })}
+ >
+ Logout
+ </DropdownItem>,
]
const avatarComponent = avatar ? (
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
index 8dc52f7a..64218a0a 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
@@ -64,7 +64,6 @@ function ScenarioTable({ portfolio, status }) {
) : (
'Unknown Topology'
)}
- ,
</Td>
<Td dataLabel="Workload">{`${scenario.workload.trace.name} (${
scenario.workload.samplingFraction * 100
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js
index 6b136120..a0054ef6 100644
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js
+++ b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js
@@ -25,6 +25,7 @@ import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import UnitAddComponent from './UnitAddComponent'
import { addUnit } from '../../../../redux/actions/topology/machine'
+import UnitType from './UnitType'
function UnitAddContainer({ machineId, unitType }) {
const units = useSelector((state) => Object.values(state.topology[unitType]))
@@ -37,7 +38,7 @@ function UnitAddContainer({ machineId, unitType }) {
UnitAddContainer.propTypes = {
machineId: PropTypes.string.isRequired,
- unitType: PropTypes.string.isRequired,
+ unitType: UnitType.isRequired,
}
export default UnitAddContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js
index daa3e7a7..75ab0ad7 100644
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js
@@ -20,9 +20,10 @@ import {
} from '@patternfly/react-core'
import { CubesIcon, InfoIcon, TrashIcon } from '@patternfly/react-icons'
import { ProcessingUnit, StorageUnit } from '../../../../shapes'
+import UnitType from './UnitType'
function UnitInfo({ unit, unitType }) {
- if (unitType === 'cpu' || unitType === 'gpu') {
+ if (unitType === 'cpus' || unitType === 'gpus') {
return (
<DescriptionList>
<DescriptionListGroup>
@@ -60,7 +61,7 @@ function UnitInfo({ unit, unitType }) {
}
UnitInfo.propTypes = {
- unitType: PropTypes.string.isRequired,
+ unitType: UnitType.isRequired,
unit: PropTypes.oneOfType([ProcessingUnit, StorageUnit]).isRequired,
}
@@ -104,7 +105,7 @@ function UnitListComponent({ unitType, units, onDelete }) {
}
UnitListComponent.propTypes = {
- unitType: PropTypes.string.isRequired,
+ unitType: UnitType.isRequired,
units: PropTypes.arrayOf(PropTypes.oneOfType([ProcessingUnit, StorageUnit])).isRequired,
onDelete: PropTypes.func,
}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js
index 25e750c4..bcd4bdcc 100644
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js
+++ b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js
@@ -25,6 +25,7 @@ import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import UnitListComponent from './UnitListComponent'
import { deleteUnit } from '../../../../redux/actions/topology/machine'
+import UnitType from './UnitType'
function UnitListContainer({ machineId, unitType }) {
const dispatch = useDispatch()
@@ -40,7 +41,7 @@ function UnitListContainer({ machineId, unitType }) {
UnitListContainer.propTypes = {
machineId: PropTypes.string.isRequired,
- unitType: PropTypes.string.isRequired,
+ unitType: UnitType.isRequired,
}
export default UnitListContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js
new file mode 100644
index 00000000..b6d7bf8b
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * 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 PropTypes from 'prop-types'
+
+export default PropTypes.oneOf(['cpus', 'gpus', 'memories', 'storages'])
diff --git a/opendc-web/opendc-web-ui/src/data/query.js b/opendc-web/opendc-web-ui/src/data/query.js
index 59eaa684..3e5423b9 100644
--- a/opendc-web/opendc-web-ui/src/data/query.js
+++ b/opendc-web/opendc-web-ui/src/data/query.js
@@ -26,6 +26,7 @@ import { useAuth } from '../auth'
import { configureExperimentClient } from './experiments'
import { configureProjectClient } from './project'
import { configureTopologyClient } from './topology'
+import { configureUserClient } from './user'
let queryClient
@@ -34,6 +35,7 @@ function createQueryClient(auth) {
configureProjectClient(client, auth)
configureExperimentClient(client, auth)
configureTopologyClient(client, auth)
+ configureUserClient(client, auth)
return client
}
diff --git a/opendc-web/opendc-web-ui/src/data/user.js b/opendc-web/opendc-web-ui/src/data/user.js
new file mode 100644
index 00000000..97c0e1e2
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/data/user.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * 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 { useQuery } from 'react-query'
+import { fetchUser } from '../api/users'
+
+/**
+ * Configure the query defaults for the user client.
+ */
+export function configureUserClient(queryClient, auth) {
+ queryClient.setQueryDefaults('user', {
+ queryFn: () => fetchUser(auth),
+ })
+}
+
+/**
+ * Fetch the user data on the server.
+ */
+export default function useUser(options = {}) {
+ return useQuery('user', options)
+}
diff --git a/opendc-web/opendc-web-ui/src/util/available-metrics.js b/opendc-web/opendc-web-ui/src/util/available-metrics.js
index b21ab150..fda6cd4d 100644
--- a/opendc-web/opendc-web-ui/src/util/available-metrics.js
+++ b/opendc-web/opendc-web-ui/src/util/available-metrics.js
@@ -42,10 +42,10 @@ export const METRIC_NAMES_SHORT = {
mean_num_deployed_images: 'Mean Num. Deployed Images Per Host',
max_num_deployed_images: 'Max. Num. Deployed Images Per Host',
total_failure_vm_slices: 'Total Num. Failed VM Slices',
- total_vms_submitted: 'Total Num. VMs Submitted',
- total_vms_queued: 'Max. Num. VMs Queued',
- total_vms_finished: 'Max. Num. VMs Finished',
- total_vms_failed: 'Max. Num. VMs Failed',
+ total_vms_submitted: 'VMs Submitted',
+ total_vms_queued: 'VMs Queued',
+ total_vms_finished: 'VMs Finished',
+ total_vms_failed: 'VMs Failed',
}
export const METRIC_NAMES = {
@@ -58,11 +58,11 @@ export const METRIC_NAMES = {
mean_cpu_demand: 'Mean Host CPU Demand',
mean_num_deployed_images: 'Mean Number of Deployed Images Per Host',
max_num_deployed_images: 'Maximum Number Deployed Images Per Host',
- total_failure_vm_slices: 'Total Number Failed VM Slices',
- total_vms_submitted: 'Total Number VMs Submitted',
- total_vms_queued: 'Maximum Number VMs Queued',
- total_vms_finished: 'Maximum Number VMs Finished',
- total_vms_failed: 'Maximum Number VMs Failed',
+ total_failure_vm_slices: 'Failed VM Slices',
+ total_vms_submitted: 'VMs Submitted',
+ total_vms_queued: 'VMs Queued',
+ total_vms_finished: 'VMs Finished',
+ total_vms_failed: 'VMs Failed',
}
export const METRIC_UNITS = {
@@ -94,9 +94,8 @@ export const METRIC_DESCRIPTIONS = {
mean_num_deployed_images: 'The average number of virtual machines deployed on a host.',
max_num_deployed_images: 'The maximum number of virtual machines deployed at any time.',
total_failure_vm_slices: 'The total amount of CPU clock cycles lost due to failure.',
- total_vms_submitted: 'The total number of virtual machines scheduled by the compute service.',
- total_vms_queued:
- 'The maximum number of virtual machines waiting to be scheduled by the compute service at any point.',
- total_vms_finished: 'The total number of virtual machines that completed successfully.',
- total_vms_failed: 'The total number of virtual machines that failed during execution.',
+ total_vms_submitted: 'The number of virtual machines scheduled by the compute service.',
+ total_vms_queued: 'The number of virtual machines still waiting to be scheduled by the compute service.',
+ total_vms_finished: 'The number of virtual machines that completed.',
+ total_vms_failed: 'The number of virtual machines that could not be scheduled.',
}