Skip to content

Commit

Permalink
feat: deployment select
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismclarke committed Feb 29, 2024
1 parent daf0783 commit 35a08da
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 11 deletions.
3 changes: 2 additions & 1 deletion apps/picsa-apps/dashboard/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<button mat-icon-button (click)="sidenav.opened = !sidenav.opened">
<mat-icon>menu</mat-icon>
</button>
<span style="flex: 1">PICSA Dashboard</span>
<dashboard-deployment-select />
<span style="flex: 1; text-align: center;">PICSA Dashboard</span>
@if(supabaseService.auth.authUser(); as user){
<div style="position: relative">
<button mat-button (click)="supabaseService.auth.signOut()" style="margin-top: 16px">
Expand Down
3 changes: 2 additions & 1 deletion apps/picsa-apps/dashboard/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { SupabaseService } from '@picsa/shared/services/core/supabase';

import { DASHBOARD_NAV_LINKS, INavLink } from './data';
import { DashboardMaterialModule } from './material.module';
import { DeploymentSelectComponent } from './modules/deployment/components';

@Component({
standalone: true,
imports: [RouterModule, DashboardMaterialModule, CommonModule],
imports: [RouterModule, DashboardMaterialModule, DeploymentSelectComponent, CommonModule],
selector: 'dashboard-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<button mat-button [matMenuTriggerFor]="menu" [style.visibility]="deployments.length > 0 ? 'visible' : 'hidden'">
@if(service.activeDeployment(); as deployment){
<ng-container *ngTemplateOutlet="deploymentSummary; context: { $implicit: deployment }"></ng-container>
} @else {
<div>Select Deployment</div>
}
<mat-icon iconPositionEnd>unfold_more</mat-icon>
</button>

<mat-menu #menu="matMenu">
@for(deployment of deployments; track deployment.id){
<button mat-menu-item class="menu-button" (click)="service.setActiveDeployment(deployment.id)">
<ng-container *ngTemplateOutlet="deploymentSummary; context: { $implicit: deployment }"></ng-container>
</button>

}
</mat-menu>

<ng-template #deploymentSummary let-deployment>
<div style="display: flex; align-items: center">
@if(deployment.icon_path){
<img
[src]="deployment.icon_path | storagePath"
style="height: 30px; width: 30px; object-fit: contain; margin-right: 8px"
/>
}
<span>{{ deployment.label }}</span>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DeploymentSelectComponent } from './deployment-select.component';

describe('DeploymentSelectComponent', () => {
let component: DeploymentSelectComponent;
let fixture: ComponentFixture<DeploymentSelectComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DeploymentSelectComponent],
}).compileComponents();

fixture = TestBed.createComponent(DeploymentSelectComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { CommonModule } from '@angular/common';
import { Component, effect, OnInit } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { StoragePathPipe } from '@picsa/shared/services/core/supabase';

import { DeploymentDashboardService } from '../../deployment.service';
import { IDeploymentRow } from '../../types';

@Component({
selector: 'dashboard-deployment-select',
standalone: true,
imports: [CommonModule, MatButtonModule, MatIconModule, MatMenuModule, StoragePathPipe],
templateUrl: './deployment-select.component.html',
styleUrls: ['./deployment-select.component.scss'],
})
export class DeploymentSelectComponent implements OnInit {
public deployments: IDeploymentRow[] = [];
constructor(public service: DeploymentDashboardService) {
effect(() => {
const allDeployments = service.deployments();
this.deployments = allDeployments.sort(this.sortDeployments);
});
}

async ngOnInit() {
await this.service.ready();
}

// Sort deployments so global (no country code) appear on bottom of list, and otherwise
// group by variant
private sortDeployments(a: IDeploymentRow, b: IDeploymentRow) {
if (a.country_code === b.country_code) return a.variant! > b.variant! ? 1 : -1;
if (!a.country_code) return 1;
return -1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IDeploymentRow } from './types';
@Injectable({ providedIn: 'root' })
export class DeploymentDashboardService extends PicsaAsyncService {
public readonly deployments = signal<IDeploymentRow[]>([]);
public readonly activeDeployment = signal<IDeploymentRow | null>(null);

public get table() {
return this.supabaseService.db.table('deployments');
Expand All @@ -20,6 +21,17 @@ export class DeploymentDashboardService extends PicsaAsyncService {
public override async init() {
await this.supabaseService.ready();
await this.listDeployments();
this.loadStoredDeployment();
}

public async setActiveDeployment(id: string) {
// provide optimistic update
this.activeDeployment.set(this.deployments().find((d) => d.id === id) || null);
// provide server update
// TODO - subscribe to realtime updates
const { data } = await this.table.select<'*', IDeploymentRow>('*').eq('id', id).limit(1).single();
this.activeDeployment.set(data);
this.storeDeployment(data?.id);
}

private async listDeployments() {
Expand All @@ -29,4 +41,21 @@ export class DeploymentDashboardService extends PicsaAsyncService {
}
this.deployments.set(data);
}

/** Store deployment id to localstorage to persist across sessions */
private storeDeployment(id?: string) {
if (id) {
localStorage.setItem('picsa_dashboard_deployment', id);
} else {
localStorage.removeItem('picsa_dashboard_deployment');
}
}

/** Retrieve persisted deployment id from localstorage and load */
private loadStoredDeployment() {
const id = localStorage.getItem('picsa_dashboard_deployment');
if (id) {
this.setActiveDeployment(id);
}
}
}
19 changes: 10 additions & 9 deletions apps/picsa-server/supabase/data/deployments_rows.csv
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
id,country_code,label,configuration,variant,access_key_md5,public
demo_admin,,Admin Demo,{},other,,true
global,,Global,{},extension,,true
global_translators,,Translators,{},other,,true
mw_extension,mw,Extension,{},extension,,true
mw_farmer,mw,Farmer,{},farmer,,true
zm_extension,zm,Zambia,{},extension,,true
zm_extension_demo,zm,ZM Admin Demo,{},other,,true
zm_farmer,zm,Farmer,{},farmer,,true
id,country_code,label,configuration,variant,access_key_md5,public,icon_path
demo_admin,,Admin Demo,{},other,,true,global/images/flags/global.svg
global,,Extension,{},extension,,true,global/images/flags/global.svg
global_translators,,Translators,{},other,,true,global/images/flags/global.svg
mw_admin_demo,mw,Admin Demo,{},other,,true,global/images/flags/mw.svg
mw_extension,mw,Extension,{},extension,,true,global/images/flags/mw.svg
mw_farmer,mw,Farmer,{},farmer,,true,global/images/flags/mw.svg
zm_admin_demo,zm,Admin Demo,{},other,,true,global/images/flags/zm.svg
zm_extension,zm,Extension,{},extension,,true,global/images/flags/zm.svg
zm_farmer,zm,Farmer,{},farmer,,true,global/images/flags/zm.svg

0 comments on commit 35a08da

Please sign in to comment.