Skip to content

Commit 59c72e4

Browse files
committed
frontend/devices: Add last state change
1 parent c513fab commit 59c72e4

File tree

4 files changed

+76
-2
lines changed

4 files changed

+76
-2
lines changed

frontend/src/locales/de.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ export const de ={
6464
"sorting_sequence_asc": "Aufsteigend",
6565
"sorting_sequence_desc": "Absteigend",
6666
"note": "Notiz",
67+
"last_state_change": "Letzte Statusänderung",
68+
"time_just_now": "Gerade eben",
69+
"time_minutes_ago": "vor {{count}}m",
70+
"time_hours_ago": "vor {{count}}h",
71+
"time_days_ago": "vor {{count}}d",
6772
"edit_note_heading": "Notiz bearbeiten",
6873
"edit_note_failed": "Notiz bearbeiten fehlgeschlagen",
6974
"accept": "Bestätigen",

frontend/src/locales/en.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export const en = {
6868
"sorting_sequence_asc": "Ascending",
6969
"sorting_sequence_desc": "Descending",
7070
"note": "Note",
71+
"last_state_change": "Last State Change",
72+
"time_just_now": "Just now",
73+
"time_minutes_ago": "{{count}}m ago",
74+
"time_hours_ago": "{{count}}h ago",
75+
"time_days_ago": "{{count}}d ago",
7176
"edit_note_heading": "Edit note",
7277
"edit_note_failed": "Editing note failed",
7378
"accept": "Accept",

frontend/src/pages/devices.tsx

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface Device {
2121
status: string,
2222
port: number,
2323
valid: boolean,
24+
last_state_change?: number | null,
2425
}
2526

2627
interface StateDevice {
@@ -31,9 +32,10 @@ interface StateDevice {
3132
note: string,
3233
port: number,
3334
valid: boolean,
35+
last_state_change?: number | null,
3436
}
3537

36-
type SortColumn = "name" | "uid" | "status" | "none" | "note";
38+
type SortColumn = "name" | "uid" | "status" | "none" | "note" | "last_state_change";
3739

3840
interface DeviceListState {
3941
devices: StateDevice[],
@@ -60,6 +62,7 @@ export class DeviceList extends Component<{}, DeviceListState> {
6062
port: 0,
6163
valid: true,
6264
note: "",
65+
last_state_change: null,
6366
};
6467
this.state = {
6568
devices: [],
@@ -124,6 +127,7 @@ export class DeviceList extends Component<{}, DeviceListState> {
124127
status: device.status,
125128
port: device.port,
126129
valid: device.valid,
130+
last_state_change: device.last_state_change,
127131
}
128132
stateDevices.push(state_charger);
129133
}
@@ -182,6 +186,31 @@ export class DeviceList extends Component<{}, DeviceListState> {
182186
}
183187
}
184188

189+
formatLastStateChange(t: (key: string, options?: any) => string, timestamp?: number | null): string {
190+
if (!timestamp) {
191+
return "-";
192+
}
193+
194+
const date = new Date(timestamp * 1000);
195+
const now = new Date();
196+
const diffMs = now.getTime() - date.getTime();
197+
const diffMinutes = Math.floor(diffMs / (1000 * 60));
198+
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
199+
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
200+
201+
if (diffMinutes < 1) {
202+
return t("time_just_now");
203+
} else if (diffMinutes < 60) {
204+
return t("time_minutes_ago", { count: diffMinutes });
205+
} else if (diffHours < 24) {
206+
return t("time_hours_ago", { count: diffHours });
207+
} else if (diffDays < 7) {
208+
return t("time_days_ago", { count: diffDays });
209+
} else {
210+
return date.toLocaleDateString();
211+
}
212+
}
213+
185214
connection_possible(device: StateDevice) {
186215
let connection_possible = true;
187216
if (device.status !== "Connected" || device.valid === false) {
@@ -224,6 +253,11 @@ export class DeviceList extends Component<{}, DeviceListState> {
224253
<Col className="text-end">{Base58.int_to_base58(device.uid)}</Col>
225254
</Row>
226255
<hr style="margin-top: 5px;margin-bottom: 5px;"/>
256+
<Row>
257+
<Col xs="auto"><b>{t("last_state_change")}</b></Col>
258+
<Col className="text-end">{this.formatLastStateChange(t, device.last_state_change)}</Col>
259+
</Row>
260+
<hr style="margin-top: 5px;margin-bottom: 5px;"/>
227261
<Row>
228262
<Col xs="auto">
229263
<Row>
@@ -316,7 +350,9 @@ export class DeviceList extends Component<{}, DeviceListState> {
316350
case "uid":
317351
return i18n.t("chargers.charger_id");
318352
case "note":
319-
return i18n.t("chargers.note")
353+
return i18n.t("chargers.note");
354+
case "last_state_change":
355+
return i18n.t("chargers.last_state_change");
320356
default:
321357
return i18n.t("chargers.select_sorting");
322358
}
@@ -344,6 +380,16 @@ export class DeviceList extends Component<{}, DeviceListState> {
344380
case "number":
345381
ret = first - (second as number);
346382
break;
383+
default:
384+
// Handle null/undefined values (like last_state_change)
385+
if (first === null || first === undefined) {
386+
ret = second === null || second === undefined ? 0 : 1;
387+
} else if (second === null || second === undefined) {
388+
ret = -1;
389+
} else {
390+
ret = (first as number) - (second as number);
391+
}
392+
break;
347393
}
348394
if (this.state.sortSequence === "asc") {
349395
return ret;
@@ -395,6 +441,9 @@ export class DeviceList extends Component<{}, DeviceListState> {
395441
{t("remove")}
396442
</Button>
397443
</td>
444+
<td class="align-middle text-center">
445+
{this.formatLastStateChange(t, charger.last_state_change)}
446+
</td>
398447
<td class="align-middle">
399448
<Container fluid>
400449
<Row>
@@ -540,6 +589,18 @@ export class DeviceList extends Component<{}, DeviceListState> {
540589
</th>
541590
<th/>
542591
<th/>
592+
<th onClick={() => this.setSort("last_state_change")}>
593+
<Container fluid>
594+
<Row>
595+
<Col>
596+
{t("last_state_change")}
597+
</Col>
598+
<Col xs="auto">
599+
{this.get_icon("last_state_change")}
600+
</Col>
601+
</Row>
602+
</Container>
603+
</th>
543604
<th onClick={() => this.setSort("note")}>
544605
<Container fluid>
545606
<Row>
@@ -566,6 +627,7 @@ export class DeviceList extends Component<{}, DeviceListState> {
566627
<Dropdown.Item onClick={() => this.setMobileSort("name")}>{t("charger_name")}</Dropdown.Item>
567628
<Dropdown.Item onClick={() => this.setMobileSort("uid")}>{t("charger_id")}</Dropdown.Item>
568629
<Dropdown.Item onClick={() => this.setMobileSort("status")}>{t("status")}</Dropdown.Item>
630+
<Dropdown.Item onClick={() => this.setMobileSort("last_state_change")}>{t("last_state_change")}</Dropdown.Item>
569631
<Dropdown.Item onClick={() => this.setMobileSort("note")}>{t("note")}</Dropdown.Item>
570632
</DropdownButton>
571633
<DropdownButton className="dropdown-btn" title={this.state.sortSequence == "asc" ? t("sorting_sequence_asc") : t("sorting_sequence_desc")}>

frontend/src/schema.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,8 @@ export interface components {
548548
};
549549
GetChargerSchema: {
550550
id: string;
551+
/** Format: int64 */
552+
last_state_change?: number | null;
551553
name: string;
552554
note?: string | null;
553555
/** Format: int32 */

0 commit comments

Comments
 (0)