src/app/modules/dashboard/components/list-all-reports/list-all-reports.component.ts
OnInit
selector | app-list-all-reports |
styleUrls | ./list-all-reports.component.scss |
templateUrl | ./list-all-reports.component.html |
Properties |
|
Methods |
|
Accessors |
constructor(resourceService: ResourceService, reportService: ReportService, activatedRoute: ActivatedRoute, router: Router, userService: UserService, navigationhelperService: NavigationHelperService, telemetryService: TelemetryService, layoutService: LayoutService, tncService: TncService, location: Location)
|
|||||||||||||||||||||||||||||||||
Parameters :
|
Private getReportsCount | |||
getReportsCount(undefined)
|
|||
Parameters :
Returns :
any
|
Private getReportsList | ||||||
getReportsList(isUserReportAdmin: boolean)
|
||||||
Parameters :
Returns :
any
Observable with list of reports. |
Public getReportViewerTncPolicy |
getReportViewerTncPolicy()
|
Returns :
void
|
goBack |
goBack()
|
Returns :
void
|
Private indexColumn | ||||
indexColumn(table)
|
||||
Parameters :
Returns :
void
|
initLayout |
initLayout()
|
Returns :
void
|
Private logTelemetry | |||
logTelemetry(undefined)
|
|||
Parameters :
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Public prepareTable | ||||||||||||
prepareTable(el, data: [])
|
||||||||||||
Parameters :
Returns :
void
|
Private renderStatus | ||||||||
renderStatus(data, type, row)
|
||||||||
Parameters :
Returns :
string
|
Private renderTags | ||||
renderTags(data)
|
||||
Parameters :
Returns :
any
|
Public rowClickEventHandler |
rowClickEventHandler(reportId: string, hash?: string, materialize?: boolean)
|
Returns :
void
|
Public setTelemetryInteractEdata | |||
setTelemetryInteractEdata(undefined)
|
|||
Parameters :
Returns :
{ id: string; type: any; pageid: any; }
|
Public showReportViewerTncForFirstUser |
showReportViewerTncForFirstUser()
|
Returns :
void
|
Private _isUserReportAdmin |
Type : boolean
|
Private filterReportsBasedOnRoles |
Default value : () => {...}
|
Private getDefaultTableOptions |
Default value : () => {...}
|
Public getTelemetryImpression |
Default value : () => {...}
|
layoutConfiguration |
Type : any
|
Public location |
Type : Location
|
Public noResultFoundError |
Type : string
|
reports |
Type : any
|
Public reportService |
Type : ReportService
|
Public reportsList$ |
Type : Observable<any>
|
reportViewerTncUrl |
Type : string
|
reportViewerTncVersion |
Type : string
|
Public resourceService |
Type : ResourceService
|
Public setTelemetryInteractObject |
Default value : () => {...}
|
showTncPopup |
Default value : false
|
Public tncService |
Type : TncService
|
userProfile |
inputTag | ||||||
setinputTag(element: ElementRef | null)
|
||||||
Parameters :
Returns :
void
|
datasetTable | ||||||
setdatasetTable(element: ElementRef | null)
|
||||||
Parameters :
Returns :
void
|
import { UserService, TncService } from '@sunbird/core';
import { TelemetryService } from '@sunbird/telemetry';
import { ResourceService, NavigationHelperService, LayoutService } from '@sunbird/shared';
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { catchError, mergeMap, map, first } from 'rxjs/operators';
import * as _ from 'lodash-es';
import { ReportService } from '../../services';
import { of, Observable, throwError } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import dayjs from 'dayjs';
import $ from 'jquery';
import 'datatables.net';
import { Location } from '@angular/common';
const reportsToExclude : string[] = ['program_dashboard'];
@Component({
selector: 'app-list-all-reports',
templateUrl: './list-all-reports.component.html',
styleUrls: ['./list-all-reports.component.scss']
})
export class ListAllReportsComponent implements OnInit {
reports: any;
userProfile;
reportViewerTncVersion: string;
reportViewerTncUrl: string;
showTncPopup = false;
constructor(public resourceService: ResourceService, public reportService: ReportService, private activatedRoute: ActivatedRoute,
private router: Router, private userService: UserService, private navigationhelperService: NavigationHelperService,
private telemetryService: TelemetryService, private layoutService: LayoutService, public tncService: TncService, public location:Location) { }
public reportsList$: Observable<any>;
public noResultFoundError: string;
private _isUserReportAdmin: boolean;
layoutConfiguration: any;
@ViewChild('allReports') set inputTag(element: ElementRef | null) {
if (!element) { return; }
const [reports, ] = this.reports;
this.prepareTable(element.nativeElement, reports);
}
@ViewChild('allDatasets') set datasetTable(element: ElementRef | null) {
if (!element) { return; }
let [, datasets] = this.reports;
if (this.reportService.isUserReportAdmin() && !this.reportService.isUserSuperAdmin()) {
datasets = datasets.filter(dataset => dataset.status === 'live');
}
this.prepareTable(element.nativeElement, datasets);
}
ngOnInit() {
this.initLayout();
this.userService.userData$.pipe(first()).subscribe(async (user) => {
if (user && user.userProfile) {
this.userProfile = user.userProfile;
this.getReportViewerTncPolicy();
}
});
this.reportsList$ = this.reportService.isAuthenticated(_.get(this.activatedRoute, 'snapshot.data.roles')).pipe(
mergeMap((isAuthenticated: boolean) => {
this._isUserReportAdmin = this.reportService.isUserReportAdmin();
return isAuthenticated ? this.getReportsList(this._isUserReportAdmin) : throwError({ messageText: 'messages.stmsg.m0144' });
}),
catchError(err => {
this.noResultFoundError = _.get(err, 'messageText') || 'messages.stmsg.m0006';
return of({
table: {},
count: 0,
reportsArr: [],
datasetsArr: []
});
})
);
}
goBack() {
this.location.back();
}
private filterReportsBasedOnRoles = (reports: any[]) => {
if (this.reportService.isUserSuperAdmin()) {
return this.reportService.getMaterializedChildRows(reports);
} else if (this.reportService.isUserReportAdmin()) {
return of(reports);
} else {
return of(this.reportService.getFlattenedReports(reports));
}
}
/**
* @private
* @returns Observable with list of reports.
* @memberof ListAllReportsComponent
*/
private getReportsList(isUserReportAdmin: boolean) {
const filters = {};
return this.reportService.listAllReports(filters).pipe(
mergeMap(res => this.filterReportsBasedOnRoles(res.reports)),
map(reports => {
const [reportsArr, datasetsArr] = this.reports = _.partition(reports, report => _.toLower(_.get(report, 'report_type')) === 'report');
const count = _.get(reports, 'length');
_.remove(reportsArr, (report) => {
return reportsToExclude.includes(report.reportconfig.report_type)
})
return { count, reportsArr, datasetsArr };
})
);
}
/**
* @description routes to report detailed view page
* @param {*} event
* @memberof ListAllReportsComponent
*/
public rowClickEventHandler(reportId: string, hash?: string, materialize?: boolean) {
this.router.navigate(['/dashBoard/reports', reportId, ...(hash ? [hash] : [])],
{ queryParams: { ...(this.reportService.isUserReportAdmin() && { materialize }) } }).catch(err => {
console.log({ err });
});
}
private renderStatus(data, type, row) {
if (row.isParameterized && row.children && this.reportService.isUserReportAdmin()) {
if (_.every(row.children, child => _.toLower(child.status) === 'live')) {
data = 'live';
} else {
if (_.some(row.children, child => _.toLower(child.status) === 'live')) {
data = 'partially live';
} else {
data = 'draft';
}
}
}
const icon = {
live: { color: 'success-0', icon: 'check' },
draft: { color: 'warning-0', icon: 'edit' },
retired: { color: 'primary-100', icon: 'close' },
['partially live']: { color: 'secondary-0', icon: 'check' }
};
const status = _.startCase(_.toLower(data));
const spanElement = `<span class="sb-label sb-label-table sb-label-${icon[_.toLower(data)].color}" tabindex="0">
${data === 'live' ? `<span class="sb-live"></span>` : ''} ${status}</span>`;
return spanElement;
}
private renderTags(data) {
if (Array.isArray(data)) {
const elements = _.join(_.map(data, tag => `<span class="sb-label-name sb-label-table sb-label-primary-100 mr-5 px-8 py-4" tabindex="0">${_.startCase(_.toLower(tag))}</span>`), ' ');
return `<div class="sb-filter-label" tabindex="0"><div class="d-inline-flex m-0">${elements}</div></div>`;
}
return _.startCase(_.toLower(data));
}
/**
* @description returns default config options for master and child table
* @private
* @memberof ListAllReportsComponent
*/
private getDefaultTableOptions = () => ({
paging: true,
lengthChange: true,
searching: true,
ordering: true,
info: true,
autoWidth: true,
})
private indexColumn(table) {
table.on('order.dt search.dt', () => {
table.column(0, { search: 'applied', order: 'applied' }).nodes().each((cell, i) => {
cell.innerHTML = i + 1;
});
}).draw();
}
/**
* @description initializes the dataTables with relevant configurations
* @param {*} el
* @memberof ListAllReportsComponent
*/
public prepareTable(el, data = []) {
const masterTable = $(el).DataTable({
...this.getDefaultTableOptions(),
order: [[1, 'desc']],
data,
columns: [
{
title: 'Serial No.',
searchable: false,
orderable: false,
data: null
},
{ title: 'Created On', data: 'createdon', visible: false },
...(this.reportService.isUserReportAdmin() ? [{
class: 'details-control',
title: '',
orderable: false,
data: null,
render: (value, type, row) => {
const isParameterized = _.get(row, 'isParameterized') || false;
let count = 0;
if (isParameterized && row.children) {
count = _.filter(row.children, child => _.toLower(child.status) === 'live').length;
}
return `<button class="sb-btn sb-btn-link sb-btn-link-primary sb-btn-normal sb-btn-square" aria-label="file-icon" tabindex="0">
<i class="icon ${isParameterized && row.children ? 'copy outline' : 'file outline'}
alternate"></i><span>${isParameterized && row.children ? `${count}/${row.children.length} Live` : ''}</span></button>`;
},
defaultContent: ''
}] : []),
{ title: 'Report Id', data: 'reportid', visible: false },
{
title: 'Title', data: 'title', render: (value, type, row) => {
const { title, description } = row;
return `<div class="sb-media" tabindex="0"><div class="sb-media-body"><h6 class="p-0">
${title}</h6> <p class="media-description sb__ellipsis"> ${description}</p></div></div>`;
}
},
{
title: 'Last Published Date', data: 'updatedon',
render: (value) => {
const date = dayjs(value);
if (date.isValid()) {
return `<td tabindex="0"> ${dayjs(value).format('YYYY/MM/DD')} </td>`;
}
return _.startCase(_.toLower(value));
}
}, {
title: 'Tags',
data: 'tags',
render: this.renderTags
}, {
title: 'Update Frequency',
data: 'updatefrequency',
render: this.renderTags
},
...(this._isUserReportAdmin ? [{
title: 'Status',
data: 'status',
render: this.renderStatus.bind(this)
}] : [])]
});
this.indexColumn(masterTable);
$(el).on('click', 'tbody tr td:not(.details-control)', (event) => {
const rowData = masterTable && masterTable.row(event?.currentTarget).data();
if (_.get(rowData, 'reportid') && _.get(rowData, 'hashed_val') && rowData.hasOwnProperty('materialize')) {
const reportid = _.get(rowData,'reportid');
const hashed_val = _.get(rowData,'hashed_val');
const materialize = _.get(rowData,'materialize');
this.logTelemetry({ type: 'select-report', id: `${reportid}` });
this.rowClickEventHandler(reportid, hashed_val, materialize || false);
}
});
const getChildTable = (table_id) => `<table id="${table_id}" class="sb-table sb-table-hover sb-table-striped sb-table-sortable w-80 dataTable no-footer"></table>`;
$(el).on('click', 'td.details-control', (event) => {
const tr = $(event.currentTarget).closest('tr');
const row = masterTable.row(tr);
const rowData = _.get(row, 'data')();
if (row.child.isShown()) {
row.child.hide();
} else {
if (!rowData.isParameterized) { return false; }
if (!_.has(rowData, 'children')) { return false; }
const id = rowData.reportid;
this.logTelemetry({
type: 'select-parameterized', id: `${id}`,
cdata: [{ id: `${_.get(rowData, 'children.length')}`, type: 'CountReports' },
{ id: `${this.getReportsCount({ reports: rowData.children, status: 'live' })}`, type: 'Live' },
{ id: `${this.getReportsCount({ reports: rowData.children, status: 'draft' })}`, type: 'Draft' }]
});
row.child(getChildTable(id)).show();
const childTable = $(`#${id}`).DataTable({
...this.getDefaultTableOptions(),
lengthChange: false,
info: false,
data: rowData.children,
columns: [
{
title: 'Serial No.',
searchable: false,
orderable: false,
data: null
},
{
title: 'Parameter',
data: 'hashed_val',
className: 'text-center',
render: value => {
const parameters = _.split(atob(value), '__');
return parameters;
}
}, {
title: 'Status',
data: 'status',
render: this.renderStatus.bind(this),
className: 'text-center'
}]
});
this.indexColumn(childTable);
$(`#${id}`).on('click', 'td', e => {
const { reportid, hashed_val, materialize } = childTable.row(e.currentTarget).data();
this.logTelemetry({ type: 'select-report', id: `${reportid}`, cdata: [{ id: `${this.reportService.getParameterFromHash(hashed_val)}`, type: 'ParameterName' }] });
this.rowClickEventHandler(reportid, hashed_val, materialize || false);
});
}
});
}
public getTelemetryImpression = ({ type, cdata = [] }) => ({
context: {
env: this.activatedRoute.snapshot.data.telemetry.env,
cdata
},
object: {
id: this.userService.userid,
type: 'user',
ver: '1.0'
},
edata: {
type,
pageid: this.activatedRoute.snapshot.data.telemetry.pageid,
uri: this.router.url,
duration: this.navigationhelperService.getPageLoadTime()
}
})
public setTelemetryInteractObject = ({ id, type = 'Report', ver = '1.0' }) => ({ id, type, ver });
public setTelemetryInteractEdata({ type, id = 'reports-list' }) {
return {
id,
type,
pageid: this.activatedRoute.snapshot.data.telemetry.pageid
};
}
private logTelemetry({ type, cdata = [], id }) {
const interactData = {
context: {
env: _.get(this.activatedRoute.snapshot.data.telemetry, 'env') || 'reports',
cdata
},
edata: {
...this.setTelemetryInteractEdata({ type }),
},
object: {
...this.setTelemetryInteractObject({ id }),
rollup: {}
}
};
this.telemetryService.interact(interactData);
}
private getReportsCount({ reports = [], status = 'draft' }) {
return _.size(_.filter(reports, report => _.get(report, 'status') === status));
}
initLayout() {
this.layoutConfiguration = this.layoutService.initlayoutConfig();
this.layoutService.switchableLayout()
.subscribe(layoutConfig => {
if (layoutConfig != null) {
this.layoutConfiguration = layoutConfig.layout;
}
});
}
public getReportViewerTncPolicy() {
this.tncService.getReportViewerTnc().subscribe((data) => {
const reportViewerTncData = JSON.parse(_.get(data, 'result.response.value'));
if (_.get(reportViewerTncData, 'latestVersion')) {
this.reportViewerTncVersion = _.get(reportViewerTncData, 'latestVersion');
this.reportViewerTncUrl = _.get(_.get(reportViewerTncData, _.get(reportViewerTncData, 'latestVersion')), 'url');
this.showReportViewerTncForFirstUser();
}
});
}
public showReportViewerTncForFirstUser() {
const reportViewerTncObj = _.get(this.userProfile, 'allTncAccepted.reportViewerTnc');
if (!reportViewerTncObj) {
this.showTncPopup = true;
}
}
}
<app-landing-section [noTitle]="true" [layoutConfiguration]="layoutConfiguration">
</app-landing-section>
<div
[ngClass]="layoutConfiguration ? 'sb-back-actionbar' : 'sb-bg-color-white back-btn-container cc-player__btn-back relative9'"
class="relative position mt-0">
<div class="ui container py-0 px-0 d-flex flex-ai-center">
<div class="py-0 d-flex flex-ai-center w-100">
<!-- /* Back button */ -->
<button type="button" [ngClass]="layoutConfiguration ? 'sb-btn-primary sb-btn-round' : 'sb-btn-link sb-btn-link-primary sb-left-icon-btn px-0'"
class="sb-btn sb-btn-normal" tabindex="0" (click)="goBack()" attr.aria-label="{{resourceService?.frmelmnts?.btn?.back}}">
<em class="icon-svg icon-svg--xxs icon-back mr-4"><svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#arrow-long-left"></use>
</svg></em>
<span>{{resourceService?.frmelmnts?.btn?.back}}</span>
</button>
<div class="textbook d-flex flex-ai-center flex-jc-space-between w-100 ml-16">
<!-- title -->
<h5 class="textbook__title sb-color-primary font-weight-bold mb-0" tabindex="0">Reports</h5>
</div>
</div>
</div>
</div>
<div [ngClass]="layoutConfiguration ? 'sbt-inside-page-container' : 'pt-16'">
<div class="sb-pageSection my-24 ui container listallreports-section">
<ng-container *ngIf="(reportsList$ | async ) as reportsList else loading">
<div class="sb-pageSection-content">
<ng-container *ngIf="reportsList.count > 0 else noResult">
<div
[appTelemetryImpression]="getTelemetryImpression({type: 'page-loaded', cdata: reportService?.isUserReportAdmin() ? [{id: '' + reportsList?.reportsArr?.length, type: 'CountReports'},
{id: '' + reportsList?.datasetsArr?.length, type: 'CountDatasets'}] : [{id: '' + reportsList?.reportsArr?.length, type: 'CountReports'}]})">
<mat-tab-group mat-align-tabs="center" class="sb-mat__tab sb-mat__tab--tabinacc list-all-mat-tab">
<mat-tab label="Reports">
<div class="ui bottom attached small p-0 b-0 no-bg py-24 sb-table-responsive">
<table #allReports class="sb-table sb-table-hover sb-table-striped sb-table-sortable width-100">
</table>
</div>
</mat-tab>
<mat-tab label="Datasets" *ngIf="reportService?.isUserReportAdmin()">
<div class="ui bottom attached small p-0 b-0 no-bg py-24 sb-table-responsive">
<table #allDatasets class="sb-table sb-table-hover sb-table-striped sb-table-sortable width-100">
</table>
</div>
</mat-tab>
</mat-tab-group>
</div>
<div>
<app-tnc-popup [showAcceptTnc]="showTncPopup" [reportViewerTncVersion]="reportViewerTncVersion" [tncUrl]="reportViewerTncUrl" #termsAndCondPopUp *ngIf="showTncPopup">
</app-tnc-popup>
</div>
</ng-container>
<ng-template #noResult>
<app-no-result [data]="{messageText: noResultFoundError}"></app-no-result>
</ng-template>
</div>
</ng-container>
<ng-template #loading>
<app-loader></app-loader>
</ng-template>
</div>
</div>
./list-all-reports.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.sbgrid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(292px, 1fr));
grid-gap: 1rem;
}
@media screen and (max-width: 1024px) {
.sb__DesktopOnly {
display: none;
}
}
:host{
.ui.tabular.menu.report-menu .item{
width: 50%;
display: flex;
justify-content: center;
}
}
:host::ng-deep {
.listallreports-section {
.dataTables_wrapper .dataTables_filter input {
outline: 0;
background-color: var(--white) !important;
}
.sb-table .sb-table-striped tbody tr:nth-child(2n) {
background-color: var(--primary-0);
}
}
}