Dashboard: fix/updates (WIP)

Hide dahboard in menu when user doesn't have permission
This commit is contained in:
phil 2024-03-24 12:08:42 +05:30
parent 31165ce3d5
commit 89eae25604
19 changed files with 166 additions and 127 deletions

View file

@ -6,8 +6,6 @@ import { MatTableDataSource } from '@angular/material/table'
import { Observable, forkJoin, of as observableOf } from 'rxjs'
import { map, mergeMap } from 'rxjs/operators'
// import { Apollo, gql } from 'apollo-angular'
const fieldTypeMap = {
Int: 'number',
Float: 'number',
@ -167,22 +165,22 @@ export class DashboardPageSection {
) {}
}
export class DashboardPage {
constructor(
public name: string,
public group: string,
public errors: string = undefined,
public description: string = undefined,
public html: string = undefined,
public notebook: string = undefined,
public dfData: MatTableDataSource<object> = undefined,
public plotData: Object = undefined,
public time: Date = undefined,
public attachment: string = undefined,
public expandedPanes: string[] = [],
public sections: DashboardPageSection[] = []
) {}
}
// export class DashboardPage {
// constructor(
// public name: string,
// public group: string,
// public errors: string = undefined,
// public description: string = undefined,
// public html: string = undefined,
// public notebook: string = undefined,
// public dfData: MatTableDataSource<object> = undefined,
// public plotData: Object = undefined,
// public time: Date = undefined,
// public attachment: string = undefined,
// public expandedPanes: string[] = [],
// public sections: DashboardPageSection[] = []
// ) {}
// }
export class Model {
constructor(
@ -361,62 +359,63 @@ export class ModelDataService {
}
}
@Injectable()
export class DashboardDataService {
constructor(
// private apollo: Apollo
) {}
// @Injectable()
// export class DashboardDataService {
// constructor(
// public dashboardService: DashboardService,
// ) {}
getDashboardPage(group: string, name: string): Observable<DashboardPage> {
console.warn('Migrate Graphql')
return observableOf()
// return this.get(dashboardPageQuery, {'name': name, 'group': group}).pipe(map(
// res => {
// if (res['errors'] && res['errors'].length > 0) {
// return new DashboardPage(
// name,
// group,
// res['errors'].map(e => e.message).join(', '),
// )
// }
// getDashboardPage(group: string, name: string): Observable<Dashboard> {
// return this.dashboardService.getDashboardPageApiDashboardPageGroupNameGet(
// group, name
// )
// // return this.get(dashboardPageQuery, {'name': name, 'group': group}).pipe(map(
// // res => {
// // if (res['errors'] && res['errors'].length > 0) {
// // return new DashboardPage(
// // name,
// // group,
// // res['errors'].map(e => e.message).join(', '),
// // )
// // }
// let page = res['dashboard_page']
// return new DashboardPage(
// page['name'],
// page['group'],
// '',
// page['description'],
// page['html'],
// page['notebook'],
// JSON.parse(page['dfData']),
// JSON.parse(page['plotData']),
// page['time'],
// page['attachment'],
// page['expandedPanes'],
// page['sections'] ? page['sections'].map(
// section => new DashboardPageSection(
// section['name'],
// section['plot']
// )
// ) : []
// )
// }
// ))
}
// // let page = res['dashboard_page']
// // return new DashboardPage(
// // page['name'],
// // page['group'],
// // '',
// // page['description'],
// // page['html'],
// // page['notebook'],
// // JSON.parse(page['dfData']),
// // JSON.parse(page['plotData']),
// // page['time'],
// // page['attachment'],
// // page['expandedPanes'],
// // page['sections'] ? page['sections'].map(
// // section => new DashboardPageSection(
// // section['name'],
// // section['plot']
// // )
// // ) : []
// // )
// // }
// // ))
// }
get(query, vars: object = {}): Observable<any> {
console.warn('Migrate Graphql')
return observableOf()
// return this.apollo.query({
// query: query,
// variables: vars
// }).pipe(map(
// result => {
// if (result.errors && result.errors.length > 0) {
// return result
// }
// return result.data
// }
// ))
}
}
// get(query, vars: object = {}): Observable<any> {
// console.warn('Migrate Graphql')
// return observableOf()
// // return this.apollo.query({
// // query: query,
// // variables: vars
// // }).pipe(map(
// // result => {
// // if (result.errors && result.errors.length > 0) {
// // return result
// // }
// // return result.data
// // }
// // ))
// }
// }

View file

@ -128,6 +128,7 @@ export class AuthenticationService {
isAuthorized(roles: string[]): Observable<boolean> {
// Return true if at least one role in given list matches one role of the authenticated user
if (roles.length == 0) return of(true)
if (roles.every(role => role == undefined)) return of(true)
// return this.roles.filter(value => -1 !== roles.indexOf(value.name)).length > 0
return this.configService.conf.pipe(map(
conf => conf.bsData?.user?.roles?.filter(value => -1 !== roles.indexOf(value.name)).length > 0

View file

@ -5,19 +5,20 @@
>
<mat-expansion-panel-header>
<mat-panel-title>
{{ menuItem['name'] }}
{{ menuItem.name }}
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list-item
*ngFor="let item of menuItem['pages']"
*ngFor="let item of menuItem.pages"
>
<button mat-button
matTooltip="{{ item['description'] }}"
[hidden]="isHidden(item) | async"
matTooltip="{{ item.description }}"
matTooltipPosition="right"
routerLink="/dashboard/{{ item['group'] }}/{{ item['name'] }}"
routerLink="/dashboard/{{ item.group }}/{{ item.name }}"
routerLinkActive="active"
>
{{ item['name'] }}
{{ item.name }}
</button>
</mat-list-item>
</mat-expansion-panel>

View file

@ -1,8 +1,10 @@
import { Component, OnInit, Input,
ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'
import { DashboardService, DashboardGroup } from '../../openapi'
import { DashboardService, DashboardGroup, DashboardPageMetaData } from '../../openapi'
import { AuthenticationService } from '../../_services/authentication.service'
import { Observable, map, of } from 'rxjs'
import { Dash } from 'plotly.js-dist-min'
@Component({
selector: 'gisaf-dashboard-menu',
@ -15,6 +17,7 @@ export class DashboardMenuComponent implements OnInit {
constructor(
public dashboardService: DashboardService,
public authenticationService: AuthenticationService,
private cdr: ChangeDetectorRef,
) {}
@ -26,4 +29,10 @@ export class DashboardMenuComponent implements OnInit {
}
)
}
isHidden(dashboard: DashboardPageMetaData): Observable<boolean> {
return this.authenticationService.isAuthorized([dashboard.viewable_role]).pipe(map(
r => !r
))
}
}

View file

@ -2,16 +2,17 @@ import { Injectable } from '@angular/core'
import { RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'
import { Observable } from 'rxjs'
import { DashboardDataService } from '../../_services/apollo.service'
// import { DashboardDataService } from '../../_services/apollo.service'
import { DashboardService, Dashboard } from '../../openapi'
@Injectable()
export class DashboardPageResolver {
constructor(
private dashboardDataService: DashboardDataService,
private dashboardService: DashboardService,
) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<object> {
return this.dashboardDataService.getDashboardPage(
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Dashboard> {
return this.dashboardService.getDashboardPageApiDashboardPageGroupNameGet(
route.paramMap.get('group'),
route.paramMap.get('name')
)

View file

@ -6,8 +6,7 @@ import { Observable, of } from 'rxjs'
import { map, startWith } from 'rxjs/operators'
import { UntypedFormControl } from '@angular/forms'
import { DashboardPage, DashboardPageSection } from '../../_services/apollo.service'
import { Dashboard, DashboardSection } from '../../openapi'
const expandDefault = ['attachment', 'plot', 'html']
@ -25,12 +24,12 @@ export class Section {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardPageSectionsComponent implements OnInit {
@Input() page: DashboardPage
currentSection: DashboardPageSection
@Input() page: Dashboard
currentSection: DashboardSection
myControl: UntypedFormControl = new UntypedFormControl()
@ViewChild('ipt', { static: true }) ipt: ElementRef
//sections: Section[] = []
filteredOptions: Observable<DashboardPageSection[]>
filteredOptions: Observable<DashboardSection[]>
constructor(
protected route: ActivatedRoute,
@ -41,7 +40,7 @@ export class DashboardPageSectionsComponent implements OnInit {
ngOnInit() {
this.route.queryParams.subscribe(
(params: Params) => {
let s: DashboardPageSection[] = this.page.sections.filter(s=>s.name == params['section'])
let s: DashboardSection[] = this.page.sections.filter(s=>s.name == params['section'])
if (s.length > 0) {
this.select(s[0])
}
@ -81,14 +80,14 @@ export class DashboardPageSectionsComponent implements OnInit {
)
}
filter(val: string): DashboardPageSection[] {
filter(val: string): DashboardSection[] {
let filter = val.toLowerCase()
return this.page.sections.filter(option => {
return option.name.toLowerCase().indexOf(filter) != -1
})
}
select(section: DashboardPageSection) {
select(section: DashboardSection) {
this.currentSection = section
this.cdr.markForCheck()
}

View file

@ -18,6 +18,8 @@ a {
:host ::ng-deep table th.mat-mdc-header-cell {
padding: 0 0.5em;
text-transform: capitalize;
font-weight: bolder;
}
:host ::ng-deep table td.mat-mdc-cell {

View file

@ -1,14 +1,14 @@
<mat-card appearance="outlined">
<mat-card-title>
{{ page.group }} / {{ page.name }}
{{ page?.group }} / {{ page.name }}
</mat-card-title>
<mat-card-subtitle>
{{ page.description }}
</mat-card-subtitle>
<mat-card-content>
<p *ngIf='page.errors' class='errors'>
<!-- <p *ngIf='page.errors' class='errors'>
Error: {{ page.errors }}
</p>
</p> -->
<mat-accordion
[multi]='multiPanel'>
<mat-expansion-panel *ngIf='page.attachment'
@ -41,7 +41,7 @@
</mat-expansion-panel-header>
<div class='item' [innerHTML]='page.html | safeHtml'></div>
</mat-expansion-panel>
<mat-expansion-panel *ngIf='page.dfData'
<mat-expansion-panel *ngIf='page.dfData.length > 0'
[expanded]="expand.includes('data')">
<mat-expansion-panel-header>
<mat-panel-title>
@ -49,17 +49,17 @@
</mat-panel-title>
</mat-expansion-panel-header>
<table mat-table
[dataSource]='page.dfData'>
[dataSource]='getTableData()'>
<ng-container *ngFor='let colName of df_columns'
[matColumnDef]='colName'>
<th mat-header-cell *matHeaderCellDef>{{ colName }}</th>
<td mat-cell *matCellDef="let value"> {{ value[colName] }} </td>
<td mat-cell *matCellDef="let value"> {{ formatCell(value[colName]) }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="df_columns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: df_columns"></tr>
</table>
</mat-expansion-panel>
<gisaf-dashboard-page-sections *ngIf='page.sections.length > 0' [page]="page">
<gisaf-dashboard-page-sections *ngIf='page.sections?.length > 0' [page]="page">
</gisaf-dashboard-page-sections>
</mat-accordion>
</mat-card-content>

View file

@ -2,7 +2,8 @@ import { Component, OnInit,
ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { DashboardPage } from '../../_services/apollo.service'
import { Dashboard } from '../../openapi'
import { CdkTableDataSourceInput } from '@angular/cdk/table'
const expandDefault = ['attachment', 'plot', 'html']
@ -13,7 +14,11 @@ const expandDefault = ['attachment', 'plot', 'html']
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardPageComponent implements OnInit {
page: DashboardPage
page: Dashboard = {
name: '',
group: '',
description: '',
}
multiPanel: boolean = true
df_columns: string[]
// Default expanded panels
@ -40,14 +45,13 @@ export class DashboardPageComponent implements OnInit {
ngOnInit() {
this.route.data.subscribe(
(data: DashboardPage) => {
let item = data['item']
if (item.dfData) {
this.df_columns = item.dfData['schema']['fields'].map(f => f.name)
item.dfData = item.dfData['data']
data => {
this.page = data['dashboard']
if (this.page.dfData && this.page.dfData.length > 0) {
// this.df_columns = item.dfData['schema']['fields'].map(f => f.name)
this.df_columns = Object.keys(this.page.dfData[0])
}
this.page = item
if (this.page.expandedPanes.length > 0) {
if (this.page.expandedPanes?.length > 0) {
this.expand = this.page.expandedPanes
}
else {
@ -57,4 +61,17 @@ export class DashboardPageComponent implements OnInit {
}
)
}
getTableData(): CdkTableDataSourceInput<object> {
return this.page.dfData as CdkTableDataSourceInput<object>
}
formatCell(value) {
if (typeof value === 'number') {
return value.toFixed(1)
}
else {
return value
}
}
}

View file

@ -14,7 +14,7 @@ const routes: Routes = [
path: ':group/:name',
component: DashboardPageComponent,
resolve: {
item: DashboardPageResolver
dashboard: DashboardPageResolver
}
},
]

View file

@ -26,7 +26,7 @@ import { PlotlyViaWindowModule } from 'angular-plotly.js'
import { PipesModule } from '../pipes.module'
import { DashboardDataService } from '../_services/apollo.service'
// import { DashboardDataService } from '../_services/apollo.service'
import { DashboardComponent } from './dashboard.component'
import { DashboardRoutingModule } from './dashboard-routing.module'
import { DashboardMenuComponent } from './dashboard-menu/dashboard-menu.component'
@ -69,7 +69,7 @@ import { DashboardHomeComponent } from './dashboard-home/dashboard-home.componen
DashboardHomeComponent,
],
providers: [
DashboardDataService
// DashboardDataService
]
})

View file

@ -27,7 +27,6 @@ import { FlexLayoutModule } from 'ngx-flexible-layout'
import { PipesModule } from '../pipes.module'
import { AdminDetailModule } from '../admin/admin-detail/admin-detail.module'
import { DashboardDataService } from '../_services/apollo.service'
import { InfoDataService } from './info-data.service'
import { InfoComponent } from './info.component'
@ -112,7 +111,6 @@ import { DownloaderComponent } from './info-tools/downloader.component'
],
providers: [
InfoDataService,
DashboardDataService,
TagsPluginsService,
]
})

View file

@ -21,7 +21,7 @@ export type OpenAPIConfig = {
export const OpenAPI: OpenAPIConfig = {
BASE: '',
VERSION: '2023.4.dev51+g15fe7fa.d20240318',
VERSION: '2023.4.dev53+gd539a72.d20240320',
WITH_CREDENTIALS: false,
CREDENTIALS: 'include',
TOKEN: undefined,

View file

@ -16,10 +16,11 @@ export type { Body_login_for_access_token_api_token_post } from './models/Body_l
export type { BootstrapData } from './models/BootstrapData';
export type { CategoryGroup } from './models/CategoryGroup';
export type { CategoryRead } from './models/CategoryRead';
export type { DashboadPageSectionType } from './models/DashboadPageSectionType';
export type { Dashboard } from './models/Dashboard';
export type { DashboardGroup } from './models/DashboardGroup';
export type { DashboardHome } from './models/DashboardHome';
export type { DashboardPage_ } from './models/DashboardPage_';
export type { DashboardPageMetaData } from './models/DashboardPageMetaData';
export type { DashboardSection } from './models/DashboardSection';
export type { DataProvider } from './models/DataProvider';
export type { Downloader } from './models/Downloader';
export type { Equipment } from './models/Equipment';

View file

@ -2,18 +2,18 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { DashboadPageSectionType } from './DashboadPageSectionType';
export type DashboardPage_ = {
import type { DashboardSection } from './DashboardSection';
export type Dashboard = {
name: string;
group: string;
description: string;
time?: (string | null);
html?: (string | null);
attachment?: (string | null);
dfData?: (string | null);
dfData?: Array<any>;
plotData?: (string | null);
notebook?: (string | null);
expandedPanes?: (Array<string> | null);
sections?: (Array<DashboadPageSectionType> | null);
sections?: (Array<DashboardSection> | null);
};

View file

@ -2,9 +2,9 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { DashboardPage_ } from './DashboardPage_';
import type { DashboardPageMetaData } from './DashboardPageMetaData';
export type DashboardGroup = {
name: string;
pages: Array<DashboardPage_>;
pages: Array<DashboardPageMetaData>;
};

View file

@ -0,0 +1,11 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type DashboardPageMetaData = {
name: string;
group: string;
description: string;
viewable_role?: (string | null);
};

View file

@ -2,7 +2,7 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type DashboadPageSectionType = {
export type DashboardSection = {
name: string;
plot: string;
};

View file

@ -5,9 +5,9 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import type { Observable } from 'rxjs';
import type { Dashboard } from '../models/Dashboard';
import type { DashboardGroup } from '../models/DashboardGroup';
import type { DashboardHome } from '../models/DashboardHome';
import type { DashboardPage_ } from '../models/DashboardPage_';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
@Injectable({
@ -47,13 +47,13 @@ export class DashboardService {
* Get Dashboard Page
* @param group
* @param name
* @returns DashboardPage_ Successful Response
* @returns Dashboard Successful Response
* @throws ApiError
*/
public getDashboardPageApiDashboardPageGroupNameGet(
group: string,
name: string,
): Observable<DashboardPage_> {
): Observable<Dashboard> {
return __request(OpenAPI, this.http, {
method: 'GET',
url: '/api/dashboard/page/{group}/{name}',