Skip to content

Commit

Permalink
Add dashboard poc
Browse files Browse the repository at this point in the history
  • Loading branch information
hvangeffen committed Nov 13, 2024
1 parent b72f5cd commit e9e30fd
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 0 deletions.
24 changes: 24 additions & 0 deletions public/css/map-and-reports.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.dashboard-container {
grid-template-areas:
"map reports"
"map charts";
grid-template-columns: 2fr 1fr;
grid-template-rows:
2fr
3fr;
}

/* Mobile */
@media only screen and (max-width: 768px) and (orientation: portrait) {
.dashboard-container {
grid-template-areas:
"map"
"reports"
"charts";
grid-template-columns: 1fr;
grid-template-rows:
2fr
1fr
3fr;
}
}
8 changes: 8 additions & 0 deletions public/css/ssd-and-charts.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.dashboard-container {
grid-template-areas:
"ssd"
"charts";
grid-template-rows:
2fr
1fr;
}
28 changes: 28 additions & 0 deletions public/css/widgets-and-reports.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.dashboard-container {
grid-template-areas:
"reports map map"
"reports widget-rain widget-snow"
"reports widget-temp widget-wind";
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows:
1fr
1fr
1fr;
}

/* Mobile */
@media only screen and (max-width: 768px) and (orientation: portrait) {
.dashboard-container {
grid-template-areas:
"reports reports"
"widget-rain widget-snow"
"widget-temp widget-wind"
"map map";
grid-template-columns: 1fr 1fr;
grid-template-rows:
1fr
1fr
1fr
1fr;
}
}
80 changes: 80 additions & 0 deletions public/dashboards.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
[
{
"id": "widgets-and-reports",
"title": "Widgets and reports",
"css": "widgets-and-reports.css",
"panels": [
{
"id": "widget-rain"
},
{
"id": "widget-snow"
},
{
"id": "widget-temp"
},
{
"id": "widget-wind"
},
{
"id": "reports",
"reportDisplay": {
"reports": [
{
"moduleInstanceId": "ReportHazardMapRainfallSAWS"
}
]
}
},
{
"id": "map"
}
]
},
{
"id": "map-and-reports",
"title": "Map and reports",
"css": "map-and-reports.css",
"panels": [
{
"id": "map",
"gridDisplaySelection": {
"plotId": "hazard_map_saws"
}
},
{
"id": "reports",
"reportDisplay": {
"reports": [
{
"moduleInstanceId": "ReportHazardMapRainfallSAWS"
}
]
}
},
{
"id": "charts"
}
]
},
{
"id": "ssd-and-charts",
"title": "SSD and charts",
"css": "ssd-and-charts.css",
"panels": [
{
"id": "ssd"
},
{
"id": "charts",
"chartDisplay": {
"charts": [
{
"moduleInstanceId": "ChartHazardMapRainfallSAWS"
}
]
}
}
]
}
]
68 changes: 68 additions & 0 deletions src/components/general/DashboardDisplay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<div class="dashboard-container">
<template v-for="(panel, i) in dashboard.panels">
<section
:style="{
backgroundColor: distinctColorFromIndex(i),
gridArea: panel.id,
}"
>
<h2 class="pa-5">{{ panel.id }}</h2>
</section>
</template>
</div>
</template>

<script setup lang="ts">
import { watch } from "vue";
interface Panel {
id: string;
}
interface Dashboard {
id: string;
title: string;
css: string;
panels: Panel[];
}
interface Props {
dashboard: Dashboard;
}
const props = defineProps<Props>();
function distinctColorFromIndex(index: number) {
return `hsl(${(index * 137) % 360}, 50%, 50%)`;
}
function loadCss(url: string) {
if (!document.querySelector(`link[href="${url}"]`)) {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = url;
document.head.appendChild(link);
}
}
function removeCss(url: string) {
const link = document.querySelector(`link[href="${url}"]`);
if (link) {
link.remove();
}
}
watch(() => props.dashboard.css, (newCss, oldCss) => {
if (oldCss) removeCss(`/css/${oldCss}`);
loadCss(`/css/${newCss}`);
}, { immediate: true });
</script>

<style scoped>
.dashboard-container {
display: grid;
height: 100%;
width: 100%;
}
</style>
13 changes: 13 additions & 0 deletions src/lib/topology/displayTabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface DisplayTab {
| 'data-download'
| 'schematic-status-display'
| 'system-monitor'
| 'dashboard'
id: string
title: string
href?: string
Expand Down Expand Up @@ -75,6 +76,14 @@ const displayTabs: DisplayTab[] = [
icon: 'mdi-view-dashboard',
active: false,
},
{
type: 'dashboard',
id: 'dashboard',
title: 'Dashboard',
to: { name: 'TopologyDashboard' },
icon: 'mdi-view-dashboard',
active: false,
}
]

export function displayTabsForNode(node: TopologyNode, parentNodeId?: string) {
Expand Down Expand Up @@ -110,6 +119,10 @@ export function displayTabsForNode(node: TopologyNode, parentNodeId?: string) {
tab.active = nodeHasSystemMonitor(node)
tab.to.params = { ...params }
break
case 'dashboard':
tab.active = true
tab.to.params = { ...params }
break
}
}
return displayTabs.filter((tab) => tab.active)
Expand Down
8 changes: 8 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const TimeSeriesDisplay = () =>
import('../components/timeseries/TimeSeriesDisplay.vue')
const HtmlDisplayView = () => import('../views/HtmlDisplayView.vue')
const ReportsDisplayView = () => import('../views/ReportsDisplayView.vue')
const DashboardView = () => import('../views/DashboardView.vue')
const Empty = () => import('../views/Empty.vue')

const routesBase: Readonly<RouteRecordRaw[]> = [
Expand Down Expand Up @@ -181,6 +182,13 @@ export const dynamicRoutes: Readonly<RouteRecordRaw[]> = [
props: true,
meta: { sidebar: true },
},
{
path: '/topology/node/:nodeId*/dashboard',
name: 'TopologyDashboard',
component: DashboardView,
props: true,
meta: { sidebar: true },
},
{
path: '/topology/node/:nodeId*/ssd/:panelId?',
name: 'TopologySchematicStatusDisplay',
Expand Down
53 changes: 53 additions & 0 deletions src/views/DashboardView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<div class="dashboard-wrapper">
<v-toolbar>
<v-select
v-model="selectedDashboard"
:items="dashboards"
return-object
hide-details
item-text="title"
item-value="id"
label="Dashboard"
class="px-2"
menu-icon="mdi-chevron-down"
variant="solo-filled"
dense
/>
<v-spacer />
</v-toolbar>
<DashboardDisplay v-if="selectedDashboard" :dashboard="selectedDashboard" />
</div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import DashboardDisplay from '@/components/general/DashboardDisplay.vue';
async function getDashboards() {
const data = await fetch('/dashboards.json')
return data.json()
}
const selectedDashboard = ref();
const dashboards = ref();
onMounted(async () => {
dashboards.value = await getDashboards();
selectedDashboard.value = dashboards.value[0];
});
</script>

<style scoped>
.dashboard-wrapper {
display: grid;
grid-template-rows: auto 1fr;
height: 100%;
width: 100%;
}
.dashboard-body {
height: 100%;
width: 100%;
}
</style>

0 comments on commit e9e30fd

Please sign in to comment.