Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
24 changes: 15 additions & 9 deletions angular-client/src/app/app-nav-bar/app-nav-bar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,7 @@ export class AppNavBarComponent implements OnInit, OnDestroy {
onClick: () => this.navigateTo(appRoutes.graphRoute()),
icon: 'bar_chart'
},
{ id: appRoutes.faultsRoute(), label: 'Fault', onClick: () => this.navigateTo(appRoutes.faultsRoute()), icon: 'error' },
{ id: appRoutes.bmsRoute(), label: 'BMS', onClick: () => this.navigateTo(appRoutes.bmsRoute()), icon: 'action_key' },
{
id: appRoutes.efusesRoute(),
label: 'eFuses',
onClick: () => this.navigateTo(appRoutes.efusesRoute()),
icon: 'electrical_services'
}
{ id: appRoutes.bmsRoute(), label: 'BMS', onClick: () => this.navigateTo(appRoutes.bmsRoute()), icon: 'action_key' }
];

onlyDesktopNavItems: NavItem[] = [...this.mostUsedNavItems];
Expand All @@ -164,8 +157,19 @@ export class AppNavBarComponent implements OnInit, OnDestroy {
}
}

allNavItems: NavItem[] = [this.homeNavItem, ...this.mostUsedNavItems];
navMenuItems: NavItem[] = [
{
id: appRoutes.faultsRoute(),
label: 'Fault',
onClick: () => this.navigateTo(appRoutes.faultsRoute()),
icon: 'error'
},
{
id: appRoutes.efusesRoute(),
label: 'eFuses',
onClick: () => this.navigateTo(appRoutes.efusesRoute()),
icon: 'electrical_services'
},
{
id: appRoutes.mapRoute(),
label: 'Map',
Expand All @@ -192,6 +196,8 @@ export class AppNavBarComponent implements OnInit, OnDestroy {
}
];

allNavItems: NavItem[] = [this.homeNavItem, ...this.mostUsedNavItems, ...this.navMenuItems];

openMenu() {
this.menuRef = this.dialogService.open(NavOptionsMenuComponent, {
showHeader: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,8 @@
.stat-display-list {
display: flex;
align-items: stretch;
justify-content: space-evenly;
min-height: 0;
padding: 0;
gap: 0;
margin-top: -12px;
}

.divider {
width: 2px;
align-self: center;
height: 70px;
background-color: var(--color-divider);
flex-shrink: 0;
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,3 @@
<div class="stat-display-list">
@for (statConfig of this.configs(); track statConfig.key; let last = $last) {
<stat-display
[value]="statConfig.value"
[unit]="statConfig.unit"
[subtitle]="statConfig.subtitle"
[precision]="statConfig.precision ?? 1"
[unitBelow]="statConfig.unitBelow ?? false"
[headerLabel]="statConfig.headerLabel ?? ''"
[headerIcon]="statConfig.headerIcon ?? ''"
>
@if (this.enableWidgets() && statConfig.widget?.type === 'connection-dot') {
<connection-dot-with-message
[getStatusColor]="statConfig.widget?.getStatusColor ?? this.defaultStatusColor"
style="margin-left: 5px"
/>
}
@if (this.enableWidgets() && statConfig.widget?.type === 'thermometer') {
<glance-thermometer
[temperature]="statConfig.widget?.value ?? statConfig.value ?? 0"
[min]="statConfig.widget?.min ?? -15"
[max]="statConfig.widget?.max ?? 30"
/>
}
@if (this.enableWidgets() && statConfig.widget?.type === 'battery-level-indicator') {
<battery-level-indicator [percentage]="statConfig.widget?.value ?? statConfig.value ?? 0"></battery-level-indicator>
}
</stat-display>

@if (!last) {
<div class="divider"></div>
}
}
<ng-content />
</div>
Original file line number Diff line number Diff line change
@@ -1,48 +1,9 @@
import { Component, input } from '@angular/core';
import { BatteryLevelIndicatorComponent } from '../battery-level-indicator/battery-level-indicator.component';
import { ConnectionDotWithMessageComponent } from '../connection-dot-with-message/connection-dot-with-message.component';
import { GlanceThermometerComponent } from '../glance-thermometer/glance-thermometer.component';
import { StatDisplayComponent } from '../stat-display/stat-display.component';

export type StatDisplayWidgetType = 'connection-dot' | 'thermometer' | 'battery-level-indicator';

export interface StatDisplayWidgetConfig {
type: StatDisplayWidgetType;
min?: number;
max?: number;
value?: number;
getStatusColor?: () => string;
}

export interface StatDisplayListConfig {
key: string;
value: number | undefined;
unit: string;
subtitle: string;
precision?: number;
unitBelow?: boolean;
headerLabel?: string;
headerIcon?: string;
widget?: StatDisplayWidgetConfig;
}
import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'stat-display-list',
templateUrl: './stat-display-list.component.html',
styleUrl: './stat-display-list.component.css',
standalone: true,
imports: [
StatDisplayComponent,
ConnectionDotWithMessageComponent,
GlanceThermometerComponent,
BatteryLevelIndicatorComponent
]
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StatDisplayListComponent {
configs = input<StatDisplayListConfig[]>([]);
enableWidgets = input<boolean>(true);

defaultStatusColor = (): string => {
return 'var(--color-text-subtitle)';
};
}
export class StatDisplayListComponent {}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
flex-direction: column;
align-items: center;
justify-content: flex-end;
flex-shrink: 0;
flex: 1 1 0;
min-width: 0;
}

/* ---- Header row (Cell/Chip label) ---- */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
}

<div class="value-row">
<span class="value">{{ formattedValue }}</span>
<span class="value">{{ formattedValue() }}</span>
<span class="unit" [class.unit-below]="unitBelow()">{{ unit() }}</span>
@if (connectionDotStatusColor(); as statusColor) {
<connection-dot-with-message [getStatusColor]="statusColor" style="margin-left: 5px" />
}
<ng-content />
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,30 @@
import { Component, input, OnChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { MatIcon } from '@angular/material/icon';
import { ConnectionDotWithMessageComponent } from '../connection-dot-with-message/connection-dot-with-message.component';

/**
* Lightweight stat display component designed for the At A Glance bar.
* Renders value + unit + subtitle with optional header label and widget slot.
* Uses pure CSS — no nested hstack/vstack/typography wrappers.
*/
@Component({
selector: 'stat-display',
templateUrl: './stat-display.component.html',
styleUrl: './stat-display.component.css',
standalone: true,
imports: [MatIcon],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [MatIcon, ConnectionDotWithMessageComponent],
host: {
'[class.unit-below-mode]': 'unitBelow()'
}
})
export class StatDisplayComponent implements OnChanges {
export class StatDisplayComponent {
value = input<number>();
unit = input<string>('');
subtitle = input<string>('');
precision = input<number>(1);
/** Optional header label (e.g. "Cell: 114 | Chip: A") */
headerLabel = input<string>('');
/** SVG icon name to show in header (registered via matIconRegistry) */
headerIcon = input<string>('');
/** When true, render the unit below the value instead of inline */
unitBelow = input<boolean>(false);
connectionDotStatusColor = input<() => string>();

formattedValue = '-';

ngOnChanges(): void {
formattedValue = computed(() => {
const val = this.value();
this.formattedValue = (val?.toFixed(this.precision()) ?? '-') + (this.unit() === 'C' ? '°' : '');
}
if (!Number.isFinite(val)) return '-';
return val!.toFixed(this.precision()) + (this.unit() === 'C' ? '°' : '');
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
} @else {
<mat-grid-list cols="6" gutterSize="15px" rowHeight="1.5rem" style="margin-top: -20px">
<mat-grid-tile [colspan]="6" rowspan="3">
<bms-header style="width: 100%" [pageTitle]="this.windowSize < 1200 ? 'ACCU' : 'Accumulator'" />
<bms-header style="width: 100%" [pageTitle]="this.windowSize < 1300 ? 'ACCU' : 'Accumulator'" />
</mat-grid-tile>
<mat-grid-tile [colspan]="6" rowspan="3">
<bms-at-a-glance style="height: 100%; width: 100%" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
:host {
display: block;
}

.stat-divider {
width: 2px;
height: 70px;
align-self: center;
background-color: var(--color-divider);
flex-shrink: 0;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,61 @@
<info-panel title="At A Glance" svgIcon="battery_charging_2" padding="6px 20px 14px">
<stat-display-list [configs]="this.statDisplayConfigs" [enableWidgets]="this.enableWidgets"></stat-display-list>
<stat-display-list>
<stat-display
[value]="packVoltage()"
unit="V"
subtitle="Pack Voltage"
[connectionDotStatusColor]="enableWidgets() ? getPackVoltageStatusColor : undefined"
/>
<div class="stat-divider"></div>

<stat-display [value]="packTemp()" unit="C" subtitle="Average Temp." [unitBelow]="true">
@if (enableWidgets()) {
<glance-thermometer [temperature]="packTemp() ?? 0" [min]="-15" [max]="30" />
}
</stat-display>
<div class="stat-divider"></div>

<stat-display [value]="chargeState()" unit="%" subtitle="Charge State" [unitBelow]="true">
@if (enableWidgets()) {
<battery-level-indicator [percentage]="chargeState() ?? 0" />
}
</stat-display>
<div class="stat-divider"></div>

<stat-display [value]="ccl()" unit="A" subtitle="CCL" />
<div class="stat-divider"></div>

<stat-display [value]="dcl()" unit="A" subtitle="DCL" />
<div class="stat-divider"></div>

<stat-display
[value]="highVoltsValue()"
unit="V"
[precision]="3"
subtitle="High Voltage"
headerIcon="battery"
[headerLabel]="highVoltsLabel()"
/>
<div class="stat-divider"></div>

<stat-display
[value]="lowVoltsValue()"
unit="V"
[precision]="3"
subtitle="Low Voltage"
headerIcon="battery"
[headerLabel]="lowVoltsLabel()"
/>
<div class="stat-divider"></div>

<stat-display
[value]="highTempValue()"
unit="C"
[precision]="2"
subtitle="High Temp."
[unitBelow]="true"
headerIcon="battery"
[headerLabel]="highTempLabel()"
/>
</stat-display-list>
</info-panel>
Loading