Paginate, new table

This commit is contained in:
Daniel Ponte 2024-11-26 09:19:31 -05:00
parent a4fc8f7cca
commit 20104c59af
8 changed files with 253 additions and 131 deletions

View file

@ -163,37 +163,6 @@
</svg>
</button>
<!-- End Navigation Toggle -->
<!-- Breadcrumb -->
<ol class="ms-3 flex items-center whitespace-nowrap">
<li
class="flex items-center text-sm text-gray-800 dark:text-neutral-400"
>
Application Layout
<svg
class="shrink-0 mx-3 overflow-visible size-2.5 text-gray-400 dark:text-neutral-500"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</li>
<li
class="text-sm font-semibold text-gray-800 truncate dark:text-neutral-400"
aria-current="page"
>
Dashboard
</li>
</ol>
<!-- End Breadcrumb -->
</div>
</div>
<!-- End Breadcrumb -->
@ -289,14 +258,16 @@
<!-- Content -->
@if (auth.loggedIn) {
<div class="w-full lg:ps-64">
<div class="p-4 sm:p-6 space-y-4 sm:space-y-6">
<div class="container w-full lg:ps-64">
<div
class="object-contain object-scale-down p-4 sm:p-6 space-y-4 sm:space-y-6"
>
<router-outlet />
</div>
</div>
} @else {
<div class="w-full">
<div class="p-4 sm:p-6 space-y-4 sm:space-y-6">
<div class="object-contain p-4 sm:p-6 space-y-4 sm:space-y-6">
<router-outlet />
</div>
</div>

View file

@ -1,5 +1,5 @@
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter, } from '@angular/router';
import { provideRouter } from '@angular/router';
import { environment } from './../environments/environment';
import {
HttpRequest,

View file

@ -39,10 +39,10 @@ export interface Metadata {
}
export const iconMapping: IconMap = {
'police': 'matLocalPoliceOutline',
'fire': 'matFireTruckOutline',
'ems': 'matEmergencyOutline',
'bus': 'matDirectionsBusOutline',
police: 'matLocalPoliceOutline',
fire: 'matFireTruckOutline',
ems: 'matEmergencyOutline',
bus: 'matDirectionsBusOutline',
'': 'matGroupWorkOutline',
};

View file

@ -60,14 +60,14 @@
<alert-rule-builder [rules]="tg.alert_config" />
<div>
<label for="icon">Icon: </label>
<select
class="select"
name="icon"
id="icon"
formControlName="icon"
>
<select class="select" name="icon" id="icon" formControlName="icon">
@for (opt of iconMapping | keyvalue; track opt) {
<option value="{{ opt.key }}" [selected]="opt.key == tg.metadata?.icon">{{ opt.key | titlecase }}</option>
<option
value="{{ opt.key }}"
[selected]="opt.key == tg.metadata?.icon"
>
{{ opt.key | titlecase }}
</option>
}
</select>
</div>

View file

@ -1,5 +1,10 @@
import { Component, inject } from '@angular/core';
import { Talkgroup, TalkgroupUpdate, IconMap, iconMapping } from '../../talkgroup';
import {
Talkgroup,
TalkgroupUpdate,
IconMap,
iconMapping,
} from '../../talkgroup';
import { TalkgroupService } from '../talkgroups.service';
import { AlertRuleBuilderComponent } from './alert-rule-builder/alert-rule-builder.component';
import { CommonModule } from '@angular/common';
@ -51,8 +56,6 @@ export class TalkgroupRecordComponent {
});
console.log(this.tg.icon);
});
}
submit() {
@ -86,7 +89,9 @@ export class TalkgroupRecordComponent {
if (this.tg.icon == null || this.tg.icon == '') {
tgu.metadata = Object.assign(tgu.metadata, { icon: undefined });
} else {
tgu.metadata = Object.assign(tgu.metadata!, { icon: this.form.controls['icon'] });
tgu.metadata = Object.assign(tgu.metadata!, {
icon: this.form.controls['icon'],
});
}
}
this.tgService

View file

@ -1,33 +1,102 @@
<a href="#" class="btn btn-primary" routerLink="/talkgroups/import">Import</a>
<div class="w-100 justify-center overflow-x-auto">
<table class="table">
<thead>
<a href="#" class="btn btn-primary" routerLink="/talkgroups/import">Import</a>
<div class="rounded-lg border border-gray-200 dark:border-gray-700">
<div class="overflow-x-auto rounded-t-lg">
<table
class="min-w-full divide-y-2 divide-gray-200 bg-white text-sm dark:divide-gray-700 dark:bg-gray-900"
>
<thead class="ltr:text-left">
<tr>
<th></th>
<th>Sys</th>
<th>Sys ID</th>
<th>Group</th>
<th>Name</th>
<th>Alpha</th>
<th>TG ID</th>
<th>Learned</th>
<th></th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
></th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
Sys
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
Sys ID
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
Group
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
Name
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
Alpha Tag
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
TG ID
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
Learned
</th>
<th
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
></th>
</tr>
</thead>
<tbody>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@let tgs = talkgroups$ | async;
@for (tg of tgs?.talkgroups; track tg.id) {
<tr>
<!-- <td class="tgIcon" [innerHTML]="(tg | iconify).iconSvg! | sanitizeHtml"></td> -->
<td class="tgIcon"><ng-icon [name]="(tg | iconify).iconSvg!"></ng-icon></td>
<td>{{ tg.system?.name }}</td>
<td>{{ tg.system?.id }}</td>
<td>{{ tg.tg_group }}</td>
<td>{{ tg.name }}</td>
<td>{{ tg.alpha_tag }}</td>
<td>{{ tg.tgid }}</td>
<td>{{ tg?.learned ? "Y" : "" }}</td>
<td>
<td class="tgIcon">
<ng-icon [name]="(tg | iconify).iconSvg!"></ng-icon>
</td>
<td
class="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white"
>
{{ tg.system?.name }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
{{ tg.system?.id }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
{{ tg.tg_group }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
{{ tg.name }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
{{ tg.alpha_tag }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
{{ tg.tgid }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
{{ tg?.learned ? "Y" : "" }}
</td>
<td
class="whitespace-nowrap px-4 py-2 text-gray-700 dark:text-gray-200"
>
<a routerLink="/talkgroups/{{ tg.system?.id }}/{{ tg.tgid }}"
><ng-icon name="ionCreateOutline"></ng-icon
></a>
@ -36,10 +105,75 @@
}
</tbody>
</table>
<div class="w-100">
Total: {{ tgs?.count }}
<button class="btn btn-primary" (click)="prevPage()" [class.btn-ghost]="page == 1"><ng-icon name="ionChevronBack"></ng-icon></button>
Page {{ page }} of {{ totalPages }}
<button class="btn btn-primary" (click)="nextPage()" [class.btn-ghost]="page == totalPages"><ng-icon name="ionChevronForward"></ng-icon></button>
</div>
<div
class="rounded-b-lg border-t border-gray-200 px-4 py-2 dark:border-gray-700"
>
<ol class="flex justify-end gap-1 text-xs font-medium">
<li>
<button
(click)="prevPage()"
[class.btn-ghost]="page == 1"
class="inline-flex size-8 items-center justify-center rounded border border-gray-100 bg-white text-gray-900 rtl:rotate-180 dark:border-gray-800 dark:bg-gray-900 dark:text-white"
>
<span class="sr-only">Prev Page</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="size-3"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clip-rule="evenodd"
/>
</svg>
</button>
</li>
@for (pgn of [].constructor(totalPages); track i; let i = $index) {
@if (i != page) {
<li>
<button
(click)="setPage(i + 1)"
class="block size-8 rounded border border-gray-100 bg-white text-center leading-8 text-gray-900 dark:border-gray-800 dark:bg-gray-900 dark:text-white"
>
{{ i + 1 }}
</button>
</li>
} @else {
<li
class="block size-8 rounded border-blue-600 bg-blue-600 text-center leading-8 dark:text-white"
>
{{ i + 1 }}
</li>
}
}
<li>
<button
(click)="nextPage()"
[class.btn-ghost]="page == totalPages"
class="inline-flex size-8 items-center justify-center rounded border border-gray-100 bg-white text-gray-900 rtl:rotate-180 dark:border-gray-800 dark:bg-gray-900 dark:text-white"
>
<span class="sr-only">Next Page</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="size-3"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
/>
</svg>
</button>
</li>
</ol>
</div>
</div>
</div>

View file

@ -1,7 +1,11 @@
import { Component, inject, Pipe, PipeTransform } from '@angular/core';
import { TalkgroupService, TalkgroupsPaginated } from './talkgroups.service';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import { ionCreateOutline, ionChevronBack, ionChevronForward } from '@ng-icons/ionicons';
import {
ionCreateOutline,
ionChevronBack,
ionChevronForward,
} from '@ng-icons/ionicons';
import {
matFireTruckOutline,
matLocalPoliceOutline,
@ -17,7 +21,6 @@ import { RouterModule, RouterOutlet, RouterLink } from '@angular/router';
import { CommonModule } from '@angular/common';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({
standalone: true,
name: 'iconify',
@ -35,19 +38,16 @@ export class IconifyPipe implements PipeTransform {
@Pipe({
standalone: true,
name: 'sanitizeHtml'
name: 'sanitizeHtml',
})
export class SanitizeHtmlPipe implements PipeTransform {
constructor(private _sanitizer:DomSanitizer) {
}
constructor(private _sanitizer: DomSanitizer) {}
transform(v: string): SafeHtml {
return this._sanitizer.bypassSecurityTrustHtml(v);
}
}
@Component({
selector: 'talkgroups',
standalone: true,
@ -62,7 +62,9 @@ export class SanitizeHtmlPipe implements PipeTransform {
],
templateUrl: './talkgroups.component.html',
styleUrl: './talkgroups.component.css',
providers: [provideIcons({ ionCreateOutline,
providers: [
provideIcons({
ionCreateOutline,
matFireTruckOutline,
matLocalPoliceOutline,
matEmergencyOutline,
@ -70,7 +72,8 @@ export class SanitizeHtmlPipe implements PipeTransform {
matGroupWorkOutline,
ionChevronBack,
ionChevronForward,
})],
}),
],
})
export class TalkgroupsComponent {
selectedSys: number = 0;
@ -97,15 +100,24 @@ export class TalkgroupsComponent {
}
}
setPage(p: number) {
if (p <= this.totalPages && p > 0) {
this.page = p;
this.fetchTGs();
}
}
fetchTGs() {
this.talkgroups$ = this.route.paramMap.pipe(
switchMap((params) => {
this.selectedSys = Number(params.get('sys'));
this.selectedId = Number(params.get('tg'));
return this.tgService.getTalkgroupsPag({page: this.page, perPage: this.perPage}).pipe(
return this.tgService
.getTalkgroupsPag({ page: this.page, perPage: this.perPage })
.pipe(
tap((event) => {
this.totalPages = Math.ceil(event.count / this.perPage);
})
}),
);
}),
);