src/app/modules/program-dashboard/components/program-datasets/program-datasets.component.ts
OnInit
OnDestroy
selector | app-datasets |
styleUrls | ./program-datasets.component.scss |
templateUrl | ./program-datasets.component.html |
constructor(activatedRoute: ActivatedRoute, layoutService: LayoutService, telemetryService: TelemetryService, resourceService: ResourceService, kendraService: KendraService, userService: UserService, onDemandReportService: OnDemandReportService, config: ConfigService, toasterService: ToasterService, formService: FormService, router: Router, location: Location, reportService: ReportService)
|
||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
addFilters |
addFilters()
|
Returns :
void
|
blockChanged | ||||
blockChanged($event)
|
||||
Parameters :
Returns :
void
|
checkStatus |
checkStatus()
|
Returns :
boolean
|
Private closeConfirmationModal |
closeConfirmationModal()
|
Returns :
void
|
Public closeConfirmModal |
closeConfirmModal()
|
Returns :
void
|
closeDashboard |
closeDashboard()
|
Returns :
void
|
Public closeModal |
closeModal()
|
Returns :
void
|
confirm |
confirm()
|
Returns :
void
|
Private convertHTMLToCanvas | ||||||
convertHTMLToCanvas(element, options)
|
||||||
Parameters :
Returns :
any
|
Public csvRequest |
csvRequest()
|
Returns :
void
|
dataFilterQuery | ||||||
dataFilterQuery(filterKeysObj, keys)
|
||||||
Parameters :
Returns :
void
|
dataModification | ||||
dataModification(row)
|
||||
Parameters :
Returns :
any
|
dateChanged | ||||||
dateChanged($event, type)
|
||||||
Parameters :
Returns :
void
|
dependentFilterMsg |
dependentFilterMsg()
|
Returns :
void
|
districtSelection | ||||
districtSelection($event)
|
||||
Parameters :
Returns :
void
|
downloadReport | ||||
downloadReport(reportType)
|
||||
Parameters :
Returns :
void
|
downloadReportAsImage |
downloadReportAsImage()
|
Returns :
void
|
downloadReportAsPdf |
downloadReportAsPdf()
|
Returns :
void
|
fetchConfig | ||||
fetchConfig(filters)
|
||||
Parameters :
Returns :
Observable<any>
|
getDataSourceById | ||||||||||||
getDataSourceById(dataSources: literal type[], id: string)
|
||||||||||||
Parameters :
Returns :
any
|
getDistritAndOrganisationList | ||||||
getDistritAndOrganisationList(requestBody: ResourceAPIRequestBody)
|
||||||
Parameters :
Returns :
void
|
Public getFormDetails |
getFormDetails()
|
Returns :
void
|
getProgramsList |
getProgramsList()
|
Returns :
void
|
Public getReportTypes | ||||||
getReportTypes(programId, solutionType)
|
||||||
Parameters :
Returns :
void
|
getSolutionList | ||||
getSolutionList(program)
|
||||
Parameters :
Returns :
void
|
getTableData | |||||||||
getTableData(data: literal type[], tableId)
|
|||||||||
Parameters :
Returns :
any
|
Public getUpdatedParameterizedPath | ||||
getUpdatedParameterizedPath(dataSources)
|
||||
Parameters :
Returns :
any
|
goBack |
goBack()
|
Returns :
void
|
Public handleConfirmationEvent | ||||||
handleConfirmationEvent(event: boolean)
|
||||||
Parameters :
Returns :
void
|
hashTheTag | ||||||
hashTheTag(key: string)
|
||||||
Parameters :
Returns :
string
|
initLayout |
initLayout()
|
Returns :
void
|
loadReports |
loadReports()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onDownloadLinkFail | ||||
onDownloadLinkFail(data)
|
||||
Parameters :
Returns :
void
|
organisationSelection | ||||
organisationSelection($event)
|
||||
Parameters :
Returns :
void
|
pdFilterChanged | ||||
pdFilterChanged($event)
|
||||
Parameters :
Returns :
void
|
prepareTableData |
prepareTableData(tablesArray: any, data: any, downloadUrl: string)
|
Returns :
Array<literal type>
|
Public programSelection | ||||
programSelection($event)
|
||||
Parameters :
Returns :
void
|
renderReport | ||||
renderReport(reportId)
|
||||
Parameters :
Returns :
Observable<any>
|
reportChanged | ||||
reportChanged(selectedReportData)
|
||||
Parameters :
Returns :
void
|
Public requestDataset |
requestDataset()
|
Returns :
void
|
resetConfigFilters |
resetConfigFilters()
|
Returns :
void
|
Public resetFilter |
resetFilter()
|
Returns :
void
|
Public resolveParameterizedPath |
resolveParameterizedPath(path: string, explicitValue?: string)
|
Returns :
string
|
selectedTabChange | ||||
selectedTabChange(event)
|
||||
Parameters :
Returns :
void
|
Public selectSolution | ||||
selectSolution($event)
|
||||
Parameters :
Returns :
void
|
submitRequest |
submitRequest()
|
Returns :
void
|
timeRangeInit |
timeRangeInit()
|
Returns :
void
|
Private toggleHtmlVisibilty | ||||||
toggleHtmlVisibilty(flag: boolean)
|
||||||
Parameters :
Returns :
void
|
Public activatedRoute |
Type : ActivatedRoute
|
appliedFilters |
Type : object
|
Default value : {}
|
awaitPopUp |
Default value : false
|
blocks |
Type : object[]
|
Default value : []
|
chartsReportData |
Type : any
|
config |
configuredFilters |
Type : any
|
Default value : {}
|
Public dashboardReport$ |
displayFilters |
Type : any
|
Default value : {}
|
districts |
Type : any
|
downloadCSV |
Default value : true
|
errorMessage |
Default value : this.resourceService?.frmelmnts?.lbl?.resourceSelect
|
exportOptions |
Type : []
|
Default value : ['Pdf', 'Img']
|
filter |
Type : any
|
Default value : []
|
formData |
Type : Object
|
Public formService |
Type : FormService
|
globalDistrict |
Type : any
|
globalOrg |
Type : any
|
goToPrevLocation |
Type : boolean
|
Default value : true
|
hashedTag |
hideElements |
Type : boolean
|
Default value : false
|
hideTableToCsv |
Type : boolean
|
Default value : true
|
instance |
Type : string
|
isColumnsSearchable |
Default value : false
|
Public isProcessed |
Default value : false
|
Public kendraService |
Type : KendraService
|
layoutConfiguration |
Type : any
|
Public layoutService |
Type : LayoutService
|
loadash |
Default value : _
|
Public location |
Type : Location
|
maxEndDate |
Type : any
|
maxStartDate |
Type : any
|
Public message |
Default value : this.resourceService?.frmelmnts?.msg?.noDataDisplayed
|
minEndDate |
Type : any
|
modal |
Decorators :
@ViewChild('modal', {static: false})
|
newData |
Type : boolean
|
Default value : false
|
Public noResult |
Type : boolean
|
Public noResultMessage |
Type : INoResultMessage
|
oldProgram |
Public onDemandReportData |
Type : []
|
Default value : []
|
Public onDemandReportService |
Type : OnDemandReportService
|
organisations |
Type : any
|
Default value : []
|
pdFilters |
Type : ConfigFilter[]
|
Default value : []
|
popup |
Default value : false
|
programs |
Type : []
|
Default value : []
|
programSelected |
Type : any
|
reportConfig |
Type : any
|
Public reportExportInProgress |
Default value : false
|
reportSection |
Decorators :
@ViewChild('reportSection')
|
Public reportService |
Type : ReportService
|
reportStatus |
Type : object
|
Default value : {
'submitted': 'SUBMITTED',
'processing': 'PROCESSING',
'failed': 'FAILED',
'success': 'SUCCESS',
}
|
reportTypes |
Type : []
|
Default value : []
|
Public resourceService |
Type : ResourceService
|
Public router |
Type : Router
|
Public selectedReport |
Public selectedSolution |
Type : string
|
Public showConfirmationModal |
Default value : false
|
showErrorForGraphs |
Type : boolean
|
Default value : false
|
showPopUpModal |
Type : boolean
|
solutions |
Type : []
|
Default value : []
|
solutionSelected |
Type : any
|
solutionType |
Type : any
|
tabIndex |
Type : number
|
Default value : 0
|
tableToCsv |
Type : boolean
|
tag |
Type : string
|
Public telemetryService |
Type : TelemetryService
|
Public toasterService |
Type : ToasterService
|
Public unsubscribe$ |
Default value : new Subject<void>()
|
Public userAccess |
Type : boolean
|
userDataSubscription |
Type : Subscription
|
Public userId |
Type : string
|
userProfile |
Type : IUserProfile
|
Reference of User Profile interface |
Public userRoles |
Type : Array<string>
|
Default value : []
|
all user role |
Public userService |
Type : UserService
|
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { INoResultMessage, ToasterService, IUserData, IUserProfile, LayoutService, ResourceService, ConfigService, OnDemandReportService } from '@sunbird/shared';
import { TelemetryService } from '@sunbird/telemetry';
import { Subject, Subscription, throwError ,Observable, of, combineLatest, queueScheduler} from 'rxjs';
import { KendraService, UserService, FormService } from '@sunbird/core';
import { mergeMap, switchMap, takeUntil,map, catchError} from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms';
import * as _ from 'lodash-es';
import { Location } from '@angular/common';
import { ReportService } from '../../../dashboard/services';
import dayjs from 'dayjs';
import html2canvas from 'html2canvas';
import * as jspdf from 'jspdf';
import { Md5 } from 'ts-md5';
import { HttpErrorResponse } from '@angular/common/http';
const PRE_DEFINED_PARAMETERS = ['$slug', 'hawk-eye'];
export interface ConfigFilter{
label: string,
controlType: string,
reference: string,
defaultValue: number
}
export interface ResourceAPIRequestBody{
type:string,
id:string,
projection:string,
solutionType?:string,
districtLocationId?:string
}
@Component({
selector: 'app-datasets',
templateUrl: './program-datasets.component.html',
styleUrls: ['./program-datasets.component.scss'],
})
export class DatasetsComponent implements OnInit, OnDestroy {
public activatedRoute: ActivatedRoute;
public showConfirmationModal = false;
public dashboardReport$;
public noResultMessage: INoResultMessage;
public noResult: boolean;
showPopUpModal: boolean;
config;
reportTypes = [];
programs = [];
solutions = [];
public message = this.resourceService?.frmelmnts?.msg?.noDataDisplayed;
instance: string;
@ViewChild('reportSection') reportSection;
public reportExportInProgress = false;
@ViewChild('modal', { static: false }) modal;
popup = false;
awaitPopUp = false;
reportStatus = {
'submitted': 'SUBMITTED',
'processing': 'PROCESSING',
'failed': 'FAILED',
'success': 'SUCCESS',
};
public isProcessed = false;
formData: Object;
public columns = [
{ name: 'Report type', isSortable: true, prop: 'datasetConfig.title', placeholder: 'Filter report type' },
{ name: 'Request date', isSortable: true, prop: 'jobStats.dtJobSubmitted', placeholder: 'Filter request date', type: 'date' },
{ name: 'Status', isSortable: false, prop: 'status', placeholder: 'Filter status' },
{ name: 'Report link', isSortable: false, prop: 'downloadUrls', placeholder: 'Filter download link' },
{ name: 'Generated date', isSortable: true, prop: 'jobStats.dtJobCompleted', placeholder: 'Filter generated date', type: 'dateTime' },
];
public onDemandReportData = [];
downloadCSV = true;
isColumnsSearchable = false;
tag: string;
reportForm = new UntypedFormGroup({
programName: new UntypedFormControl('', [Validators.required]),
solution: new UntypedFormControl(),
reportType: new UntypedFormControl('', [Validators.required]),
districtName: new UntypedFormControl(),
organisationName: new UntypedFormControl(),
startDate: new UntypedFormControl(),
endDate: new UntypedFormControl(),
blockName:new UntypedFormControl()
});
passwordForm = new UntypedFormGroup({
password: new UntypedFormControl('', [Validators.minLength(8), Validators.required, Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$')])
});
programSelected: any;
solutionSelected: any;
districts: any;
organisations: any = [];
filter: any = [];
newData: boolean = false;
goToPrevLocation: boolean = true;
reportConfig: any;
chartsReportData: any;
exportOptions = ['Pdf', 'Img'];
hideElements: boolean = false;
globalDistrict: any;
globalOrg: any;
tabIndex: number = 0;
tableToCsv: boolean;
hideTableToCsv:boolean = true;
minEndDate: any; //Min end date - has to be one more than start date
maxEndDate: any; //Max end date - current date has to be max
maxStartDate: any; //Start date - has to be one day less than end date
displayFilters:any = {};
loadash = _;
pdFilters:ConfigFilter[] = [];
configuredFilters:any = {};
appliedFilters:object = {};
blocks:object[] = [];
errorMessage = this.resourceService?.frmelmnts?.lbl?.resourceSelect;
solutionType: any;
showErrorForGraphs: boolean = false;
constructor(
activatedRoute: ActivatedRoute,
public layoutService: LayoutService,
public telemetryService: TelemetryService,
public resourceService: ResourceService,
public kendraService: KendraService,
public userService: UserService,
public onDemandReportService: OnDemandReportService,
config: ConfigService,
public toasterService: ToasterService,
public formService: FormService,
public router: Router,
public location: Location,
public reportService: ReportService
) {
this.config = config;
this.activatedRoute = activatedRoute;
}
layoutConfiguration: any;
public unsubscribe$ = new Subject<void>();
userDataSubscription: Subscription;
/**
* Reference of User Profile interface
*/
userProfile: IUserProfile;
/**
* all user role
*/
public userRoles: Array<string> = [];
public userId: string;
public selectedReport;
public selectedSolution: string;
public userAccess:boolean;
hashedTag;
oldProgram;
getProgramsList() {
const paramOptions = {
url:
this.config.urlConFig.URLS.KENDRA.PROGRAMS_BY_PLATFORM_ROLES + '?role=' + this.userRoles.toString()
};
this.kendraService.get(paramOptions).pipe(takeUntil(this.unsubscribe$)).subscribe(data => {
if (data && data.result) {
this.programs = data.result;
}
}, error => {
this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
});
}
getSolutionList(program) {
const paramOptions = {
url:
this.config.urlConFig.URLS.KENDRA.SOLUTIONS_BY_PROGRAMID + '/' + program._id + '?role=' + program.role[0]
};
this.kendraService.get(paramOptions).pipe(takeUntil(this.unsubscribe$)).subscribe(data => {
if (data && data.result) {
this.solutions = data.result;
}
}, error => {
this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
});
}
getDistritAndOrganisationList(requestBody:ResourceAPIRequestBody) {
const paramOptions = {
url:
this.config.urlConFig.URLS.KENDRA.DISTRICTS_AND_ORGANISATIONS+`?resourceType=${requestBody.type}&resourceId=${requestBody.id}`,
data: {
projection: requestBody.projection,
...(requestBody.solutionType) && {solutionType:requestBody.solutionType},
...(requestBody.districtLocationId) && {query : {districtLocationId:requestBody.districtLocationId}},
programId: _.get(this.reportForm, 'controls.programName.value')
}
};
this.kendraService.post(paramOptions).pipe(takeUntil(this.unsubscribe$)).subscribe(data => {
if (data && Object.keys(data.result).length) {
const processData = (result) => {
if (result) {
return result.filter(data => data?.name !== null);
}
return []
};
if(requestBody.projection !== 'block'){
this.organisations = processData(data.result.organisations);
this.districts = processData(data.result.districts);
}
this.blocks = processData(data.result.block);
}
}, error => {
this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
});
}
initLayout() {
this.layoutConfiguration = this.layoutService.initlayoutConfig();
this.layoutService.switchableLayout().pipe(takeUntil(this.unsubscribe$)).subscribe(layoutConfig => {
if (layoutConfig != null) {
this.layoutConfiguration = layoutConfig.layout;
}
});
}
ngOnInit() {
this.showPopUpModal = true;
this.instance = _.upperCase(this.resourceService.instance || 'SUNBIRD');
this.userDataSubscription = this.userService.userData$.subscribe(
(user: IUserData) => {
if (user && !user.err) {
this.userProfile = user.userProfile;
this.userRoles = user.userProfile.userRoles;
this.userId = user.userProfile.id;
}
});
this.initLayout();
this.getProgramsList();
this.getFormDetails();
this.timeRangeInit();
}
timeRangeInit() {
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth();
const today = new Date().getDate();
this.minEndDate = new Date(currentYear - 100, 0, 1);
this.maxEndDate = new Date(currentYear + 0, currentMonth, today);
this.maxStartDate = new Date(currentYear + 0, currentMonth, today - 1);
}
public resolveParameterizedPath(path: string, explicitValue?: string): string {
return _.reduce(PRE_DEFINED_PARAMETERS, (result: string, parameter: string) => {
if (_.includes(result, parameter)) {
result = _.replace(result, parameter, explicitValue);
}
return result;
}, path);
}
public getUpdatedParameterizedPath(dataSources) {
const explicitValue = !this.reportForm.controls.solution.value ? _.get(this.reportForm, 'controls.programName.value') : _.get(this.reportForm, 'controls.solution.value')
return _.map(dataSources, (dataSource) => ({
id: dataSource.id,
path: this.resolveParameterizedPath(dataSource.path, explicitValue)
}));
}
selectedTabChange(event) {
this.tabIndex = event.index;
}
public programSelection($event) {
this.reportForm.reset();
this.displayFilters = {};
const program = this.programs.filter(data => {
if (data._id == $event.value) {
return data;
}
});
this.solutions = [];
this.reportTypes = [];
this.onDemandReportData = [];
this.resetConfigFilters();
this.getSolutionList(program[0]);
this.displayFilters['Program'] = [program[0].name]
this.reportForm.controls.programName.setValue($event.value);
this.appliedFilters = {};
this.districts = this.organisations = this.blocks = [];
this.errorMessage = this.resourceService?.frmelmnts?.lbl?.resourceSelect;
this.getReportTypes($event.value,'user_detail_report');
this.oldProgram = !_.has(program[0],'requestForPIIConsent')
this.userAccess = this.reportTypes.length > 0 && _.has(program[0],'requestForPIIConsent');
if(this.userAccess){
this.tag = program[0]._id + '_' + this.userId;
this.hashedTag = this.hashTheTag(this.tag)
this.loadReports();
}
this.newData = !this.userAccess;
this.showErrorForGraphs = false;
const requestBody:ResourceAPIRequestBody= {
type:'program',
id:$event.value,
projection:'district'
}
this.getDistritAndOrganisationList(requestBody);
}
public selectSolution($event) {
this.newData = false;
this.showErrorForGraphs = false;
this.noResult = false;
this.districts = this.organisations = []
this.userAccess = true;
this.resetConfigFilters();
delete this.displayFilters['District'];
delete this.displayFilters['Organisation'];
this.errorMessage = this.resourceService?.frmelmnts?.lbl?.resourceSelect;
this.appliedFilters = {}
if (this.programSelected && this.reportForm.value && this.reportForm.value['solution']) {
const solution = this.solutions.filter(data => {
if (data._id == $event.value) {
return data;
}
});
this.tag = solution[0]._id + '_' + this.userId;
this.hashedTag = this.hashTheTag(this.tag)
this.loadReports();
const program = this.programSelected;
this.reportForm.reset();
this.reportForm.controls.solution.setValue($event.value);
this.reportForm.controls.programName.setValue(program);
this.displayFilters['Resource'] = [$event?.source?.triggerValue]
if (solution[0].isRubricDriven === true && solution[0].type === 'observation') {
const type = solution[0].criteriaLevelReport ? solution[0].type + '_with_rubric' : solution[0].type + '_with_rubric_no_criteria_level_report'
this.getReportTypes(this.programSelected, type);
} else {
this.getReportTypes(this.programSelected, solution[0].type);
}
this.solutionType = solution[0].type
const requestBody:ResourceAPIRequestBody = {
type:'solution',
id:$event.value,
projection:'district',
solutionType:this.solutionType
}
this.getDistritAndOrganisationList(requestBody);
}
}
public getReportTypes(programId, solutionType) {
this.reportTypes = [];
let selectedProgram = this.programs.filter(program => program._id == programId);
if (selectedProgram && selectedProgram[0]) {
let role = selectedProgram[0]['role'];
let types = this.formData[solutionType];
let filtersForReport = {
"reportconfig.report_type": "program_dashboard",
"reportconfig.solution_type": `${(solutionType === 'improvementProject') ? "project" : solutionType}`,
"reportconfig.report_status": "active"
}
this.dashboardReport$ = this.renderReport(filtersForReport).pipe(
catchError(err => {
console.error('Error while rendering report', err);
this.noResultMessage = {
'messageText': _.get(err, 'messageText') || 'messages.stmsg.m0131'
};
this.noResult = true;
return of({});
})
);
if (types && types.length > 0) {
types.forEach(element => {
let roleMatch = role.some(e => element.roles.includes(e));
if (roleMatch) {
this.reportTypes.push(element);
}
});
}
}
}
fetchConfig(filters): Observable<any> {
return this.reportService.listAllReports(filters).pipe(
mergeMap(apiResponse => {
const report = _.get(apiResponse, 'reports');
return report ? of(_.head(report)) : throwError('No report found');
})
);
}
renderReport(reportId): Observable<any> {
return this.fetchConfig(reportId).pipe(switchMap(
(report => {
const reportConfig = this.reportConfig = _.get(report, 'reportconfig');
const dataSource = _.get(reportConfig, 'dataSource') || [];
let updatedDataSource = _.isArray(dataSource) ? dataSource : [{ id: 'default', path: dataSource }];
updatedDataSource = this.getUpdatedParameterizedPath(updatedDataSource);
const charts = _.get(reportConfig, 'charts'), tables = _.get(reportConfig, 'table')
return this.reportService.downloadMultipleDataSources(updatedDataSource).pipe(map((apiResponse) => {
const data = apiResponse;
const result: any = Object.assign({});
const chart = (charts && this.reportService.prepareChartData(charts, data, updatedDataSource,
_.get(reportConfig, 'reportLevelDataSourceId'))) || [];
result['charts'] = chart;
result['tables'] = (tables && this.prepareTableData(tables, data, _.get(reportConfig, 'downloadUrl'))) || [];
this.hideTableToCsv = (result?.tables[0]?.data != undefined) ? true : false;
result['reportMetaData'] = reportConfig;
result['lastUpdatedOn'] = this.reportService.getFormattedDate(this.reportService.getLatestLastModifiedOnDate(data));
this.chartsReportData = JSON.parse(JSON.stringify(result));
return result;
}))
})
))
}
prepareTableData(tablesArray: any, data: any, downloadUrl: string): Array<{}> {
tablesArray = _.isArray(tablesArray) ? tablesArray : [tablesArray];
return _.map(tablesArray, table => {
const tableId = _.get(table, 'id') || `table-${_.random(1000)}`;
const dataset = this.getTableData(data, _.get(table, 'id'));
const tableData: any = {};
tableData.id = tableId;
tableData.name = _.get(table, 'name') || 'Table';
tableData.config = _.get(table, 'config') || false;
tableData.data = dataset.data;
let columns = []
tableData.header = _.get(table, 'columns') || _.get(dataset, _.get(table, 'columnsExpr'));
tableData.header && tableData.header.map((col) => {
let obj = { title: col, data: col }
columns.push(obj);
})
tableData.columnsConfiguration = {
columnConfig: columns,
bLengthChange: true,
info: true,
lengthMenu: [10, 25, 50, 100],
paging: true,
searchable: true
}
tableData.downloadUrl = this.resolveParameterizedPath(_.get(table, 'downloadUrl') || downloadUrl, (this.userAccess && !this.reportForm.controls.solution.value ? _.get(this.reportForm, 'controls.programName.value') : _.get(this.reportForm, 'controls.solution.value')));
return tableData;
});
}
getTableData(data: { result: any, id: string }[], tableId) {
if (data.length === 1) {
const [dataSource] = data;
if (dataSource.id === 'default') {
return dataSource.result;
}
}
return this.getDataSourceById(data, tableId) || {};
}
getDataSourceById(dataSources: { result: any, id: string }[], id: string = 'default') {
return _.get(_.find(dataSources, ['id', id]), 'result');
}
downloadReport(reportType) {
this.reportExportInProgress = true;
this.toggleHtmlVisibilty(true);
setTimeout(() => {
switch (_.toLower(_.get(reportType, 'value'))) {
case 'img': {
this.downloadReportAsImage();
break;
}
case 'pdf': {
this.downloadReportAsPdf();
break;
}
}
})
}
private convertHTMLToCanvas(element, options) {
return html2canvas(element, options);
}
downloadReportAsPdf() {
this.convertHTMLToCanvas(this.reportSection.nativeElement, {
scrollX: 0,
scrollY: -window.scrollY,
scale: 2
}).then(canvas => {
const imageURL = canvas.toDataURL('image/jpeg');
const pdfFormat = new jspdf('p', 'px', 'a4');
const docWidth = pdfFormat.internal.pageSize.getWidth();
const imageHeight = (canvas.height * docWidth) / canvas.width;
pdfFormat.internal.pageSize.setHeight(imageHeight);
pdfFormat.addImage(imageURL, 'JPEG', 10, 8, docWidth - 28, imageHeight - 24);
pdfFormat.save('report.pdf');
this.toggleHtmlVisibilty(false);
this.reportExportInProgress = false;
}).catch(_err => {
this.toggleHtmlVisibilty(false);
this.reportExportInProgress = false;
});
}
downloadReportAsImage() {
this.convertHTMLToCanvas(this.reportSection.nativeElement, {
scrollX: 0,
scrollY: -window.scrollY,
scale: 2
}).then(canvas => {
const imageURL = canvas.toDataURL('image/jpeg');
const anchorElement = document.createElement('a');
anchorElement.href = imageURL.replace('image/jpeg', 'image/octet-stream');
anchorElement.download = 'report.jpg';
anchorElement.click();
this.toggleHtmlVisibilty(false);
this.reportExportInProgress = false;
}).catch(_err => {
this.toggleHtmlVisibilty(false);
this.reportExportInProgress = false;
});
}
private toggleHtmlVisibilty(flag: boolean): void {
this.hideElements = flag;
}
public closeModal(): void {
this.popup = false;
}
public csvRequest() {
this.popup = false;
this.submitRequest();
}
public requestDataset() {
if (this.selectedReport.encrypt == true) {
this.popup = true;
} else {
this.showConfirmationModal = true;
}
}
private closeConfirmationModal() {
this.showConfirmationModal = false;
}
goBack() {
this.goToPrevLocation ? this.location.back() : (this.showPopUpModal = false);
}
confirm() {
this.showPopUpModal = false;
}
public handleConfirmationEvent(event: boolean) {
this.closeConfirmationModal();
if (event == true) {
this.submitRequest();
}
}
public closeConfirmModal() {
this.awaitPopUp = false;
}
public resetFilter() {
this.reportForm.reset();
this.filter = [];
this.districts = [];
this.organisations = [];
this.solutions = [];
this.reportTypes = [];
this.onDemandReportData = [];
this.goToPrevLocation = false;
this.showPopUpModal = true;
this.appliedFilters = {}
this.displayFilters = {};
this.timeRangeInit();
this.resetConfigFilters();
}
loadReports() {
const requestWithUnhashedTag = this.onDemandReportService.getReportList(this.tag);
const requestWithHashedTag = this.onDemandReportService.getReportList(this.hashedTag);
combineLatest([
requestWithHashedTag.pipe(catchError((err) => of(err))),
requestWithUnhashedTag.pipe(catchError((err) => of(err))),
])
.pipe(
map(([response1, response2]: [any, any]) => {
const jobs1 = response1 instanceof HttpErrorResponse ? null : response1?.result?.jobs || null;
const jobs2 = response2 instanceof HttpErrorResponse ? null : response2?.result?.jobs || null;
if (jobs1 === null && jobs2 === null) {
throw new Error("Both job requests failed");
}
const jobs = _.compact(_.concat(jobs1, jobs2));
return jobs;
}),
catchError((error) => {
this.toasterService.error(
_.get(this.resourceService, "messages.fmsg.m0004")
);
return throwError("Report list APIs failed", queueScheduler);
}),
takeUntil(this.unsubscribe$)
)
.subscribe((reportData: object[]) => {
this.onDemandReportData = reportData.length
? _.map(reportData, (row) => this.dataModification(row))
: [];
});
}
districtSelection($event) {
this.newData = false;
this.showErrorForGraphs = false
this.appliedFilters = {...this.appliedFilters, district_externalId: $event.value}
this.reportForm.controls.districtName.setValue($event.value);
this.errorMessage = this.resourceService?.frmelmnts?.lbl?.resourceSelect;
this.displayFilters['District'] = [$event?.source?.triggerValue];
const requestBody:ResourceAPIRequestBody = {
type:_.get(this.reportForm, 'controls.solution.value') ? 'solution' : 'program',
id:_.get(this.reportForm, 'controls.solution.value') || _.get(this.reportForm, 'controls.programName.value'),
projection:'block',
districtLocationId:$event.value,
...(_.get(this.reportForm, 'controls.solution.value')) && {solutionType : this.solutionType}
}
this.getDistritAndOrganisationList(requestBody);
const tagBasedOnUserAccess = (this.userAccess ? _.get(this.reportForm, 'controls.programName.value') : _.get(this.reportForm, 'controls.solution.value'))
this.tag = tagBasedOnUserAccess + '_' + this.userId+'_'+ _.toLower(_.trim([$event?.source?.triggerValue]," "));
this.hashedTag = this.hashTheTag( tagBasedOnUserAccess + '_' + this.userId+'_'+ $event.value);
this.loadReports();
}
organisationSelection($event) {
this.appliedFilters= {...this.appliedFilters, organisation_id:$event.value}
this.reportForm.controls.organisationName.setValue($event.value);
this.displayFilters['Organisation'] = [$event?.source?.triggerValue]
this.newData = false;
this.showErrorForGraphs = false;
this.errorMessage = this.resourceService?.frmelmnts?.lbl?.resourceSelect;
}
blockChanged($event){
this.reportForm.controls.blockName.setValue($event.value)
if($event.value.length){
this.appliedFilters = {...this.appliedFilters, block_externalId:$event.value};
this.displayFilters['Block'] = [$event?.source?.triggerValue];
const tagBasedOnUserAccess = (this.userAccess ? _.get(this.reportForm, 'controls.programName.value') : _.get(this.reportForm, 'controls.solution.value'))
this.tag = tagBasedOnUserAccess + '_' + this.userId+'_'+ _.get(this.reportForm, 'controls.districtName.value') + ($event.value).sort();
this.hashedTag = this.hashTheTag(this.tag);
this.loadReports();
}else{
delete this.appliedFilters['block_externalId']
this.appliedFilters = { ...this.appliedFilters }
}
}
dependentFilterMsg(){
if(!this.reportForm.controls.districtName.value){
this.newData = true;
this.errorMessage = this.resourceService?.frmelmnts?.lbl?.blockWithoutDistrict;
this.showErrorForGraphs = true;
}
}
reportChanged(selectedReportData) {
this.resetConfigFilters();
this.selectedReport = selectedReportData;
if(this.selectedReport.configurableFilters){
this.pdFilters = this.selectedReport.uiFilters;
this.pdFilters.map(filter => {
if(filter['controlType'] === 'number'){
this.configuredFilters[filter['reference']] = filter['defaultValue'] as number -1
}else if(filter['controlType'] === 'multi-select'){
this.configuredFilters[filter['reference']] = undefined
}
})
}
}
resetConfigFilters(){
this.pdFilters = [];
this.configuredFilters = {};
}
pdFilterChanged($event){
if($event.data){
const [reference, value]= [Object.keys($event.data),Object.values($event.data)] ;
if($event.controlType === 'number'){
if([0,null].includes(value[0] as number) || value[0] as number < 0){
this.configuredFilters[reference[0]] = undefined;
}else{
this.configuredFilters[reference[0]] = value[0] as number -1;
}
}else if($event.controlType === 'multi-select'){
if((value[0] as string[]).length){
this.configuredFilters[reference[0]] = value[0]
}else{
this.configuredFilters[reference[0]] = undefined;
}
}
}
}
addFilters() {
this.pdFilters.map(filter => {
if(filter['controlType'] === 'multi-select' && this.configuredFilters[filter['reference']] === undefined){
this.configuredFilters[filter['reference']] = filter['options']
}
})
const filterKeysObj = {
"program_id": _.get(this.reportForm, 'controls.programName.value') || undefined,
"solution_id": _.get(this.reportForm, 'controls.solution.value') || undefined,
"programId": _.get(this.reportForm, 'controls.programName.value') || undefined,
"solutionId": _.get(this.reportForm, 'controls.solution.value') || undefined,
"district_externalId": _.get(this.reportForm, 'controls.districtName.value') || undefined,
"district_id":_.get(this.reportForm, 'controls.districtName.value') || undefined,
"organisation_id": _.get(this.reportForm, 'controls.organisationName.value') || undefined,
"object_id":_.get(this.reportForm, 'controls.programName.value') || undefined,
"user_locations['district_id']":_.get(this.reportForm, 'controls.districtName.value') || undefined,
'>=':_.get(this.reportForm,'controls.startDate.value') || undefined,
'<=':_.get(this.reportForm,'controls.endDate.value') || undefined,
...this.configuredFilters
}
const keys = Object.keys(filterKeysObj);
this.dataFilterQuery(filterKeysObj,keys);
}
submitRequest() {
this.addFilters();
this.selectedSolution = this.reportForm.controls.solution.value;
const isRequestAllowed = this.checkStatus();
if (isRequestAllowed) {
this.isProcessed = false;
const config = {
type: this.selectedReport['datasetId'],
params: {
...((_.get(this.reportForm, 'controls.startDate.value') && _.get(this.reportForm, 'controls.solution.value')) && { 'start_date': _.get(this.reportForm, 'controls.startDate.value') }),
...((_.get(this.reportForm, 'controls.endDate.value') && _.get(this.reportForm, 'controls.solution.value') ) && { 'end_date': _.get(this.reportForm, 'controls.endDate.value') }),
filters: this.filter
},
title: this.selectedReport.name
};
const request = {
request: {
dataset: this.selectedReport['dataset'],
tag: this.hashedTag,
requestedBy: this.userId,
datasetConfig: config,
output_format: 'csv'
}
};
if (this.selectedReport.encrypt === true) {
request.request['encryptionKey'] = this.passwordForm.controls.password.value;
}
this.onDemandReportService.submitRequest(request).subscribe((data: any) => {
if (data && data.result) {
if (data.result.status === this.reportStatus.failed) {
const error = _.get(this.resourceService, 'frmelmnts.lbl.reportRequestFailed');
this.toasterService.error(error);
} else {
if (data['result'] && data['result']['requestId']) {
const dataFound = this.onDemandReportData.filter(function (submittedReports) {
if (submittedReports['requestId'] == data['result']['requestId']) {
return data;
}
});
if (dataFound && dataFound.length > 0) {
this.popup = false;
this.isProcessed = true;
setTimeout(() => {
this.isProcessed = false;
}, 5000);
this.toasterService.error(_.get(this.resourceService, 'frmelmnts.lbl.reportRequestFailed'));
this.passwordForm.reset();
} else {
data = this.dataModification(data['result']);
const updatedReportList = [data, ...this.onDemandReportData];
this.onDemandReportData = updatedReportList;
this.awaitPopUp = true;
this.passwordForm.reset();
}
}
}
}
}, error => {
this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
});
this.filter = [];
} else {
this.popup = false;
this.isProcessed = true;
this.filter = [];
setTimeout(() => {
this.isProcessed = false;
}, 10000);
this.toasterService.error(_.get(this.resourceService, 'frmelmnts.lbl.reportRequestFailed'));
this.passwordForm.reset();
}
}
public getFormDetails() {
const formServiceInputParams = {
formType: 'program-dashboard',
formAction: 'reportData',
contentType: 'csv-dataset',
component: 'portal'
};
this.formService.getFormConfig(formServiceInputParams).subscribe((formData) => {
if (formData) {
this.formData = formData;
}
}, error => {
this.toasterService.error(this.resourceService.messages.emsg.m0005);
});
}
checkStatus() {
let requestStatus = true;
const selectedReportList = [];
_.forEach(this.onDemandReportData, (value) => {
if (value.datasetConfig.type === this.selectedReport.datasetId){
_.forEach(value.datasetConfig.params.filters, (filter) => {
const conditionForSolutionBasedReports = ['solutionId','solution_id'].includes(filter['dimension']) && filter.value === this.selectedSolution
const conditionForProgramBasedReports = ['object_id'].includes(filter?.table_filters?.[0]['name']) && filter?.table_filters?.[0].value === this.reportForm.controls.programName.value
if(conditionForSolutionBasedReports || conditionForProgramBasedReports){
selectedReportList.push(value);
}
});
}
});
const sortedReportList = _.sortBy(selectedReportList, [(data) => {
return data && data.jobStats && data.jobStats.dtJobSubmitted;
}]);
const reportListData = _.last(sortedReportList) || {};
if (!_.isEmpty(reportListData)) {
const isInProgress = this.onDemandReportService.isInProgress(reportListData, this.reportStatus);
if (!isInProgress) {
requestStatus = true;
} else {
requestStatus = false;
}
}
return requestStatus;
}
onDownloadLinkFail(data) {
const tagId = data && data.tag && data.tag.split(':');
this.onDemandReportService.getReport(_.head(tagId), data.requestId).subscribe((data: any) => {
if (data) {
const downloadUrls = _.get(data, 'result.downloadUrls') || [];
const downloadPath = _.head(downloadUrls);
if (downloadPath) {
window.open(downloadPath, '_blank');
} else {
this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
}
}
}, error => {
this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
});
}
dataModification(row) {
row.title = row.datasetConfig.title;
return row;
}
dateChanged($event, type) {
if (dayjs($event.value).isValid()) {
this.newData = false;
this.showErrorForGraphs = false;
this.errorMessage = this.resourceService?.frmelmnts?.lbl?.resourceSelect;
const year = new Date($event.value._d).getFullYear();
const month = new Date($event.value._d).getMonth();
const day = new Date($event.value._d).getDate();
if(type === 'startDate'){
this.minEndDate = new Date(year, month, day + 1);
}else{
this.maxStartDate = new Date(year, month, day - 1);
}
this.reportForm.controls[type].setValue(dayjs(_.get($event, 'value._d')).format('YYYY-MM-DD'));
}
}
closeDashboard(){
this.location.back()
}
dataFilterQuery(filterKeysObj,keys){
if(this.selectedReport['queryType'] === "cassandra"){
this.filter = _.cloneDeep(this.selectedReport['filters'])
_.map(this.filter, filterObj => {
_.remove(filterObj['table_filters'], filterItem => {
_.map(keys,key => {
(filterItem.name === key || filterItem.operator === key) && (filterItem.value = filterKeysObj[key])
})
return filterItem.value === undefined
})
})
}else{
this.selectedReport['filters'].map(data => {
keys.filter(key => {
return data.dimension === key && (_.has(data,'value') ? data.value = filterKeysObj[key] : data.values = filterKeysObj[key]);
})
if (data.value !== undefined || data.values !== undefined) {
this.filter.push(data);
}
});
}
}
hashTheTag(key:string):string{
return Md5.hashStr(key);
}
ngOnDestroy() {
if (this.userDataSubscription) {
this.userDataSubscription.unsubscribe();
}
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
}
<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 relative12'"
class="relative position mt-0">
<div class="py-0 d-flex flex-ai-center w-100">
<!-- /* Back button */ -->
<div class="mr-12">
<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)="closeDashboard()" id="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>
<div class="textbook d-flex flex-jc-space-between w-100">
<!-- title -->
<h4 class="textbook__title sb-color-primary font-weight-bold mt-8 ml-24" >{{resourceService?.frmelmnts?.lnk?.programDashboard}}</h4>
<div>
<button class="sb-btn sb-btn-primary sb-btn-normal px-24" (click)="closeDashboard()">
{{resourceService?.frmelmnts?.btn?.closedb}}
</button>
</div>
</div>
</div>
</div>
<div class="sbt-inside-page-container" #reportSection>
<mat-tab-group class="sb-mat__tab sb-mat__tab--tabinacc" (selectedTabChange)="selectedTabChange($event)">
<mat-tab appTelemetryInteract>
<ng-template mat-tab-label>
<span class="font-weight-bold">{{resourceService?.frmelmnts?.lbl?.programDatasets}}</span>
</ng-template>
<ng-container *ngTemplateOutlet="programDataset"></ng-container>
</mat-tab>
<ng-container *ngIf="!noResult && (dashboardReport$ | async) as currentReport">
<mat-tab appTelemetryInteract>
<ng-template mat-tab-label>
<span class="font-weight-bold">{{resourceService?.frmelmnts?.lbl?.graphs}}</span>
</ng-template>
<ng-container *ngTemplateOutlet="graphs;context:{$implicit:currentReport}"></ng-container>
</mat-tab>
<mat-tab *ngFor="let table of currentReport?.tables;">
<ng-template mat-tab-label>
<span class="font-weight-bold">{{table.name}}</span>
</ng-template>
<ng-container *ngTemplateOutlet="tables;context:{$implicit:table}"></ng-container>
</mat-tab>
</ng-container>
</mat-tab-group>
</div>
<ng-template #globalFilters>
<ng-container *ngIf="!hideElements">
<form class="sb-form" [formGroup]="reportForm">
<div class="d-flex">
<div class="d-flex flex-w-wrap flex-ai-center ml-32 col-gap">
<div class="d-flex flex-dc">
<label>{{resourceService?.frmelmnts?.lbl?.programLbl }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd">
<mat-select role="radio" class="selection" valueField="_id" formControlName="programName"
[(ngModel)]="programSelected"
[placeholder]="resourceService?.frmelmnts?.lbl?.program" (selectionChange)="programSelection($event)">
<mat-option *ngFor="let program of programs" class="mat-dropdown__options" role="option" [value]="program._id">
{{program.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="d-flex flex-dc">
<label>{{ resourceService?.frmelmnts?.lbl?.solutionLbl }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd">
<mat-select role="radio" class="selection" [(ngModel)]="solutionSelected" valueField="_id" formControlName="solution"
[placeholder]="resourceService?.frmelmnts?.lbl?.solution" (selectionChange)="selectSolution($event)">
<mat-option *ngFor="let solution of solutions" class="mat-dropdown__options" role="option" [value]="solution._id">
{{solution.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="d-flex flex-dc">
<label>{{ resourceService?.frmelmnts?.lbl?.dashboarddistrictLbl }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd">
<mat-select role="radio" class="selection" valueField="locationId" formControlName="districtName"
[placeholder]="resourceService?.frmelmnts?.lbl?.dashboarddistrict" (selectionChange)="districtSelection($event)">
<mat-option *ngFor="let district of districts" class="mat-dropdown__options" role="option" [value]="district.id">
{{district.name | titlecase }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf="tabIndex !== 2" class="d-flex flex-dc">
<label>{{ resourceService?.frmelmnts?.lbl?.block }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd" >
<mat-select role="radio" class="selection" valueField="locationId" multiple formControlName="blockName"
[placeholder]="resourceService?.frmelmnts?.lbl?.blockLabel" (selectionChange)="blockChanged($event)" (click)="dependentFilterMsg()" [disabled]="!reportForm.controls.districtName.value">
<mat-option *ngFor="let block of blocks" class="mat-dropdown__options custom_mat_multi" role="option" [value]="block.id">
{{block.name | titlecase}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="d-flex flex-dc">
<label>{{ resourceService?.frmelmnts?.lbl?.dashboardOrgLbl }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd">
<mat-select role="radio" class="selection" valueField="organisationId" formControlName="organisationName"
[placeholder]="resourceService?.frmelmnts?.lbl?.dashboardOrg" (selectionChange)="organisationSelection($event)">
<mat-option *ngFor="let organisation of organisations" class="mat-dropdown__options" role="option" [value]="organisation.id">
{{organisation.name | titlecase}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf="tabIndex !== 1 && tabIndex !== 2 && tabIndex !== 3" class="d-flex flex-dc customDate">
<label>{{resourceService?.frmelmnts?.lbl?.startdate | titlecase }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd sb-color-primary">
<input [disabled]="!reportForm.controls.programName.value" matInput placeholder="dd/mm/yyyy" [max]="maxStartDate" (dateInput)="dateChanged($event,'startDate')" (dateChange)="dateChanged($event,'startDate')" formControlName="startDate" [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker" class="sb-color-primary"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
<div *ngIf="tabIndex !== 1 && tabIndex !== 2 && tabIndex !== 3" class="d-flex flex-dc customDate">
<label>{{resourceService?.frmelmnts?.lbl?.enddate | titlecase }}</label>
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd sb-color-primary">
<input [disabled]="!reportForm.controls.programName.value" matInput placeholder="dd/mm/yyyy" [min]="minEndDate" [max]="maxEndDate" (dateInput)="dateChanged($event,'endDate')" (dateChange)="dateChanged($event,'endDate')" formControlName="endDate" [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker" class="sb-color-primary"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
<ng-container *ngIf="pdFilters.length && tabIndex !== 1 && tabIndex !== 2">
<ng-container *ngFor="let filter of pdFilters">
<app-pd-filters [pdFilter]="filter" (filterChanged)="pdFilterChanged($event)"></app-pd-filters>
</ng-container>
</ng-container>
</div>
<div class="d-flex flex-dc ml-auto btn-col">
<button type="button" class="sb-field sb-btn sb-btn-normal sb-btn-primary reset-filter flex-as-flex-end" (click)="resetFilter()">{{resourceService?.frmelmnts?.btn?.resetFilters}}</button>
<mat-form-field *ngIf="!noResult && (tabIndex == 1)" appearance="fill" class="sb-mat__dropdown custom_mat_dd">
<mat-select role="radio" class="selection" placeholder="Export as" (selectionChange)="downloadReport($event)" >
<mat-option class="mat-dropdown__options" role="option" *ngFor="let option of exportOptions" [value]="option"
attr.aria-label="{{option}}">{{option}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</form>
</ng-container>
<div class="sb-filter-label pt-16 pb-8" *ngIf="hideElements">
<div *ngFor="let key of loadash.keys(displayFilters)" class="d-inline-flex flex-w-wrap pr-10">
<span class="sb-label-name mb-4">{{key}}:</span><span class="sb-label-value"
*ngFor="let val of displayFilters[key]">{{val}}
</span>
</div>
</div>
</ng-template>
<ng-template #programDataset>
<ng-container *ngTemplateOutlet="globalFilters"></ng-container>
<div *ngIf="reportForm.controls.programName.value && (!userAccess|| (oldProgram && !reportForm.controls.solution.value) || newData)"class="newData">*{{errorMessage}}</div>
<div class="sbt-inside-page-container relative position mt-32">
<div>
<div>
<label>{{resourceService?.frmelmnts?.lbl?.detailsReports}}</label>
<hr>
</div>
<div [formGroup]="reportForm" class="mt-32">
<label>{{ resourceService?.frmelmnts?.lbl?.reportType }}</label>
<div class="d-flex flex-w-wrap flex-dr">
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd d-flex flex-ai-center w-auto" >
<mat-select role="listbox" formControlName="reportType" class="selection"
[placeholder]="resourceService?.frmelmnts?.lbl?.selectReport" [disabled]="!userAccess">
<mat-option role="option" *ngFor="let report of reportTypes" class="custom_mat_dd mat-dropdown__options" [value]="report?.name" (click)="reportChanged(report)">
{{report?.name}}
</mat-option>
</mat-select>
</mat-form-field>
<button [disabled]="(!reportForm.valid)"
[ngClass]="{'sb-btn-disabled': (!reportForm.valid)}"
type="button" class="sb-field sb-btn sb-btn-normal sb-btn-primary ml-12" (click)="requestDataset()">
{{resourceService?.frmelmnts?.btn?.requestReport}}
</button>
</div>
</div>
<div *ngIf="isProcessed" class="d-flex flex-ai-baseline mt-12">
<div class="information-icon">
<img src="assets/images/error-icon.svg" class="infoIcon"></div>
<p class="fsmall note-text my-8 administrator-text ml-12 sb-color-error">{{resourceService.frmelmnts?.lbl?.reportStatus}}</p>
</div>
<div class="fsmall font-weight-bold download-section-text mt-24">
{{resourceService.frmelmnts?.lbl?.downloadSectionNote}}</div>
<p class="fsmall mt-8 mb-16 administrator-text">{{resourceService?.frmelmnts?.lbl?.repgenProgramAdminNote | interpolate:'{instance}': instance }}</p>
<sb-datatable [message]="message" [data]="onDemandReportData" [columns]="columns"
[downloadCSV]="false" (downloadLink)="onDownloadLinkFail($event)"></sb-datatable>
</div>
</div>
</ng-template>
<ng-template #graphs let-currentReport>
<ng-container *ngTemplateOutlet="globalFilters" ></ng-container>
<div *ngIf="(oldProgram && newData) || (!oldProgram && showErrorForGraphs)" class="newData">*{{errorMessage}}</div>
<ng-container *ngIf="(oldProgram && reportForm.controls.solution.value && currentReport.charts.length) || (!oldProgram && currentReport.charts.length)">
<div class="sb-graph-section p-24 my-24"
*ngFor="let chart of currentReport.charts;">
<ng-container *ngIf="chart?.chartConfig?.id == 'Big_Number'">
<app-sb-bignumber [chart]="chart" [hideElements]="hideElements" [appliedFilters]="appliedFilters"></app-sb-bignumber>
</ng-container>
<ng-container *ngIf="chart?.chartConfig?.id !== 'Big_Number' && chart?.chartData && chart?.chartConfig">
<app-sb-chart [chart]="chart" [hideElements]="hideElements" [appliedFilters]="appliedFilters"></app-sb-chart>
</ng-container>
</div>
</ng-container>
<div class="ui warning message mt-16" *ngIf="(!reportForm.controls.solution.value && oldProgram) || !currentReport.charts.length">
{{resourceService?.frmelmnts?.lbl?.graphNotAvailable}}
</div>
<div *ngIf="noResult">
<app-no-result [data]="noResultMessage"></app-no-result>
</div>
<ng-template #loading>
<ng-container *ngIf="!noResult">
<div class="ui container">
<div class="nine wide column workspacesegment">
<app-loader></app-loader>
</div>
</div>
</ng-container>
</ng-template>
</ng-template>
<ng-template #tables let-table>
<ng-container *ngTemplateOutlet="globalFilters"></ng-container>
<div *ngIf="(oldProgram && newData) || (!oldProgram && !reportForm.controls.solution.value) || newData"class="newData">*{{errorMessage}}</div>
<div *ngIf="table?.data" class="sb-graph-section p-24 my-24">
<div class="customTable">
<app-sb-table [tableToCsv]="tableToCsv" [table]="table" [hideElements]="hideElements" [appliedFilters]="appliedFilters"></app-sb-table>
</div>
</div>
<div class="ui warning message mt-16" *ngIf="!table?.data">
{{resourceService?.frmelmnts?.lbl?.tableNotAvailable}}
</div>
<div *ngIf="noResult">
<app-no-result [data]="noResultMessage"></app-no-result>
</div>
<ng-template #loading>
<ng-container *ngIf="!noResult">
<div class="ui container">
<div class="nine wide column workspacesegment">
<app-loader></app-loader>
</div>
</div>
</ng-container>
</ng-template>
</ng-template>
<app-modal-wrapper [config]="{disableClose: false, size: 'small'}" (dismiss)="closeModal()" #modal *ngIf="popup">
<ng-template sbModalContent>
<div class="sb-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible small">
<div class="sb-modal-header">
{{resourceService?.frmelmnts?.lbl?.confirmReportRequest}}
</div>
<div class="sb-modal-content o-x-hide" [formGroup]="passwordForm">
<div class="sb-field-group">
<div class="sb-field relative">
<div class="sb-field filterTable mx-16 mb-0">
<input class="sb-form-control" formControlName="password" type="text"
placeholder="Enter a password to request Report" aria-label="enter password">
</div>
</div>
<p class="fsmall note-text my-8 administrator-text">
{{resourceService?.frmelmnts?.lbl?.pswdRule}}
</p>
</div>
</div>
<div class="sb-modal-actions">
<button class="sb-btn sb-btn-normal sb-btn-primary" [disabled]="(!reportForm.valid || !passwordForm.valid)"
[ngClass]="{'sb-btn-disabled': (!reportForm.valid || !passwordForm.valid)}" (click)="csvRequest()">
{{resourceService?.frmelmnts?.btn?.yes}}
</button>
<button class="sb-btn sb-btn-normal sb-btn-outline-primary" (click)="closeModal()">
{{resourceService?.frmelmnts?.btn?.no}}
</button>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper [config]="{disableClose: false, size: 'small'}" (dismiss)="closeConfirmModal()" #modal
*ngIf="awaitPopUp">
<ng-template sbModalContent>
<div class="sb-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible small">
<div class="sb-modal-content mt-16">
{{resourceService?.frmelmnts?.lbl?.datasetRequestSuccess}}
</div>
<div class="sb-modal-actions">
<button class="sb-btn sb-btn-normal sb-btn-primary" (click)="closeConfirmModal()">
{{resourceService?.frmelmnts?.btn?.ok}}
</button>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper [config]="{disableClose: false, size: 'small'}" (dismiss)="closeConfirmationModal()" #modal
*ngIf="showConfirmationModal">
<ng-template sbModalContent>
<div class="sb-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible small">
<div class="sb-modal-content o-x-hide">
<div class="my-8">
{{ resourceService?.frmelmnts?.lbl?.confirmReportRequest }}
</div>
</div>
<div class="sb-modal-actions">
<button class="sb-btn sb-btn-normal sb-btn-primary" (click)="handleConfirmationEvent(true)">
{{resourceService?.frmelmnts?.btn?.yes}}
</button>
<button class="sb-btn sb-btn-normal sb-btn-outline-primary" (click)="handleConfirmationEvent(false)">
{{resourceService?.frmelmnts?.btn?.no}}
</button>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper *ngIf="showPopUpModal" [config]="{disableClose: false, size: 'small'}" (dismiss)="closePopupModal()" #modal>
<ng-template sbModalContent>
<div class="sb-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible small">
<div class="sb-modal-content o-x-hide">
<div class="d-flex flex-dir-row my-8">
<div>
<mat-icon class="info">info</mat-icon>
</div>
<div class="font-weight-bold sb-color-primary modalNote"> {{resourceService?.frmelmnts?.lbl?.modalNote}}</div>
<div class="ml-auto">
<mat-icon class="goback" (click)="goBack()">highlight_off</mat-icon>
</div>
</div>
<div class="mt-48 flex-dc" [formGroup]="reportForm">
<label class="d-flex flex-jc-center sb-color-primary">{{resourceService?.frmelmnts?.lbl?.programLbl }}</label>
<div class="d-flex flex-jc-center mt-24">
<mat-form-field appearance="fill" class="sb-mat__dropdown custom_mat_dd w-80">
<mat-select role="radio" class="selection" valueField="_id" formControlName="programName"
[(ngModel)]="programSelected"
[placeholder]="resourceService?.frmelmnts?.lbl?.program" (selectionChange)="programSelection($event)">
<mat-option *ngFor="let program of programs" class="mat-dropdown__options" role="option" [value]="program._id">
{{program.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="mt-32 sb-modal-actions">
<button [disabled]="!reportForm.controls.programName.value" [ngClass]="{'sb-btn-disabled': (!reportForm.controls.programName.value)}" type="button" class="sb-field sb-btn sb-btn-normal sb-btn-primary" (click)="confirm()">{{resourceService?.frmelmnts?.btn?.confirmBtn}}</button>
</div>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper *ngIf="reportExportInProgress" [config]="{disableClose: true}" (dismiss)="close.emit()">
<ng-template sbModalContent>
<div class="sb-modal sb-hawkeye-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible normal">
<div class="sb-modal-content o-y-visible">
<div class="ui">
<div class="twelve wide column px-0 mb-30">
<app-loader [data]="{loaderMessage: 'Report generation is in Progress. Please wait...'}"></app-loader>
</div>
</div>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
./program-datasets.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.sb-modal-actions {
display: flex;
align-items: center;
justify-content: center;
}
.sb-modal .ui.modal {
margin-top: 15% !important;
}
.ngx-datatable.fixed-header .datatable-header {
padding: 0.625rem;
}
.sidebar-block {
min-height: 25rem;
}
.ngx-datatable.datatable-header {
background: var(--mat-accordion-tab-body-active-bg) !important;
}
.custom_mat_dd .mat-select-arrow-wrapper {
vertical-align: bottom !important;
}
.reset-filter{
color: var(--primary);
background-color: var(--brand-header-tail-text);
width: fit-content;
}
.newData{
color:var(--ck-color-base-error);
margin-left: 1.875rem;
margin-top: 0.625rem;
}
.info{
justify-self: flex-start;
margin-right: 0.625rem;
cursor: pointer;
color: var(--primary) !important;
}
.goback{
justify-self: flex-end;
cursor: pointer;
color: var(--ck-color-button-cancel);
}
.ppFilter{
margin-top: 1.25rem;
}
.col-gap{
gap:2rem;
}
.btn-col{
flex-grow: 1;
margin-left: 5rem !important;
}
.modalNote{
line-height: initial;
}
.infoIcon{
width: 1.125rem;
}
.sb-graph-section{
box-shadow: 0 calculateRem(2px) calculateRem(7px) 0 rgba(var(--rc-rgba-black), 0.16);
background: var(--sb-graph-section-bg);
border: 0.0625rem solid var(--rc-dddddd);
}
.sb-last-update-status {
font-size: calculateRem(12px);
font-weight: bold;
}
.sb-label-name {
font-size: 1rem;
}
.sb-label-value {
border-radius: calculateRem(24px);
padding: calculateRem(7px);
padding-right: calculateRem(9px);
padding-left: calculateRem(9px);
background-color: var(---rc-e9e8d9) !important;
box-shadow: calculateRem(4px) calculateRem(4px) calculateRem(3px) 0 var(--gray-100) !important;
color: var(--gray-800);
margin-bottom: 0.25rem;
margin-right: 0.25rem;
}
::ng-deep {
.cdk-overlay-container{
z-index: 9 !important;
}
.customTable{
sb-dashlets-filters{
display: none !important;
}
.dataTables_length{
display: flex !important;
width: 100% !important;
justify-content: flex-end !important;
}
.chart-title{
font-weight: 700;
}
table{
width: 100% !important;
}
}
.customGraph{
.sb-filter-g__item{
border-radius: 1.5rem !important;
}
.multiselect-dropdown .dropdown-btn{
border-radius: 1.5rem !important;
}
}
.customDate{
.mat-form-field-infix{
width: 8.75rem !important;
}
}
.chart-title {
font-size: 1rem;
font-weight: 500;
margin-bottom: 0.5rem !important;
padding-top: 0.5rem;
}
.custom_mat_dd{
.mat-form-field-flex{
display: flex;
align-items: center !important;
box-sizing: border-box;
width: 100%;
input::placeholder{
color: rgba(0,0,0,.42) !important;
font-weight: bold !important;
}
}
.mat-select-arrow-wrapper {
vertical-align: unset !important;
}
}
.mat-select-panel .mat-option {
white-space: normal !important;
display: inline-table !important;
width: 100% !important;
line-height: 1.5em !important;
padding: 0.625rem 1.5em;
}
.mat-option-text{
display: flex !important;
}
.mat-dropdown__options span {
position: unset !important;
}
.mat-dropdown__options span:before {
display: flex !important;
align-self: flex-end !important;
}
.custom_mat_multi.mat-option{
display: flex !important;
}
}