Added live refresh to admin UI

- Added lastLogin UI
- Added operational time
This commit is contained in:
Max W. 2024-05-30 20:40:58 +02:00
parent 017ef0afca
commit dbb53ca9da
6 changed files with 121 additions and 6 deletions

View File

@ -22,7 +22,7 @@
<div class="shadow stats bg-white"> <div class="shadow stats bg-white">
<div class="stat"> <div class="stat">
<div class="stat-title">Operational For</div> <div class="stat-title">Operational For</div>
<div class="stat-value">2 Years</div> <div class="stat-value">{{ statistics.applicationOnlineTime | duration }}</div>
<div class="stat-desc">Since launch</div> <div class="stat-desc">Since launch</div>
</div> </div>
</div> </div>
@ -38,7 +38,7 @@
<div class="shadow stats bg-white"> <div class="shadow stats bg-white">
<div class="stat"> <div class="stat">
<div class="stat-title">Last Admin Login</div> <div class="stat-title">Last Admin Login</div>
<div class="stat-value">2 days ago</div> <div class="stat-value">{{ statistics.lastUserLogin | relativeTime }}</div>
<div class="stat-desc">Most recent login</div> <div class="stat-desc">Most recent login</div>
</div> </div>
</div> </div>

View File

@ -6,6 +6,8 @@ import {DevelopmentStore} from "../../store/DevelopmentStore";
import {AuthStore} from "../../store/authStore"; import {AuthStore} from "../../store/authStore";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {FormatFileSizePipePipe} from "../format-file-size-pipe.pipe"; import {FormatFileSizePipePipe} from "../format-file-size-pipe.pipe";
import {DurationPipe} from "../duration.pipe";
import {RelativeTimePipe} from "../relative-time.pipe";
@Component({ @Component({
selector: 'app-adminui', selector: 'app-adminui',
@ -14,7 +16,9 @@ import {FormatFileSizePipePipe} from "../format-file-size-pipe.pipe";
DatePipe, DatePipe,
DecimalPipe, DecimalPipe,
NgForOf, NgForOf,
FormatFileSizePipePipe FormatFileSizePipePipe,
DurationPipe,
RelativeTimePipe
], ],
templateUrl: './adminui.component.html', templateUrl: './adminui.component.html',
styleUrl: './adminui.component.scss' styleUrl: './adminui.component.scss'
@ -25,9 +29,12 @@ export class AdminuiComponent {
expiredFileUploads: any[] = []; expiredFileUploads: any[] = [];
totalFileSizeOnDisk: number = 0; totalFileSizeOnDisk: number = 0;
totalFileDownloads = 0; totalFileDownloads = 0;
statistics: any = {};
constructor(private developmentStore: DevelopmentStore, private authStore: AuthStore, private router: Router) { constructor(private developmentStore: DevelopmentStore, private authStore: AuthStore, private router: Router) {
this.verifyToken(); setInterval(() => {
this.verifyToken();
}, 1000);
} }
async verifyToken() { async verifyToken() {
@ -38,12 +45,14 @@ export class AdminuiComponent {
} }
await this.fetchFileUploads(); await this.fetchFileUploads();
await this.fetchExpiredFileUploads(); await this.fetchExpiredFileUploads();
await this.fetchStatistics();
await this.calculateStatistics(); await this.calculateStatistics();
} }
async calculateStatistics() { async calculateStatistics() {
console.log("Calculating statistics..."); this.totalFileSizeOnDisk = 0;
console.log(this.fileUploads) this.totalFileDownloads = 0;
for(let fileUpload of this.fileUploads) { for(let fileUpload of this.fileUploads) {
this.totalFileSizeOnDisk += fileUpload.fileSize; this.totalFileSizeOnDisk += fileUpload.fileSize;
} }
@ -86,4 +95,20 @@ export class AdminuiComponent {
console.error(error); console.error(error);
} }
} }
async fetchStatistics() {
try {
const response = await axios({
method: 'get',
url: this.developmentStore.getBaseUrl() + 'api/v1/secure/statistics',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + await firstValueFrom(this.authStore.token$)
}
});
this.statistics = response.data;
console.log(this.statistics)
} catch (error) {
console.error(error);
}
}
} }

View File

@ -0,0 +1,8 @@
import { DurationPipe } from './duration.pipe';
describe('DurationPipe', () => {
it('create an instance', () => {
const pipe = new DurationPipe();
expect(pipe).toBeTruthy();
});
});

View File

@ -0,0 +1,29 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'duration',
standalone: true
})
export class DurationPipe implements PipeTransform {
transform(value: number): string {
if (!value) {
return '0m';
}
let milliseconds = value;
const days = Math.floor(milliseconds / (24 * 60 * 60 * 1000));
milliseconds %= 24 * 60 * 60 * 1000;
const hours = Math.floor(milliseconds / (60 * 60 * 1000));
milliseconds %= 60 * 60 * 1000;
const minutes = Math.floor(milliseconds / (60 * 1000));
if (days > 0) {
return `${days}d ${hours}h ${minutes}m`;
} else if (hours > 0) {
return `${hours}h ${minutes}m`;
} else {
return `${minutes}m`;
}
}
}

View File

@ -0,0 +1,8 @@
import { RelativeTimePipe } from './relative-time.pipe';
describe('RelativeTimePipe', () => {
it('create an instance', () => {
const pipe = new RelativeTimePipe();
expect(pipe).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'relativeTime',
standalone: true,
pure: false
})
export class RelativeTimePipe implements PipeTransform {
transform(value: string): string {
if (!value) {
return '';
}
const now = new Date();
const past = new Date(value);
const elapsed = now.getTime() - past.getTime();
const msPerSecond = 1000;
const msPerMinute = msPerSecond * 60;
const msPerHour = msPerMinute * 60;
const msPerDay = msPerHour * 24;
const msPerWeek = msPerDay * 7;
const msPerMonth = msPerDay * 30;
const msPerYear = msPerDay * 365;
if (elapsed < msPerSecond) {
return 'just now';
} else if (elapsed < msPerMinute) {
return `${Math.round(elapsed / msPerSecond)} seconds ago`;
} else if (elapsed < msPerHour) {
return `${Math.round(elapsed / msPerMinute)} minutes ago`;
} else if (elapsed < msPerDay) {
return `${Math.round(elapsed / msPerHour)} hours ago`;
} else if (elapsed < msPerWeek) {
return `${Math.round(elapsed / msPerDay)} days ago`;
} else if (elapsed < msPerMonth) {
return `${Math.round(elapsed / msPerWeek)} weeks ago`;
} else if (elapsed < msPerYear) {
return `${Math.round(elapsed / msPerMonth)} months ago`;
} else {
return `${Math.round(elapsed / msPerYear)} years ago`;
}
}
}