principal-dashboard-lib-v2 0.0.36 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/principal-dashboard-lib-v2.umd.js +1270 -84
- package/bundles/principal-dashboard-lib-v2.umd.js.map +1 -1
- package/bundles/principal-dashboard-lib-v2.umd.min.js +1 -1
- package/bundles/principal-dashboard-lib-v2.umd.min.js.map +1 -1
- package/esm2015/lib/chartheader/chartheader.component.js +20 -4
- package/esm2015/lib/chartview/chartview.component.js +114 -9
- package/esm2015/lib/full-table-view/full-table-view.component.js +119 -3
- package/esm2015/lib/insights/insights.component.js +535 -0
- package/esm2015/lib/principal-dashboard-lib-v2.component.js +10 -4
- package/esm2015/lib/principal-dashboard-lib-v2.module.js +6 -2
- package/esm2015/lib/principal-dashboard-lib-v2.service.js +23 -12
- package/esm2015/lib/small-table-view/small-table-view.component.js +172 -54
- package/esm2015/lib/timeline/timeline.component.js +195 -0
- package/esm2015/lib/version.js +3 -0
- package/esm2015/principal-dashboard-lib-v2.js +3 -1
- package/fesm2015/principal-dashboard-lib-v2.js +1184 -82
- package/fesm2015/principal-dashboard-lib-v2.js.map +1 -1
- package/lib/chartheader/chartheader.component.d.ts +3 -0
- package/lib/chartview/chartview.component.d.ts +20 -0
- package/lib/full-table-view/full-table-view.component.d.ts +10 -0
- package/lib/insights/insights.component.d.ts +103 -0
- package/lib/principal-dashboard-lib-v2.component.d.ts +4 -1
- package/lib/principal-dashboard-lib-v2.service.d.ts +14 -0
- package/lib/small-table-view/small-table-view.component.d.ts +23 -0
- package/lib/timeline/timeline.component.d.ts +76 -0
- package/lib/version.d.ts +1 -0
- package/lib/version.d.ts.map +1 -0
- package/package.json +1 -1
- package/principal-dashboard-lib-v2.d.ts +2 -0
- package/principal-dashboard-lib-v2.d.ts.map +1 -0
- package/principal-dashboard-lib-v2.metadata.json +1 -1
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('rxjs'), require('angular-google-charts'), require('file-saver'), require('xlsx'), require('@angular/common'), require('ng2-datepicker')) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define('principal-dashboard-lib-v2', ['exports', '@angular/core', 'rxjs', 'angular-google-charts', 'file-saver', 'xlsx', '@angular/common', 'ng2-datepicker'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['principal-dashboard-lib-v2'] = {}, global.ng.core, global.rxjs, global.angularGoogleCharts, global.FileSaver, global.XLSX, global.ng.common, global.ng2Datepicker));
|
|
5
|
-
}(this, (function (exports, i0, rxjs, angularGoogleCharts, FileSaver, XLSX, common, ng2Datepicker) { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('rxjs'), require('angular-google-charts'), require('file-saver'), require('xlsx'), require('@angular/common'), require('ng2-datepicker'), require('html2canvas'), require('jspdf')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define('principal-dashboard-lib-v2', ['exports', '@angular/core', 'rxjs', 'angular-google-charts', 'file-saver', 'xlsx', '@angular/common', 'ng2-datepicker', 'html2canvas', 'jspdf'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['principal-dashboard-lib-v2'] = {}, global.ng.core, global.rxjs, global.angularGoogleCharts, global.FileSaver, global.XLSX, global.ng.common, global.ng2Datepicker, global.html2canvas, global.jspdf));
|
|
5
|
+
}(this, (function (exports, i0, rxjs, angularGoogleCharts, FileSaver, XLSX, common, ng2Datepicker, html2canvas, jspdf) { 'use strict';
|
|
6
|
+
|
|
7
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
+
|
|
9
|
+
var html2canvas__default = /*#__PURE__*/_interopDefaultLegacy(html2canvas);
|
|
6
10
|
|
|
7
11
|
var PrincipalDashboardLibV2Service = /** @class */ (function () {
|
|
8
12
|
function PrincipalDashboardLibV2Service() {
|
|
@@ -29,7 +33,14 @@
|
|
|
29
33
|
//for get details of selected user
|
|
30
34
|
this.detailedviewData = new rxjs.BehaviorSubject(this.userMetadata);
|
|
31
35
|
this.detailedviewData$ = this.detailedviewData.asObservable();
|
|
36
|
+
// true while the Insights tab is selected instead of the user / classroom views
|
|
37
|
+
this.isInsightsView = new rxjs.BehaviorSubject(false);
|
|
38
|
+
this.isInsightsView$ = this.isInsightsView.asObservable();
|
|
32
39
|
this.openSmallTable = new rxjs.BehaviorSubject(false);
|
|
40
|
+
// colour of the timeline bar that opened the details popup
|
|
41
|
+
this.detailAccentColor = '';
|
|
42
|
+
// set when the popup should list every session of a timeline row instead of one session
|
|
43
|
+
this.detailRowRequest = null;
|
|
33
44
|
this.openSmallTable$ = this.openSmallTable.asObservable();
|
|
34
45
|
}
|
|
35
46
|
PrincipalDashboardLibV2Service.prototype.genarateResourseReqiuredData = function (data) {
|
|
@@ -422,10 +433,7 @@
|
|
|
422
433
|
for (var i = 0; i < this.userConsoleData.length; i++) {
|
|
423
434
|
//console.log('bbb-->',this.userConsoleData[i].terminalLocation)
|
|
424
435
|
var roomName = this.userConsoleData[i].terminalLocation;
|
|
425
|
-
|
|
426
|
-
//roomName = "No Name"
|
|
427
|
-
}
|
|
428
|
-
var location = roomName + " - " + this.userConsoleData[i].terminalIP;
|
|
436
|
+
var location = this.getRoomLabel(roomName, this.userConsoleData[i].terminalIP);
|
|
429
437
|
//console.log('bbblocation-->',location)
|
|
430
438
|
var userData = [location, this.userConsoleData[i].startTime, this.userConsoleData[i].endTime];
|
|
431
439
|
dataTableforChart.push(userData);
|
|
@@ -451,6 +459,11 @@
|
|
|
451
459
|
dataTableforChart = this.uniq(dataTableforChart);
|
|
452
460
|
return dataTableforChart;
|
|
453
461
|
};
|
|
462
|
+
// Row label for classroom wise chart: room name, or IP as fallback when name is missing
|
|
463
|
+
PrincipalDashboardLibV2Service.prototype.getRoomLabel = function (roomName, roomIP) {
|
|
464
|
+
var name = (roomName === undefined || roomName === null || roomName === 'undefined') ? '' : String(roomName).trim();
|
|
465
|
+
return name !== '' ? name : (roomIP || '');
|
|
466
|
+
};
|
|
454
467
|
PrincipalDashboardLibV2Service.prototype.uniq = function (a) {
|
|
455
468
|
return Array.from(new Set(a));
|
|
456
469
|
};
|
|
@@ -551,29 +564,31 @@
|
|
|
551
564
|
//console.log("bbb allRoom-->",this.userConsoleData[i])
|
|
552
565
|
var roomName = this.userConsoleData[i].terminalLocation;
|
|
553
566
|
var roomIP = this.userConsoleData[i].terminalIP;
|
|
554
|
-
|
|
555
|
-
roomName = "No Name";
|
|
556
|
-
}
|
|
557
|
-
var location = roomName + " - " + roomIP;
|
|
567
|
+
var location = this.getRoomLabel(roomName, roomIP);
|
|
558
568
|
//console.log('bbbbRoom',location)
|
|
559
569
|
// let userData = [this.userConsoleData[i].terminalIP,this.userConsoleData[i].startTime,this.userConsoleData[i].endTime];
|
|
560
570
|
var userData = [location, this.userConsoleData[i].startTime, this.userConsoleData[i].endTime];
|
|
561
571
|
dataTableforChart.push(userData);
|
|
562
572
|
}
|
|
563
573
|
var inactiveRoonName = void 0;
|
|
574
|
+
// rooms already used today are in the chart above, add only the idle ones
|
|
575
|
+
var activeRoomIPs = this.userConsoleData.map(function (room) { return room.terminalIP; });
|
|
564
576
|
for (var i = 0; i < this.schoolTerminalData.length; i++) {
|
|
565
577
|
//console.log("schoolTerminalData",this.schoolTerminalData);
|
|
566
|
-
|
|
578
|
+
if (activeRoomIPs.includes(this.schoolTerminalData[i].terminalKey)) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
inActiveClassRoom = this.getRoomLabel(this.schoolTerminalData[i].location, this.schoolTerminalData[i].terminalKey);
|
|
567
582
|
//inactiveRoonName = this.schoolTerminalData[i].location;
|
|
568
583
|
myChartRowData = {
|
|
569
584
|
userId: "",
|
|
570
585
|
userName: "",
|
|
571
586
|
startTime: new Date(this.myEndTime),
|
|
572
587
|
endTime: new Date(this.myEndTime),
|
|
573
|
-
terminalIP:
|
|
588
|
+
terminalIP: this.schoolTerminalData[i].terminalKey,
|
|
574
589
|
resourceMetauserConsoleData: [],
|
|
575
590
|
duration: 0,
|
|
576
|
-
terminalLocation:
|
|
591
|
+
terminalLocation: this.schoolTerminalData[i].location,
|
|
577
592
|
userSubjects: ""
|
|
578
593
|
};
|
|
579
594
|
allRoomsDetails.push(myChartRowData);
|
|
@@ -842,9 +857,11 @@
|
|
|
842
857
|
PrincipalDashboardLibV2Service.ctorParameters = function () { return []; };
|
|
843
858
|
|
|
844
859
|
var PrincipalDashboardLibV2Component = /** @class */ (function () {
|
|
845
|
-
function PrincipalDashboardLibV2Component() {
|
|
860
|
+
function PrincipalDashboardLibV2Component(pdService) {
|
|
861
|
+
this.pdService = pdService;
|
|
846
862
|
this.userSelectedDate = new i0.EventEmitter();
|
|
847
863
|
this.messageForUser = "Loding...";
|
|
864
|
+
this.isInsights = false;
|
|
848
865
|
}
|
|
849
866
|
Object.defineProperty(PrincipalDashboardLibV2Component.prototype, "responseStatus", {
|
|
850
867
|
set: function (res) {
|
|
@@ -855,6 +872,8 @@
|
|
|
855
872
|
configurable: true
|
|
856
873
|
});
|
|
857
874
|
PrincipalDashboardLibV2Component.prototype.ngOnInit = function () {
|
|
875
|
+
var _this = this;
|
|
876
|
+
this.pdService.isInsightsView.subscribe(function (value) { return _this.isInsights = value; });
|
|
858
877
|
// console.log(" IN --> 7 data",this.data);
|
|
859
878
|
};
|
|
860
879
|
PrincipalDashboardLibV2Component.prototype.setMessageForUser = function (res) {
|
|
@@ -870,17 +889,22 @@
|
|
|
870
889
|
PrincipalDashboardLibV2Component.decorators = [
|
|
871
890
|
{ type: i0.Component, args: [{
|
|
872
891
|
selector: 'lib-principal-dashboard-lib-v2',
|
|
873
|
-
template: "<div id=\"reprtModule\">\n <div id=\"pd-mainDiv\" class=\"pd-mainContainer\">\n <lib-header [data]=\"data\" (userSelectedDate)=\"onUserSelectDate($event)\">\n </lib-header>\n <lib-chartheader></lib-chartheader>\n \n <div id=\"pd-preloader\" class=\"pd-preloaderDiv\" *ngIf=\"responseStatus !== 'true' && !data\">\n {{messageForUser}} \n </div>\n <lib-chartview *ngIf=\"data\" [data]=\"data\"></lib-chartview>\n
|
|
892
|
+
template: "<div id=\"reprtModule\">\n <div id=\"pd-mainDiv\" class=\"pd-mainContainer\">\n <lib-header [data]=\"data\" (userSelectedDate)=\"onUserSelectDate($event)\">\n </lib-header>\n <lib-chartheader></lib-chartheader>\n \n <div id=\"pd-preloader\" class=\"pd-preloaderDiv\" *ngIf=\"responseStatus !== 'true' && !data\">\n {{messageForUser}} \n </div>\n <!-- kept alive (only hidden) while on Insights so the timeline keeps its state -->\n <div [style.display]=\"isInsights ? 'none' : 'block'\">\n <lib-chartview *ngIf=\"data\" [data]=\"data\"></lib-chartview>\n <!-- <lib-tableview *ngIf=\"data\" [data]=\"data\"></lib-tableview> -->\n <lib-full-table-view *ngIf=\"data\" [data]=\"data\"></lib-full-table-view>\n </div>\n <lib-insights *ngIf=\"data && isInsights\" [data]=\"data\"></lib-insights>\n <!-- <lib-detailedview *ngIf=\"data\" [data]=\"data\"></lib-detailedview> -->\n <lib-small-table-view *ngIf=\"data\" [data]=\"data\"></lib-small-table-view>\n \n </div>\n</div>\n ",
|
|
874
893
|
styles: [".pd-mainContainer{width:100%;height:100%}.pd-mainContainer .pd-preloaderDiv{text-align:center;line-height:27;position:absolute;width:100%;height:87%;z-index:2}.bs-datepicker-head{background-color:#000!important}"]
|
|
875
894
|
},] }
|
|
876
895
|
];
|
|
877
|
-
PrincipalDashboardLibV2Component.ctorParameters = function () { return [
|
|
896
|
+
PrincipalDashboardLibV2Component.ctorParameters = function () { return [
|
|
897
|
+
{ type: PrincipalDashboardLibV2Service }
|
|
898
|
+
]; };
|
|
878
899
|
PrincipalDashboardLibV2Component.propDecorators = {
|
|
879
900
|
data: [{ type: i0.Input }],
|
|
880
901
|
responseStatus: [{ type: i0.Input }],
|
|
881
902
|
userSelectedDate: [{ type: i0.Output }]
|
|
882
903
|
};
|
|
883
904
|
|
|
905
|
+
// Generated by scripts/lib-version.js from the library's package.json. Do not edit by hand.
|
|
906
|
+
var LIB_VERSION = '0.0.38';
|
|
907
|
+
|
|
884
908
|
var ChartheaderComponent = /** @class */ (function () {
|
|
885
909
|
function ChartheaderComponent(pdService) {
|
|
886
910
|
this.pdService = pdService;
|
|
@@ -889,9 +913,11 @@
|
|
|
889
913
|
this.datadisplaytype = 'UserWise';
|
|
890
914
|
this.isUserWise = true;
|
|
891
915
|
this.isChartView = true;
|
|
916
|
+
this.isInsights = false;
|
|
892
917
|
}
|
|
893
918
|
ChartheaderComponent.prototype.ngOnInit = function () {
|
|
894
|
-
|
|
919
|
+
// set from the library's package.json by scripts/lib-version.js
|
|
920
|
+
this.libVersion = LIB_VERSION;
|
|
895
921
|
// this.myIcon = document.getElementById('myIconImg');
|
|
896
922
|
// this.changeChatType()
|
|
897
923
|
};
|
|
@@ -907,21 +933,34 @@
|
|
|
907
933
|
this.pdService.chartType.next(this.mytype);
|
|
908
934
|
}
|
|
909
935
|
};
|
|
936
|
+
ChartheaderComponent.prototype.showInsights = function () {
|
|
937
|
+
this.isInsights = true;
|
|
938
|
+
this.pdService.openSmallTable.next(false);
|
|
939
|
+
this.pdService.isInsightsView.next(true);
|
|
940
|
+
};
|
|
910
941
|
ChartheaderComponent.prototype.changeDataTypeClassRoom = function () {
|
|
942
|
+
this.leaveInsights();
|
|
911
943
|
this.isUserWise = false;
|
|
912
944
|
this.pdService.isUserWise_data.next(false);
|
|
913
945
|
};
|
|
914
946
|
ChartheaderComponent.prototype.changeDataTypeUser = function () {
|
|
947
|
+
this.leaveInsights();
|
|
915
948
|
this.isUserWise = true;
|
|
916
949
|
this.pdService.isUserWise_data.next(true);
|
|
917
950
|
};
|
|
951
|
+
ChartheaderComponent.prototype.leaveInsights = function () {
|
|
952
|
+
if (this.isInsights) {
|
|
953
|
+
this.isInsights = false;
|
|
954
|
+
this.pdService.isInsightsView.next(false);
|
|
955
|
+
}
|
|
956
|
+
};
|
|
918
957
|
return ChartheaderComponent;
|
|
919
958
|
}());
|
|
920
959
|
ChartheaderComponent.decorators = [
|
|
921
960
|
{ type: i0.Component, args: [{
|
|
922
961
|
selector: 'lib-chartheader',
|
|
923
|
-
template: "\n<div id=\"pd-chartheader\">\n <div id=\"pd-chatTypeBtnDiv\" class=\"pd-tabIconBtn\" [ngClass]=\" isChartView ? 'tableIconImg' : 'chartIconImg'\" (click)=\"changeChatType()\">\n </div>\n \n <div id=\"pd-userWisechatTypeBtn\" class=\"userWiseBtn\" [ngStyle]=\"{ color: isUserWise ? '#ffffff' : '#000000' , backgroundColor: isUserWise ? '#000000' : '#c4c4c4'}\"\n (click)=\"changeDataTypeUser()\">User wise</div>\n <div id=\"pd-classRoomWiseBtn\" class=\"classWiseBtn\" [ngStyle]=\"{ color: isUserWise ? '#
|
|
924
|
-
styles: ["#pd-chartheader{font-size:12pt;font-weight:400;color:#5c5c5c;z-index:1;width:100%;height:40px;position:relative;margin:10 auto;text-align:center;background-color:#e0e0e0}#pd-chartheader #pd-classRoomWiseBtn,#pd-chartheader #pd-userWisechatTypeBtn{background:-moz-linear-gradient(center top,#45a1da 5%,#1172ae 100%);display:inline-block;padding:0 20px;cursor:pointer;margin:5px 0 0;width:160px;height:30px;line-height:30px}#pd-chartheader .libVersionDiv{position:absolute;font-size:12px;color:#343a40;margin-top:-21px;font-weight:700;margin-left:71px}.userWiseBtn{border-radius:6px 0 0 6px}.
|
|
962
|
+
template: "\n<div id=\"pd-chartheader\">\n <div id=\"pd-chatTypeBtnDiv\" *ngIf=\"!isInsights\" class=\"pd-tabIconBtn\" [ngClass]=\" isChartView ? 'tableIconImg' : 'chartIconImg'\" (click)=\"changeChatType()\">\n </div>\n \n <div id=\"pd-userWisechatTypeBtn\" class=\"userWiseBtn\" [ngStyle]=\"{ color: isUserWise && !isInsights ? '#ffffff' : '#000000' , backgroundColor: isUserWise && !isInsights ? '#000000' : '#c4c4c4'}\"\n (click)=\"changeDataTypeUser()\">User wise</div>\n <div id=\"pd-classRoomWiseBtn\" class=\"classWiseBtn\" [ngStyle]=\"{ color: !isUserWise && !isInsights ? '#ffffff' : '#000000' , backgroundColor: !isUserWise && !isInsights ? '#000000' : '#c4c4c4'}\"\n (click)=\"changeDataTypeClassRoom()\">Classroom wise</div><div id=\"pd-insightsBtn\" class=\"insightsBtn\" [ngStyle]=\"{ color: isInsights ? '#ffffff' : '#000000' , backgroundColor: isInsights ? '#000000' : '#c4c4c4'}\"\n (click)=\"showInsights()\">Insights</div>\n\n \n <div class=\"libVersionDiv\">v{{libVersion}}</div>\n</div>",
|
|
963
|
+
styles: ["#pd-chartheader{font-size:12pt;font-weight:400;color:#5c5c5c;z-index:1;width:100%;height:40px;position:relative;margin:10 auto;text-align:center;background-color:#e0e0e0}#pd-chartheader #pd-classRoomWiseBtn,#pd-chartheader #pd-insightsBtn,#pd-chartheader #pd-userWisechatTypeBtn{background:-moz-linear-gradient(center top,#45a1da 5%,#1172ae 100%);display:inline-block;padding:0 20px;cursor:pointer;margin:5px 0 0;width:160px;height:30px;line-height:30px}#pd-chartheader .libVersionDiv{position:absolute;font-size:12px;color:#343a40;margin-top:-21px;font-weight:700;margin-left:71px}.userWiseBtn{border-radius:6px 0 0 6px}.insightsBtn{border-radius:0 6px 6px 0;border-left:1px solid #e0e0e0}.pd-tabIconBtn{cursor:pointer;position:absolute;left:10px;top:-17px;width:62px;height:52px;background-repeat:no-repeat}.tableIconImg{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAAAzCAYAAADPX7uaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MkZDQzc3REFDMkQ2MTFFMkIzNDhCNTE1RDg3OUE1QTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MkZDQzc3REJDMkQ2MTFFMkIzNDhCNTE1RDg3OUE1QTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyRkNDNzdEOEMyRDYxMUUyQjM0OEI1MTVEODc5QTVBNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyRkNDNzdEOUMyRDYxMUUyQjM0OEI1MTVEODc5QTVBNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PnXBGHQAAAblSURBVHja3FrLbxtFGP9mdh0/m0DSPFvnEKAHkBCNShEHWlB5nEigqgRcokogLlwR/AHcEDf4BxBXToEDV0JfqlAgQiJIVVtKuaQmzcOO7fgxw3yzO/Z4vC/DurU70mhm19/Ofr/v981vZndNIFohMFyFhxnYEYGSgACQAQLHo9oGASEefTKAWcCNPtfOmX1fxr2AUuOYhGTAwwDNPSoz7IgO3otBaoDWq35+kFKdGYD1agaC+zGuA7aMlnpkwMNm3Atw02iZybjtkdpEA2u5NrYRhEEEroNtuNVM9daxF+M624mJ/BNHnj679HEimV4ilOYHeg1j7G79sLL6+4+rX2zfvVn0mf9d4maCto/OPzX6zCvLn1944+yFN8+cgumJxwZ68d7a3s1/t/bzR99a1szm2vef3Lv9x66P8HkqdivNT7z42rv2SOr8+2+dG3jQWNBH9FX4/PaTL5x7R5uuXThpkLAls2MXv/z0A2nDOR+KigV9TmZGLxqi3KFJts/6LYGLOT01PpprDTgs5XHhs/B90oNthZHbHozrrHOmRRJLLpcbSLClUqktcm1/fZdfv3W8tUnhBvDkGIXTH87B0QWMKgFKCHDqXkScikfUHYFoozo22qqCfXds7tzMbZ0qG6ZMuGyVK3ieMQa7t+uw8XWhw0cDuOfSa4dsV+XgWPUVMZM8AodQlgpBETxWywGFLbXEpfK808cAoS22FnUAtwLiApSZxWSKOaCaXPYZHjdBtky1eE5c2xA/ZFMTAmihw0et77vFtkPXRoNxda64XwZqg2QcwUngCqxNOgJCXeDSjjoBIkQDzh1ADott4IwpwLx9rPWbzSaM8nGT5UiaFAocPIDLHKIaCOoAaQEkzhRQ51utBOyy7x7LsblLBYdWQIiaPu45OS5XyqNcI95g4wDeleoqZyynUhcwsk9UyrvpbVmKZYNxqqc6cfaTmObUbd2NJ2G8LR7INgag4USIEBUsbqa3p789A+9KdXG3cr0Ehb/uyXnWEjXaFrfOPoFUMgm1eq2lZ0ro9DnOuWKcQMJOQKV66GZbW+DMPsYlnxpzhS/mVDeBN2scXp1/D54/eRpS6ZT36w3NvlYXqvvrBjx38iTYmAIhpVwuw+bmJiwuLors0PJaWw1Ur9Gowy/rG7DBvoofOOOdqW5DEhZyz8Lri+elk0EPaFxcOzZ+BNLFo/Dy6TOwt10U/tPA+2WzWRir/QRnT70Eu//sC/CW74PZ6HgO9m4yMSVIZ6rzWFK9M4JUOM7EBCxW9qB0UArNFjtFoVI/gEqlArul+y6LAddYDag2ylCtVmHvYMfXHsdOZhNQa1Zl7DsZhz6Km0i9dDodegPlOLaZTKZzA+MxpiqWmBa92Mcubl7AMbqpVAqSQrRC30u7zqHtxMREKJBazRHBRCIRyZ4/KFXHmyEb169fB9uOsg3gcHBwAFeuXIm05240GnLfffXq1UgipWziV3UPxvF4ampKpmJYqQtVLxQKMDs7KwMWVlALdnZ2pH2YHmCQbt261cUy7wfjqn/s2DHJTFAqou3MzAzcuHED8vm8DECQPRZM7zt37kj7ra2tQHE7fvy4zIy+MG4uZ3q0sQYBweuQcXQEW6xBLKIdjqnsse9nr8b2FDfej52bNtfDUh2v60XV9RKm6ji2/lv8jMvHwG5Vx6UMlTrsJrqqj4yMhNqaqh5m763qfXhIUaqOKo2qHiW6qOpra2uRmMZHTdSOS5cuhS5LD3Q5UwPPz89L1sNSF+chqvTCwkKoquN9UNWLxaK0DxsbNQCF8L+kOo3KuKpq0MnJydA3nmg/PT0t0xxbZDPsDamyx+UyyB7HnpubawXH9LNvLyJ0p6KoNLZRHMJxFZtB9mrMvr2ICFL1fu7VUT96se+Dqvvv1bEG3UR3rFdVR+BBqq7G7p+4GW83kDkUqWvXrvW0V0eV7kXVL1++HHmvrqu78jn2VEenVlZWBu6DQhyp3vFV0dzArK+vD+SXFJ8NTNfnYS/g5h9lWJC4DXLR/GXg/UcgX8bZIwScRWWcLS0tFeR8BtgZZuACx9/Yrq6ujvoxztvX8P3l5eWK6KfVZqDeaMKQIe94t4GYhPKnday2R4rrpfrZNz8c/l8/xkdzctGt1WvypiMWdY4bTfe9EZPHI0nHt/v7pThSrGrqn8m4zvaOvofP3fttNg4CDreMYz87t83Gw/usjgWxCdZbKW8yrgo+8uC2KRXlQSZCUVu4VESW4mCcueNti3rCHLfjm7iICn4aScKjWQ4F4xmTcRWJP2NmWpVMj/blOPc2GvMtZff6L6vfP5YH5Y+7/o8V3S33Oe/7v3QYErBRgwB+czxMlIa1+IrkvwIMANKaPx47pbRTAAAAAElFTkSuQmCC\")}.chartIconImg{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAAAzCAYAAADPX7uaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RDk0MUYxOEJDQzFFMTFFMkIxOUNERTUyRTI5MjFDNEYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RDk0MUYxOENDQzFFMTFFMkIxOUNERTUyRTI5MjFDNEYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEOTQxRjE4OUNDMUUxMUUyQjE5Q0RFNTJFMjkyMUM0RiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEOTQxRjE4QUNDMUUxMUUyQjE5Q0RFNTJFMjkyMUM0RiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpdyrHsAAAZISURBVHja3FpLbBtFGP5nd/1I/CCOm0AqUqRCKwQHJB6qgIioVBUnEkCV4MAhUgsHuCU8Du0hCXAAoRwAwYEeQJW4AAcCiuBSiebI4wDiIR4qEKQooYkdx3b83OGftXczO96x1/HGWXeiiXd2Znf/b77/NbNLwF0h0FuFthqguQRKmkwA8RE46nZsMyDE4Zj4UAuocEy5c+KxlHEnoIrQJi004CBAU4eqC+MID96JQUUAzVf+vJ9UXRcA81WcCCpjnAesCr+KgwYcNONOgKvCry4yrjmoNuHAqvUxmjAJfgTOg63Uq6jqVtuJcZ7tQHL01tgd4xMvBEJ9E0RRRn0dw3R9pVzcWfz568U3N1b+3JbYf4NzE0Frh44ci995cvKNM4+Mn3n0oXvhxuSAr4P32kZ69PMr3z7/iare9MuVL15av/prWuL4HD22pebH7z/9lBYMP3H2sVO+B80Kk5HJijI/ftuJU09y5tqAU2nm2EKRG6befvmcMYZS2hOVFSZzqD8+JThlm0/SJPHbAI42PTwYj1o37JWSQJlR9iEHtk2MVHNgnGed6txMshKLxXw5EdlsdtfJ7conDb+yOG4lKVQAHo1GYXZ21leg5+fnbTIKwB1Dr9YiXQVd141qlmq1avxOT0/7AvTCwgJUKhWbjNyxNMXWWsZGgXF+AlZXV10J9/HYFFS38xBAAnAa4cH3zsPhB+7qGPTIyEgNDSEyxttelvLIO7bp0rU0DOd0OEbisAFlqJRK3icvvIxeABdVXSyKorTexVBVI5sk9T92jZvrWsklazeTt2NVZ0VFQEzN3BcEjeOJQjoGLj7Xc1UXgfPHTHhXwAnnYikTunPGRZk8B65Tuaq7ZdxyqZQw1AZo1VB/74DbVJ16our2h/BAeeDr2Txm/7vjIsEgRIMB+64BqU2Cug/A7W3w3rnxKsoLf987lyDDHhgI4V1VePGe2+HC+Am7I6TMxhVPbFy0d8+dmyyBEYEHNLxV/BAukQ4DGRjAmJ3i+ond1hW1Y8ZF9rvu1W2GjA8kODFErwDRGtVZoYrh1U1V38ptwoeX37Jtkpw9PQORcKxj1e8cuN7cuYkOjBoJYi1sWf2kBoyP46wvW8zAp99chEACIDmYgNQ/OXj65HMQV9tf+/My0v1m3NlOCesw7M7st7y64dzY+VqfpgWMHQGtHxc/yTBsrxVwQrQ92X9Xw5ldQM6OERgP3BYhMJCbcVypRwRaZSzVtN3M6kr5ImTW07ZnDR4ZcpWteRTO5IxLY7jJNLFv29P6HztvVuC0gdY1gp3/6avv4KNn34UgihgO90GOFOD1lQ+6yLhOXXlJGwLirKo6YWszKs9yuHkiGBKjpA+SJAY3D90CPxR+d23jTOZ9X6Q4AlBA/kqPSE6Txi6mHVVU2yqtQLMXoPsSx+lelqWkUU4j2uFJJ8YJNMWF86gcgHMTGG+ZeFTxocUyQLCRWubYKDizQZtgJ9YOUhcTmPY3ImgNfJvgZJ2mGXR9I6KtJR+mogTjMGHpqzAOe4ytJ1VEwWxbZZcq0NiFSRBeE1b78T85WFU3c3VR5a9lcwY8SstA0+uQPTps9e2ktzFz1+A3yEBer8JRZgqGVeC98bCUwtVddQuK+RJeX3tWpVCGAi3BJl7zR/oqpLdS0sxxL6rObyWbb0WDWHGJBeGHz53//tVnJhORcMi6YGxszHfby3Nzc7C8vGy1c4UiXHj/s9Tli6/djc0C1iLb+oPdt6h626oeiURgZmbGV8ATiYQnqm57qygmMEtLS+DHIklgqMxtahK/an06QT3YXu524eTVwflDICnj+nUEXHfLuD4xMfEfO5EFSPUycMTxL/tdXFyMyxinu9fQzOTk5A4e95nJQLlShR5Dzrd2GCbM5/t4rJqDivOl8MqlL4udyjEYjxrZR6lcMh4aVJVau1JP8ahutIOhmmybmawXKlYQ/Z/IOM92yloXYImu/zjiBQHFNaEtG2eGTG94H+GxMGzIuqXyIuNm+RtrkiUxAODFPrCZb4ZdsuQF43r9fhtYj4v3tb0Tx1nJ17O267EUkfF+kXFzJv7ymGmz9Lc5Pu9lbsMxb3l2p29ZZV8s++XD3WYLWwDnD3sb+mXfpUOPgHU7CSCz8VZOqVeL1En+L8AAjJTPo0iRABoAAAAASUVORK5CYII=\")}"]
|
|
925
964
|
},] }
|
|
926
965
|
];
|
|
927
966
|
ChartheaderComponent.ctorParameters = function () { return [
|
|
@@ -1259,6 +1298,12 @@
|
|
|
1259
1298
|
this.allList = "All Users";
|
|
1260
1299
|
this.isAllUsers = false;
|
|
1261
1300
|
this.isUserWise = false;
|
|
1301
|
+
this.isSubscribed = false;
|
|
1302
|
+
// set to false to go back to the Google timeline chart
|
|
1303
|
+
this.useCustomTimeline = true;
|
|
1304
|
+
this.isTableView = false;
|
|
1305
|
+
this.timelineRows = [];
|
|
1306
|
+
this.timelineList = [];
|
|
1262
1307
|
this.myChartDataMatrix = new Array();
|
|
1263
1308
|
this.totalChartDataMatrix = new Array();
|
|
1264
1309
|
}
|
|
@@ -1284,6 +1329,7 @@
|
|
|
1284
1329
|
this.currentList = "Current Users";
|
|
1285
1330
|
this.allList = "All Users";
|
|
1286
1331
|
this.isAllUsers = false;
|
|
1332
|
+
this.pdService.isAllUsers.next(false);
|
|
1287
1333
|
this.isUserWise = false;
|
|
1288
1334
|
this.myChartDataMatrix = [];
|
|
1289
1335
|
this.totalChartDataMatrix = [];
|
|
@@ -1296,6 +1342,7 @@
|
|
|
1296
1342
|
if (this.myXmlData) {
|
|
1297
1343
|
this.currentdataList = this.pdService.genarateUserReqiuredData(this.myXmlData);
|
|
1298
1344
|
this.alluserList = this.pdService.allUserChartData();
|
|
1345
|
+
this.allRoomsList = this.pdService.allRoomsData();
|
|
1299
1346
|
this.resourceDataList = this.pdService.genarateResourseReqiuredData(this.myXmlData);
|
|
1300
1347
|
this.totalUsers = this.currentdataList.usersMetadata.length;
|
|
1301
1348
|
this.eligibleUsers = this.findEligibleUserCount();
|
|
@@ -1303,6 +1350,12 @@
|
|
|
1303
1350
|
this.currentRooms = this.findCurrentClassrooms();
|
|
1304
1351
|
this.findCurrentUserCount();
|
|
1305
1352
|
}
|
|
1353
|
+
// subscribe once; on later reloads just redraw the currently selected view
|
|
1354
|
+
if (this.isSubscribed) {
|
|
1355
|
+
this.updateDataType(this.pdService.isUserWise_data.value);
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
this.isSubscribed = true;
|
|
1306
1359
|
this.pdService.chartType.subscribe(function (data) {
|
|
1307
1360
|
if (data) {
|
|
1308
1361
|
_this.updateChartType(data);
|
|
@@ -1311,10 +1364,25 @@
|
|
|
1311
1364
|
this.pdService.isUserWise_data.subscribe(function (data) {
|
|
1312
1365
|
_this.updateDataType(data);
|
|
1313
1366
|
});
|
|
1367
|
+
this.pdService.isInsightsView.subscribe(function (insights) {
|
|
1368
|
+
if (!insights) {
|
|
1369
|
+
setTimeout(function () { return _this.fitChartHeight(); });
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1314
1372
|
window.addEventListener('resize', this.onResizeWindow.bind(this));
|
|
1315
1373
|
};
|
|
1316
1374
|
ChartviewComponent.prototype.onResizeWindow = function (event) {
|
|
1317
1375
|
this.myChartwidth = window.innerWidth * 0.88; //set an appropriate factor
|
|
1376
|
+
this.fitChartHeight();
|
|
1377
|
+
};
|
|
1378
|
+
// stretch the chart area from where it starts down to the bottom of the window
|
|
1379
|
+
ChartviewComponent.prototype.fitChartHeight = function () {
|
|
1380
|
+
var chartview = document.getElementById('pd-chartview');
|
|
1381
|
+
if (!chartview || chartview.style.display === 'none')
|
|
1382
|
+
return;
|
|
1383
|
+
var top = chartview.getBoundingClientRect().top + window.scrollY;
|
|
1384
|
+
var height = Math.max(window.innerHeight - top - 8, 240);
|
|
1385
|
+
chartview.style.height = height + 'px';
|
|
1318
1386
|
};
|
|
1319
1387
|
ChartviewComponent.prototype.myChartReady = function () {
|
|
1320
1388
|
this.createDivforTotalDurartion();
|
|
@@ -1322,16 +1390,21 @@
|
|
|
1322
1390
|
// this.removeBlankEntryBar();
|
|
1323
1391
|
};
|
|
1324
1392
|
ChartviewComponent.prototype.updateChartType = function (dataType) {
|
|
1393
|
+
var _this = this;
|
|
1394
|
+
this.isTableView = dataType == angularGoogleCharts.ChartType.Table;
|
|
1325
1395
|
if (this.chartview != null && this.chartview != undefined) {
|
|
1326
1396
|
if (dataType == angularGoogleCharts.ChartType.Table) {
|
|
1327
1397
|
this.chartview.style.display = 'none';
|
|
1328
1398
|
}
|
|
1329
1399
|
else {
|
|
1330
1400
|
this.chartview.style.display = 'block';
|
|
1401
|
+
setTimeout(function () { return _this.fitChartHeight(); });
|
|
1331
1402
|
}
|
|
1332
1403
|
}
|
|
1333
1404
|
};
|
|
1334
1405
|
ChartviewComponent.prototype.updateDataType = function (dataType) {
|
|
1406
|
+
var _this = this;
|
|
1407
|
+
setTimeout(function () { return _this.fitChartHeight(); });
|
|
1335
1408
|
this.isUserWise = dataType;
|
|
1336
1409
|
if (this.myXmlData) {
|
|
1337
1410
|
if (this.isUserWise) {
|
|
@@ -1359,7 +1432,7 @@
|
|
|
1359
1432
|
ChartviewComponent.prototype.updateChart = function () {
|
|
1360
1433
|
var _this = this;
|
|
1361
1434
|
var labels = document.getElementById('labels');
|
|
1362
|
-
while (labels.firstChild) {
|
|
1435
|
+
while (labels && labels.firstChild) {
|
|
1363
1436
|
labels.removeChild(labels.lastChild);
|
|
1364
1437
|
}
|
|
1365
1438
|
this.chartDataTable = this.myChartDataMatrix;
|
|
@@ -1422,7 +1495,7 @@
|
|
|
1422
1495
|
for (var i = 0; i < detailViewMatrix.length; i++) {
|
|
1423
1496
|
// console.log("detailViewMatrix[i]",detailViewMatrix[i]);
|
|
1424
1497
|
id_durationArray = {
|
|
1425
|
-
name: detailViewMatrix[i].terminalIP,
|
|
1498
|
+
name: this.pdService.getRoomLabel(detailViewMatrix[i].terminalLocation, detailViewMatrix[i].terminalIP),
|
|
1426
1499
|
value: parseInt(detailViewMatrix[i].duration),
|
|
1427
1500
|
};
|
|
1428
1501
|
id_durationMatrix.push(id_durationArray);
|
|
@@ -1482,6 +1555,8 @@
|
|
|
1482
1555
|
var rowLabels = [];
|
|
1483
1556
|
this.rowElements = [];
|
|
1484
1557
|
var labels = document.getElementById('labels');
|
|
1558
|
+
if (!labels)
|
|
1559
|
+
return;
|
|
1485
1560
|
while (labels.firstChild) {
|
|
1486
1561
|
labels.removeChild(labels.lastChild);
|
|
1487
1562
|
}
|
|
@@ -1524,14 +1599,83 @@
|
|
|
1524
1599
|
}
|
|
1525
1600
|
}
|
|
1526
1601
|
};
|
|
1602
|
+
// rows for lib-timeline, one per teacher or room, bars point back into `list` by index
|
|
1603
|
+
ChartviewComponent.prototype.buildTimeline = function (list) {
|
|
1604
|
+
var _this = this;
|
|
1605
|
+
this.timelineList = list || [];
|
|
1606
|
+
var rows = [];
|
|
1607
|
+
var rowByLabel = {};
|
|
1608
|
+
this.timelineList.forEach(function (session, index) {
|
|
1609
|
+
var label = _this.isUserWise
|
|
1610
|
+
? session.userName
|
|
1611
|
+
: _this.pdService.getRoomLabel(session.terminalLocation, session.terminalIP);
|
|
1612
|
+
if (label === undefined || label === null || label === '' || label === '--')
|
|
1613
|
+
return;
|
|
1614
|
+
if (label === '-')
|
|
1615
|
+
label = 'Unknown user';
|
|
1616
|
+
var row = rowByLabel[label];
|
|
1617
|
+
if (!row) {
|
|
1618
|
+
row = rowByLabel[label] = { label: label, bars: [] };
|
|
1619
|
+
rows.push(row);
|
|
1620
|
+
}
|
|
1621
|
+
if (_this.isSession(session)) {
|
|
1622
|
+
var other = _this.isUserWise
|
|
1623
|
+
? _this.pdService.getRoomLabel(session.terminalLocation, session.terminalIP)
|
|
1624
|
+
: session.userName;
|
|
1625
|
+
var time = session.startTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }) +
|
|
1626
|
+
' – ' + session.endTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
|
|
1627
|
+
row.bars.push({
|
|
1628
|
+
start: session.startTime,
|
|
1629
|
+
end: session.endTime,
|
|
1630
|
+
index: index,
|
|
1631
|
+
tooltip: ((other || '') + "\n" + time).trim(),
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
});
|
|
1635
|
+
this.timelineRows = rows;
|
|
1636
|
+
};
|
|
1637
|
+
// idle user / room placeholders have no user or no real start time
|
|
1638
|
+
ChartviewComponent.prototype.isSession = function (session) {
|
|
1639
|
+
return !!session && !!session.userId &&
|
|
1640
|
+
session.startTime instanceof Date && !isNaN(session.startTime.getTime()) &&
|
|
1641
|
+
session.endTime instanceof Date && !isNaN(session.endTime.getTime());
|
|
1642
|
+
};
|
|
1643
|
+
// every session of one row: a teacher's day (user wise) or a room's day (classroom wise)
|
|
1644
|
+
ChartviewComponent.prototype.openRow = function (event) {
|
|
1645
|
+
var _this = this;
|
|
1646
|
+
var sessions = event.indexes
|
|
1647
|
+
.map(function (i) { return _this.timelineList[i]; })
|
|
1648
|
+
.filter(function (s) { return _this.isSession(s); })
|
|
1649
|
+
.map(function (s) { return ({ userId: s.userId, ip: s.terminalIP, start: s.startTime.getTime() }); });
|
|
1650
|
+
if (!sessions.length)
|
|
1651
|
+
return;
|
|
1652
|
+
this.pdService.detailAccentColor = event.color;
|
|
1653
|
+
this.pdService.detailRowRequest = { label: event.label, isUserWise: this.isUserWise, total: event.total, sessions: sessions };
|
|
1654
|
+
this.pdService.openSmallTable.next({ allSessions: true });
|
|
1655
|
+
};
|
|
1656
|
+
ChartviewComponent.prototype.openSession = function (event) {
|
|
1657
|
+
var index = event.index;
|
|
1658
|
+
var session = this.timelineList[index];
|
|
1659
|
+
if (!this.isSession(session))
|
|
1660
|
+
return;
|
|
1661
|
+
this.pdService.detailAccentColor = event.color;
|
|
1662
|
+
this.pdService.detailRowRequest = null;
|
|
1663
|
+
this.selectedUserData = this.pdService.dataForDetailedView(this.timelineList, this.resourceDataList, index);
|
|
1664
|
+
this.pdService.detailedviewData.next(this.selectedUserData);
|
|
1665
|
+
this.pdService.openSmallTable.next(this.selectedUserData);
|
|
1666
|
+
};
|
|
1527
1667
|
ChartviewComponent.prototype.onSelectRowData = function (event) {
|
|
1528
1668
|
var _a = event.selection[0], row = _a.row, column = _a.column;
|
|
1669
|
+
// pick the same list the chart rows were built from
|
|
1670
|
+
var selectedList = this.currentdataList.userConsoleData;
|
|
1529
1671
|
if (this.isAllUsers) {
|
|
1530
|
-
|
|
1672
|
+
selectedList = this.isUserWise ? this.alluserList.fordurationTable : this.allRoomsList.fordurationTable;
|
|
1531
1673
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1674
|
+
// idle room / user rows have no session to show
|
|
1675
|
+
if (!selectedList[row] || !selectedList[row].userId || !selectedList[row].startTime) {
|
|
1676
|
+
return;
|
|
1534
1677
|
}
|
|
1678
|
+
this.selectedUserData = this.pdService.dataForDetailedView(selectedList, this.resourceDataList, row);
|
|
1535
1679
|
var smallData = [{ 'a': this.currentdataList, 'b': row }];
|
|
1536
1680
|
// console.log("this.selectedUserData",this.selectedUserData);
|
|
1537
1681
|
this.pdService.detailedviewData.next(this.selectedUserData);
|
|
@@ -1561,6 +1705,7 @@
|
|
|
1561
1705
|
};
|
|
1562
1706
|
ChartviewComponent.prototype.userWiseCurrentData = function () {
|
|
1563
1707
|
var chartDataUserWise = this.pdService.userWiseChartData();
|
|
1708
|
+
this.buildTimeline(this.currentdataList.userConsoleData);
|
|
1564
1709
|
// console.log("chartDataUserWise",chartDataUserWise);
|
|
1565
1710
|
if (chartDataUserWise.length > 0) {
|
|
1566
1711
|
this.myChartDataMatrix = chartDataUserWise;
|
|
@@ -1571,6 +1716,7 @@
|
|
|
1571
1716
|
}
|
|
1572
1717
|
};
|
|
1573
1718
|
ChartviewComponent.prototype.userWiseAllData = function () {
|
|
1719
|
+
this.buildTimeline(this.alluserList.fordurationTable);
|
|
1574
1720
|
var chartDataUserWise = this.alluserList.forChartData;
|
|
1575
1721
|
if (chartDataUserWise.length > 0) {
|
|
1576
1722
|
this.myChartDataMatrix = chartDataUserWise;
|
|
@@ -1580,6 +1726,7 @@
|
|
|
1580
1726
|
};
|
|
1581
1727
|
ChartviewComponent.prototype.classRoomWiseCurrentData = function () {
|
|
1582
1728
|
var classRoomdata = this.pdService.classRoomWiseChartData();
|
|
1729
|
+
this.buildTimeline(this.currentdataList.userConsoleData);
|
|
1583
1730
|
console.log("classRoomdata", classRoomdata);
|
|
1584
1731
|
if (classRoomdata && classRoomdata.length > 0) {
|
|
1585
1732
|
this.myChartDataMatrix = classRoomdata;
|
|
@@ -1591,7 +1738,8 @@
|
|
|
1591
1738
|
}
|
|
1592
1739
|
};
|
|
1593
1740
|
ChartviewComponent.prototype.classRoomWiseAllData = function () {
|
|
1594
|
-
var allclassRoomList = this.pdService.allRoomsData();
|
|
1741
|
+
var allclassRoomList = this.allRoomsList || this.pdService.allRoomsData();
|
|
1742
|
+
this.buildTimeline(allclassRoomList.fordurationTable);
|
|
1595
1743
|
if (allclassRoomList.forChartData && allclassRoomList.forChartData.length > 0) {
|
|
1596
1744
|
this.myChartDataMatrix = allclassRoomList.forChartData;
|
|
1597
1745
|
this.updateChart();
|
|
@@ -1642,8 +1790,8 @@
|
|
|
1642
1790
|
ChartviewComponent.decorators = [
|
|
1643
1791
|
{ type: i0.Component, args: [{
|
|
1644
1792
|
selector: 'lib-chartview',
|
|
1645
|
-
template: "<div id=\"pd-chartview-main-container\" class=\"pd-chartview-main-container\">\n <div id=\"userSummary\">\n <table class=\"summaryTable\">\n <tbody>\n <tr>\n <td id=\"totalUsers\" class=\"chartview-navigationbar\">\n Total users: {{totalUsers}}\n </td>\n <td id=\"eligibleUsers\" class=\"chartview-navigationbar\">\n Eligible users: {{eligibleUsers}}\n </td>\n <td id=\"currentUsers\" class=\"chartview-navigationbar\">\n Current users: {{currentUsers}}\n </td>\n <td id=\"totalRooms\" class=\"chartview-navigationbar\">\n Installed Classrooms: {{installedClassrooms}}\n </td>\n <td id=\"currentRooms\" class=\"chartview-navigationbar\">\n Current Classrooms: {{currentRooms}}\n </td>\n <!-- <td\n id=\"currentRooms\"\n \n >\n <span id=\"totalUsers_list\" class=\"activeAll\">User List</span>\n </td> -->\n </tr>\n </tbody>\n </table>\n </div>\n <div id=\"pd-messageDivContainer\" class='pd-messageDivContainer'>\n <div id=\"pd-messageDiv\" class='pd-messageDiv'>Click the bars to view details of content accessed by a teacher.</div>\n <div id=\"pd-toggleContainer\" class=\"pd-toggleContainer\">\n \n <div id=\"pd-currentUserBtn\" class=\"pd-currentUserBtn-div pd-commonStyleBtn\" (click)=\"showCurrentUser()\" [ngStyle]=\"{ color: isAllUsers ? '#000000' : '#ffffff' , backgroundColor: isAllUsers ? '#c4c4c4' : '#000000'}\">\n {{currentList}}</div>\n <div id=\"pd-allUserBtn\" class=\"pd-allUserBtn-div pd-commonStyleBtn\" (click)=\"showAllUser()\" [ngStyle]=\"{ color: isAllUsers ? '#ffffff' : '#000000' , backgroundColor: isAllUsers ? '#000000' : '#c4c4c4'}\">\n {{allList}}</div>\n </div>\n </div>\n <div id=\"pd-chartview\" class=\"pd-chartview\">\n <div id=\"myChartDiv\">\n <div id=\"myTimeLine\">\n <google-chart\n [type]=\"myChartType\"\n [data]=\"chartDataTable\"\n [options]=\"myChartOptions\"\n [width]=\"myChartwidth\"\n [height]=\"myChartHeight\"\n (select)=\"onSelectRowData($event)\"\n (ready)=\"myChartReady()\"\n > \n </google-chart>\n \n </div>\n <div class=\"inline babloo\" id=\"labels\"></div> \n \n \n </div>\n</div>\n",
|
|
1646
|
-
styles: [".pd-chartview-main-container .pd-chartview{display:block;overflow:scroll;width:100%;height:484px;font-family:Tahoma;font-size:12pt;font-weight:400;color:#666;margin:10 auto;text-align:center;padding-top:1px}.pd-chartview-main-container #userSummary{background:#e0e0e0;margin-top:1px}.pd-chartview-main-container #roomSummary,.pd-chartview-main-container #userSummary{position:relative;width:100%;text-align:center;padding-top:6px;padding-bottom:6px;font-size:13px}.pd-chartview-main-container .pd-messageDivContainer{margin-top:1px}.pd-chartview-main-container .pd-messageDivContainer .pd-messageDiv{
|
|
1793
|
+
template: "<div id=\"pd-chartview-main-container\" class=\"pd-chartview-main-container\">\n <div id=\"userSummary\">\n <table class=\"summaryTable\">\n <tbody>\n <tr>\n <td id=\"totalUsers\" class=\"chartview-navigationbar\">\n Total users: {{totalUsers}}\n </td>\n <td id=\"eligibleUsers\" class=\"chartview-navigationbar\">\n Eligible users: {{eligibleUsers}}\n </td>\n <td id=\"currentUsers\" class=\"chartview-navigationbar\">\n Current users: {{currentUsers}}\n </td>\n <td id=\"totalRooms\" class=\"chartview-navigationbar\">\n Installed Classrooms: {{installedClassrooms}}\n </td>\n <td id=\"currentRooms\" class=\"chartview-navigationbar\">\n Current Classrooms: {{currentRooms}}\n </td>\n <!-- <td\n id=\"currentRooms\"\n \n >\n <span id=\"totalUsers_list\" class=\"activeAll\">User List</span>\n </td> -->\n </tr>\n </tbody>\n </table>\n </div>\n <div id=\"pd-messageDivContainer\" class='pd-messageDivContainer'>\n <div id=\"pd-messageDiv\" class='pd-messageDiv' *ngIf=\"!isTableView\">Click the bars to view details of content accessed by a teacher.</div>\n <div id=\"pd-toggleContainer\" class=\"pd-toggleContainer\">\n \n <div id=\"pd-currentUserBtn\" class=\"pd-currentUserBtn-div pd-commonStyleBtn\" (click)=\"showCurrentUser()\" [ngStyle]=\"{ color: isAllUsers ? '#000000' : '#ffffff' , backgroundColor: isAllUsers ? '#c4c4c4' : '#000000'}\">\n {{currentList}}</div>\n <div id=\"pd-allUserBtn\" class=\"pd-allUserBtn-div pd-commonStyleBtn\" (click)=\"showAllUser()\" [ngStyle]=\"{ color: isAllUsers ? '#ffffff' : '#000000' , backgroundColor: isAllUsers ? '#000000' : '#c4c4c4'}\">\n {{allList}}</div>\n </div>\n </div>\n <div id=\"pd-chartview\" class=\"pd-chartview\">\n <lib-timeline\n *ngIf=\"useCustomTimeline\"\n [rows]=\"timelineRows\"\n [labelTitle]=\"isUserWise ? 'Teacher' : 'Room'\"\n (barClick)=\"openSession($event)\"\n (totalClick)=\"openRow($event)\"\n ></lib-timeline>\n <div id=\"myChartDiv\" *ngIf=\"!useCustomTimeline\">\n <div id=\"myTimeLine\">\n <google-chart\n [type]=\"myChartType\"\n [data]=\"chartDataTable\"\n [options]=\"myChartOptions\"\n [width]=\"myChartwidth\"\n [height]=\"myChartHeight\"\n (select)=\"onSelectRowData($event)\"\n (ready)=\"myChartReady()\"\n > \n </google-chart>\n \n </div>\n <div class=\"inline babloo\" id=\"labels\"></div> \n \n \n </div>\n</div>\n",
|
|
1794
|
+
styles: [".pd-chartview-main-container .pd-chartview{display:block;overflow:scroll;width:100%;height:484px;font-family:Tahoma;font-size:12pt;font-weight:400;color:#666;margin:10 auto;text-align:center;padding-top:1px}.pd-chartview-main-container #userSummary{background:#e0e0e0;margin-top:1px}.pd-chartview-main-container #roomSummary,.pd-chartview-main-container #userSummary{position:relative;width:100%;text-align:center;padding-top:6px;padding-bottom:6px;font-size:13px}.pd-chartview-main-container .pd-messageDivContainer{margin-top:1px;position:relative;display:flex;align-items:center;justify-content:center;min-height:40px;padding:0 200px;box-sizing:border-box}.pd-chartview-main-container .pd-messageDivContainer .pd-messageDiv{font-size:13px;text-align:center}.pd-chartview-main-container .pd-messageDivContainer .pd-toggleContainer{line-height:30px;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;position:absolute;right:0;top:50%;transform:translateY(-50%)}.pd-chartview-main-container .pd-messageDivContainer .pd-allUserBtn-div{border-radius:0 5px 5px 0}.pd-chartview-main-container .pd-messageDivContainer .pd-currentUserBtn-div{border-radius:5px 0 0 5px}.pd-chartview-main-container .pd-messageDivContainer .pd-commonStyleBtn{display:inline-block;cursor:pointer;font-size:12px;width:92px;text-align:center}.pd-chartview-main-container .summaryTable{width:100%;border-collapse:collapse;border-spacing:2px;border-color:grey}.pd-chartview-main-container .activeAll{cursor:pointer;background:none!important;border-radius:13px;border:none;width:64px;height:18px!important;line-height:18px!important;color:#45a1da;margin-right:0!important;padding:1px 5px;vertical-align:sub}.pd-chartview-main-container #myTimeLine{width:89%;height:60%;margin-left:5px;overflow-x:scroll;overflow-y:hidden;float:left}.pd-chartview-main-container #myTimeLine2{width:71px;position:relative;overflow-x:hidden;overflow-y:hidden}.pd-chartview-main-container #myChartDiv{width:100%}.pd-chartview-main-container .chartview-navigationbar{border-collapse:collapse;border-right:1px solid #999;text-align:center}.pd-chartview-main-container #labels{border-right:1px solid #b7b7b7;border-top:1px solid #b7b7b7;width:10%;float:left;font-size:1.2vw;overflow-x:hidden;overflow-y:hidden}.inline{vertical-align:top;position:relative}"]
|
|
1647
1795
|
},] }
|
|
1648
1796
|
];
|
|
1649
1797
|
ChartviewComponent.ctorParameters = function () { return [
|
|
@@ -2909,13 +3057,22 @@
|
|
|
2909
3057
|
this.remaningUsers = [];
|
|
2910
3058
|
this.allUsers = [];
|
|
2911
3059
|
this.usersCheckboxChecked = false;
|
|
3060
|
+
this.classroomArray = [];
|
|
3061
|
+
this.allClassrooms = [];
|
|
2912
3062
|
this.isDisplay = false;
|
|
3063
|
+
this.isUserWise = true;
|
|
3064
|
+
this.isAllUsers = false;
|
|
3065
|
+
this.isInitialized = false;
|
|
2913
3066
|
}
|
|
2914
3067
|
Object.defineProperty(FullTableViewComponent.prototype, "data", {
|
|
2915
3068
|
set: function (res) {
|
|
2916
3069
|
if (res !== null) {
|
|
2917
3070
|
console.log('newtable', JSON.parse(res));
|
|
2918
3071
|
this.jsonResponse = JSON.parse(res);
|
|
3072
|
+
// rebuild rows when new data arrives (date change / refresh)
|
|
3073
|
+
if (this.isInitialized) {
|
|
3074
|
+
this.loadUserData();
|
|
3075
|
+
}
|
|
2919
3076
|
}
|
|
2920
3077
|
},
|
|
2921
3078
|
enumerable: false,
|
|
@@ -2924,6 +3081,13 @@
|
|
|
2924
3081
|
FullTableViewComponent.prototype.ngOnInit = function () {
|
|
2925
3082
|
var _this = this;
|
|
2926
3083
|
this.loadUserData();
|
|
3084
|
+
this.isInitialized = true;
|
|
3085
|
+
this.pdService.isUserWise_data.subscribe(function (data) {
|
|
3086
|
+
_this.isUserWise = data;
|
|
3087
|
+
});
|
|
3088
|
+
this.pdService.isAllUsers.subscribe(function (data) {
|
|
3089
|
+
_this.isAllUsers = !!data;
|
|
3090
|
+
});
|
|
2927
3091
|
this.pdService.chartType.subscribe(function (data) {
|
|
2928
3092
|
if (data) {
|
|
2929
3093
|
console.log('newTable', data);
|
|
@@ -2931,9 +3095,30 @@
|
|
|
2931
3095
|
}
|
|
2932
3096
|
});
|
|
2933
3097
|
};
|
|
3098
|
+
Object.defineProperty(FullTableViewComponent.prototype, "userRows", {
|
|
3099
|
+
get: function () {
|
|
3100
|
+
return this.isAllUsers ? this.allUsers : this.currentUserArray;
|
|
3101
|
+
},
|
|
3102
|
+
enumerable: false,
|
|
3103
|
+
configurable: true
|
|
3104
|
+
});
|
|
3105
|
+
Object.defineProperty(FullTableViewComponent.prototype, "classroomRows", {
|
|
3106
|
+
get: function () {
|
|
3107
|
+
return this.isAllUsers ? this.allClassrooms : this.classroomArray;
|
|
3108
|
+
},
|
|
3109
|
+
enumerable: false,
|
|
3110
|
+
configurable: true
|
|
3111
|
+
});
|
|
2934
3112
|
FullTableViewComponent.prototype.loadUserData = function () {
|
|
2935
3113
|
var _this = this;
|
|
2936
3114
|
var json = this.jsonResponse;
|
|
3115
|
+
this.currentUserArray = [];
|
|
3116
|
+
this.remaningUsers = [];
|
|
3117
|
+
this.allUsers = [];
|
|
3118
|
+
this.classroomArray = [];
|
|
3119
|
+
this.allClassrooms = [];
|
|
3120
|
+
if (!json)
|
|
3121
|
+
return;
|
|
2937
3122
|
var usersConsole = json.usersConsole.userConsole;
|
|
2938
3123
|
var usersMetadata = json.usersMetadata.userMetadata;
|
|
2939
3124
|
var resourcesMetadata = json.resourcesMetadata.resourceMetadata;
|
|
@@ -3013,8 +3198,96 @@
|
|
|
3013
3198
|
};
|
|
3014
3199
|
});
|
|
3015
3200
|
this.allUsers = __spread(this.currentUserArray, this.remaningUsers);
|
|
3201
|
+
this.loadClassroomData(usersConsole, usersMetadata, resourcesMetadata);
|
|
3016
3202
|
this.loadTable(this.currentUserArray);
|
|
3017
3203
|
};
|
|
3204
|
+
// Classroom wise rows: grouped by room, then by session start time
|
|
3205
|
+
FullTableViewComponent.prototype.loadClassroomData = function (usersConsole, usersMetadata, resourcesMetadata) {
|
|
3206
|
+
var _this = this;
|
|
3207
|
+
var _a, _b;
|
|
3208
|
+
var schoolTerminals = ((_b = (_a = this.jsonResponse) === null || _a === void 0 ? void 0 : _a.schoolTerminals) === null || _b === void 0 ? void 0 : _b.schoolTerminal) || [];
|
|
3209
|
+
var roomNames = {};
|
|
3210
|
+
schoolTerminals.forEach(function (terminal) {
|
|
3211
|
+
roomNames[terminal.terminalKey] = _this.getTerminalLocation(terminal);
|
|
3212
|
+
});
|
|
3213
|
+
var sessionsByRoom = {};
|
|
3214
|
+
// every session is a bar in the classroom chart, so keep sessions without resources too
|
|
3215
|
+
usersConsole.forEach(function (user) {
|
|
3216
|
+
var ip = (user === null || user === void 0 ? void 0 : user.terminalIP) || '';
|
|
3217
|
+
(sessionsByRoom[ip] = sessionsByRoom[ip] || []).push(user);
|
|
3218
|
+
});
|
|
3219
|
+
var roomLabel = function (ip) { return _this.pdService.getRoomLabel(roomNames[ip], ip); };
|
|
3220
|
+
var activeIPs = Object.keys(sessionsByRoom).sort(function (a, b) { return roomLabel(a).localeCompare(roomLabel(b), undefined, { numeric: true }); });
|
|
3221
|
+
activeIPs.forEach(function (ip) {
|
|
3222
|
+
var sessions = sessionsByRoom[ip].sort(function (a, b) { return new Date(a.startTime).getTime() - new Date(b.startTime).getTime(); });
|
|
3223
|
+
sessions.forEach(function (user, sessionIndex) {
|
|
3224
|
+
var _a;
|
|
3225
|
+
var userDetails = usersMetadata.find(function (userMeta) { return userMeta.userId === user.userId; });
|
|
3226
|
+
var startTime = new Date(user === null || user === void 0 ? void 0 : user.startTime);
|
|
3227
|
+
var endTime = new Date(user === null || user === void 0 ? void 0 : user.endTime);
|
|
3228
|
+
var totalDuration = _this.formatTime(Math.round((endTime.getTime() - startTime.getTime()) / 1000));
|
|
3229
|
+
var resources = ((_a = user === null || user === void 0 ? void 0 : user.userConsoleResources) === null || _a === void 0 ? void 0 : _a.userConsoleResource) || [];
|
|
3230
|
+
var sessionRows = resources.length > 0 ? resources : [null];
|
|
3231
|
+
sessionRows.forEach(function (userResource, resourceIndex) {
|
|
3232
|
+
var _a, _b, _c, _d;
|
|
3233
|
+
var resourceDetails = userResource && resourcesMetadata.find(function (resource) { return resource.resourceId === userResource.resourceId &&
|
|
3234
|
+
userResource.type === resource.type; });
|
|
3235
|
+
var isFirstOfSession = resourceIndex === 0;
|
|
3236
|
+
_this.classroomArray.push({
|
|
3237
|
+
room: isFirstOfSession && sessionIndex === 0 ? roomLabel(ip) : '',
|
|
3238
|
+
teacherName: isFirstOfSession ? userDetails === null || userDetails === void 0 ? void 0 : userDetails.fullName : '',
|
|
3239
|
+
date: isFirstOfSession ? user === null || user === void 0 ? void 0 : user.selectedDate : '',
|
|
3240
|
+
startTime: isFirstOfSession ? _this.formatDate(startTime) : '',
|
|
3241
|
+
endtime: isFirstOfSession ? _this.formatDate(endTime) : '',
|
|
3242
|
+
totalDuration: isFirstOfSession ? totalDuration : '',
|
|
3243
|
+
tp: (_a = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.teachingPoint) === null || _a === void 0 ? void 0 : _a.title,
|
|
3244
|
+
subject: (_b = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.subject) === null || _b === void 0 ? void 0 : _b.title,
|
|
3245
|
+
chapter: (_c = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.chapter) === null || _c === void 0 ? void 0 : _c.title,
|
|
3246
|
+
grade: (_d = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.grade) === null || _d === void 0 ? void 0 : _d.title,
|
|
3247
|
+
details: userResource ? _this.getAssetDetails(userResource, resourceDetails) : '',
|
|
3248
|
+
});
|
|
3249
|
+
});
|
|
3250
|
+
});
|
|
3251
|
+
});
|
|
3252
|
+
var idleRooms = schoolTerminals
|
|
3253
|
+
.filter(function (terminal) { return !sessionsByRoom[terminal.terminalKey]; })
|
|
3254
|
+
.map(function (terminal) { return ({
|
|
3255
|
+
room: roomLabel(terminal.terminalKey),
|
|
3256
|
+
teacherName: '',
|
|
3257
|
+
date: '',
|
|
3258
|
+
startTime: '',
|
|
3259
|
+
endtime: '',
|
|
3260
|
+
totalDuration: '0s',
|
|
3261
|
+
tp: '',
|
|
3262
|
+
subject: '',
|
|
3263
|
+
chapter: '',
|
|
3264
|
+
grade: '',
|
|
3265
|
+
details: '',
|
|
3266
|
+
}); });
|
|
3267
|
+
this.allClassrooms = __spread(this.classroomArray, idleRooms);
|
|
3268
|
+
};
|
|
3269
|
+
FullTableViewComponent.prototype.getTerminalLocation = function (terminal) {
|
|
3270
|
+
var _a;
|
|
3271
|
+
try {
|
|
3272
|
+
return (terminal === null || terminal === void 0 ? void 0 : terminal.metadata) ? ((_a = JSON.parse(terminal.metadata)) === null || _a === void 0 ? void 0 : _a.location) || '' : '';
|
|
3273
|
+
}
|
|
3274
|
+
catch (e) {
|
|
3275
|
+
return '';
|
|
3276
|
+
}
|
|
3277
|
+
};
|
|
3278
|
+
FullTableViewComponent.prototype.getAssetDetails = function (userResource, resourceDetails) {
|
|
3279
|
+
var _a, _b;
|
|
3280
|
+
var prefix = this.getDisplayTypeValue(userResource.type);
|
|
3281
|
+
var title = (resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.title) || '';
|
|
3282
|
+
var duration = parseInt((userResource === null || userResource === void 0 ? void 0 : userResource.duration) || '0');
|
|
3283
|
+
if (((_a = userResource === null || userResource === void 0 ? void 0 : userResource.type) === null || _a === void 0 ? void 0 : _a.includes('question')) || ((_b = userResource === null || userResource === void 0 ? void 0 : userResource.type) === null || _b === void 0 ? void 0 : _b.includes('cquestion'))) {
|
|
3284
|
+
duration = 0;
|
|
3285
|
+
}
|
|
3286
|
+
else {
|
|
3287
|
+
duration = duration === 0 ? "<span class='seenTag' style='color:blue;'>(Seen)</span>" : this.formatTime(duration);
|
|
3288
|
+
}
|
|
3289
|
+
return title === '' ? prefix + " : " + duration : prefix + " : " + title + " : " + duration;
|
|
3290
|
+
};
|
|
3018
3291
|
FullTableViewComponent.prototype.getDisplayTypeValue = function (key) {
|
|
3019
3292
|
var assetTypeConfig = [
|
|
3020
3293
|
{ type: 'asset_media', display: 'Media' },
|
|
@@ -3092,8 +3365,8 @@
|
|
|
3092
3365
|
FullTableViewComponent.decorators = [
|
|
3093
3366
|
{ type: i0.Component, args: [{
|
|
3094
3367
|
selector: 'lib-full-table-view',
|
|
3095
|
-
template: "\n<div class=\"tableViewList\" *ngIf=\"isDisplay\">\n <!-- <label for=\"usersCheckbox\">All</label>\n <input\n type=\"checkbox\"\n id=\"usersCheckbox\"\n [checked]=\"usersCheckboxChecked\"\n (change)=\"toggleUsers()\"\n /> -->\n <div class=\"tableArea\">\n \n <table id=\"teacherTable\">\n <thead class=\"tablehead\">\n <tr>\n <th>Teacher Name</th>\n <th>Subjects</th>\n <th>Date</th>\n <th>Start Time</th>\n <th>End Time</th>\n <th>Total Duration</th>\n <th>Room</th>\n <th>Topic</th>\n <th>Subject</th>\n <th>Chapter</th>\n <th>Grade</th>\n <th>Details</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of
|
|
3096
|
-
styles: ["body{font-family:Arial,sans-serif;margin:20px}.tablehead{position:sticky;top:0;background:#fff}table{width:100%;border-collapse:collapse}td,th{border:1px solid #ddd;padding:8px;text-align:left}th{background-color:#f4f4f4;font-weight:700}tr:nth-child(2n){background-color:#f9f9f9}tr:hover{background-color:#f1f1f1}.tableViewList{position:absolute;margin-top:20px}.tableArea{height:700px;overflow:scroll;font-size:12px;margin:20px 5px 5px}.seenTag{color:#00f}"]
|
|
3368
|
+
template: "\n<div class=\"tableViewList\" *ngIf=\"isDisplay\">\n <!-- <label for=\"usersCheckbox\">All</label>\n <input\n type=\"checkbox\"\n id=\"usersCheckbox\"\n [checked]=\"usersCheckboxChecked\"\n (change)=\"toggleUsers()\"\n /> -->\n <div class=\"tableArea\">\n \n <table id=\"teacherTable\" *ngIf=\"isUserWise\">\n <thead class=\"tablehead\">\n <tr>\n <th>Teacher Name</th>\n <th>Subjects</th>\n <th>Date</th>\n <th>Start Time</th>\n <th>End Time</th>\n <th>Total Duration</th>\n <th>Room</th>\n <th>Topic</th>\n <th>Subject</th>\n <th>Chapter</th>\n <th>Grade</th>\n <th>Details</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of userRows\">\n <td>{{ user.teacherName }}</td>\n <td>{{ user.subjects }}</td>\n <td>{{ user.date }}</td>\n <td>{{ user.startTime }}</td>\n <td>{{ user.endtime }}</td>\n <td>{{ user.totalDuration }}</td>\n <td>{{ user.room }}</td>\n <td>{{ user.tp }}</td>\n <td>{{ user.subject }}</td>\n <td>{{ user.chapter }}</td>\n <td>{{ user.grade }}</td>\n <td><div [innerHTML]=\"user.details\"></div></td>\n </tr>\n </tbody>\n </table>\n\n <table id=\"classroomTable\" *ngIf=\"!isUserWise\">\n <thead class=\"tablehead\">\n <tr>\n <th>Room</th>\n <th>Teacher Name</th>\n <th>Date</th>\n <th>Start Time</th>\n <th>End Time</th>\n <th>Total Duration</th>\n <th>Topic</th>\n <th>Subject</th>\n <th>Chapter</th>\n <th>Grade</th>\n <th>Details</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of classroomRows\" [class.roomStart]=\"row.room\">\n <td class=\"roomCell\">{{ row.room }}</td>\n <td>{{ row.teacherName }}</td>\n <td>{{ row.date }}</td>\n <td>{{ row.startTime }}</td>\n <td>{{ row.endtime }}</td>\n <td>{{ row.totalDuration }}</td>\n <td>{{ row.tp }}</td>\n <td>{{ row.subject }}</td>\n <td>{{ row.chapter }}</td>\n <td>{{ row.grade }}</td>\n <td><div [innerHTML]=\"row.details\"></div></td>\n </tr>\n </tbody>\n </table>\n </div>\n \n</div>\n ",
|
|
3369
|
+
styles: ["body{font-family:Arial,sans-serif;margin:20px}.tablehead{position:sticky;top:0;background:#fff}table{width:100%;border-collapse:collapse}td,th{border:1px solid #ddd;padding:8px;text-align:left}th{background-color:#f4f4f4;font-weight:700}tr:nth-child(2n){background-color:#f9f9f9}tr:hover{background-color:#f1f1f1}.tableViewList{position:absolute;margin-top:20px}.tableArea{height:700px;overflow:scroll;font-size:12px;margin:20px 5px 5px}.seenTag{color:#00f}.roomCell{font-weight:700}.roomStart td{border-top:2px solid #b7b7b7}"]
|
|
3097
3370
|
},] }
|
|
3098
3371
|
];
|
|
3099
3372
|
FullTableViewComponent.ctorParameters = function () { return [
|
|
@@ -3112,6 +3385,15 @@
|
|
|
3112
3385
|
this.allUsers = [];
|
|
3113
3386
|
this.usersCheckboxChecked = false;
|
|
3114
3387
|
this.isDisplay = false;
|
|
3388
|
+
this.accentColor = '';
|
|
3389
|
+
// 'session' = one bar was clicked; 'all' = a row's total was clicked
|
|
3390
|
+
this.mode = 'session';
|
|
3391
|
+
this.allTitle = '';
|
|
3392
|
+
this.allSummary = [];
|
|
3393
|
+
this.otherColumn = 'Room';
|
|
3394
|
+
// who used the room (classroom wise) or which rooms were used (user wise), with time each
|
|
3395
|
+
this.people = [];
|
|
3396
|
+
this.peopleTitle = '';
|
|
3115
3397
|
}
|
|
3116
3398
|
Object.defineProperty(SmallTableViewComponent.prototype, "data", {
|
|
3117
3399
|
set: function (res) {
|
|
@@ -3128,6 +3410,12 @@
|
|
|
3128
3410
|
this.pdService.openSmallTable$.subscribe(function (data) {
|
|
3129
3411
|
if (data) {
|
|
3130
3412
|
_this.isDisplay = true;
|
|
3413
|
+
_this.accentColor = _this.pdService.detailAccentColor;
|
|
3414
|
+
if (data['allSessions'] && _this.pdService.detailRowRequest) {
|
|
3415
|
+
_this.loadRowSessions(_this.pdService.detailRowRequest);
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
_this.mode = 'session';
|
|
3131
3419
|
var userid = _this.findUserIdByName(data['userDetails'][0]);
|
|
3132
3420
|
var startTime = data['userDetails'][1];
|
|
3133
3421
|
var endTime = data['userDetails'][3];
|
|
@@ -3159,55 +3447,8 @@
|
|
|
3159
3447
|
? usersConsole.filter(function (user) { return user.userId === userId; })
|
|
3160
3448
|
: usersConsole;
|
|
3161
3449
|
filteredUsersConsole.forEach(function (user) {
|
|
3162
|
-
var
|
|
3163
|
-
|
|
3164
|
-
if (user === null || user === void 0 ? void 0 : user.userConsoleResources) {
|
|
3165
|
-
var userConsoleResource = (_a = user.userConsoleResources) === null || _a === void 0 ? void 0 : _a.userConsoleResource;
|
|
3166
|
-
if (userConsoleResource && userConsoleResource.length > 0) {
|
|
3167
|
-
userConsoleResource.forEach(function (userResource, userIndex) {
|
|
3168
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3169
|
-
var resourceId = userResource.resourceId;
|
|
3170
|
-
var resourceDetails = resourcesMetadata.find(function (resource) { return resource.resourceId === resourceId &&
|
|
3171
|
-
userResource.type === resource.type; });
|
|
3172
|
-
var prefix = _this.getDisplayTypeValue(userResource.type);
|
|
3173
|
-
var title = (resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.title) || '';
|
|
3174
|
-
var tp = _this.decodeHtmlEntities((_a = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.teachingPoint) === null || _a === void 0 ? void 0 : _a.title);
|
|
3175
|
-
var subject = _this.decodeHtmlEntities((_b = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.subject) === null || _b === void 0 ? void 0 : _b.title);
|
|
3176
|
-
var chapter = _this.decodeHtmlEntities((_c = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.chapter) === null || _c === void 0 ? void 0 : _c.title);
|
|
3177
|
-
var grade = _this.decodeHtmlEntities((_d = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.grade) === null || _d === void 0 ? void 0 : _d.title);
|
|
3178
|
-
var startTime = new Date(user === null || user === void 0 ? void 0 : user.startTime);
|
|
3179
|
-
var endTime = new Date(user === null || user === void 0 ? void 0 : user.endTime);
|
|
3180
|
-
var totalDuration = _this.formatTime(Math.round((endTime.getTime() - startTime.getTime()) / 1000));
|
|
3181
|
-
var duration = parseInt((userResource === null || userResource === void 0 ? void 0 : userResource.duration) || '0');
|
|
3182
|
-
//duration = duration === 0 ? "<span class='dddd'>(Seen)</span>" : this.formatTime(duration);
|
|
3183
|
-
if (((_e = userResource === null || userResource === void 0 ? void 0 : userResource.type) === null || _e === void 0 ? void 0 : _e.includes('question')) || ((_f = userResource === null || userResource === void 0 ? void 0 : userResource.type) === null || _f === void 0 ? void 0 : _f.includes('cquestion'))) {
|
|
3184
|
-
duration = 0;
|
|
3185
|
-
}
|
|
3186
|
-
else {
|
|
3187
|
-
duration = duration === 0 ? "<span class='dddd'>(Seen)</span>" : _this.formatTime(duration);
|
|
3188
|
-
}
|
|
3189
|
-
var finalAssetTitle = prefix + " : " + title + " : " + duration;
|
|
3190
|
-
if (title === '') {
|
|
3191
|
-
finalAssetTitle = prefix + " : " + duration;
|
|
3192
|
-
}
|
|
3193
|
-
_this.currentUserArray.push({
|
|
3194
|
-
userId: user.userId,
|
|
3195
|
-
teacherName: userIndex === 0 ? userDetails === null || userDetails === void 0 ? void 0 : userDetails.fullName : '',
|
|
3196
|
-
subjects: userIndex === 0 ? userDetails === null || userDetails === void 0 ? void 0 : userDetails.userSubjects : '',
|
|
3197
|
-
date: userIndex === 0 ? user === null || user === void 0 ? void 0 : user.selectedDate : '',
|
|
3198
|
-
startTime: userIndex === 0 ? _this.formatDate(startTime) : _this.formatDate(startTime),
|
|
3199
|
-
endtime: userIndex === 0 ? _this.formatDate(endTime) : _this.formatDate(endTime),
|
|
3200
|
-
totalDuration: userIndex === 0 ? totalDuration : '',
|
|
3201
|
-
room: userIndex === 0 ? user === null || user === void 0 ? void 0 : user.terminalIP : '',
|
|
3202
|
-
tp: tp,
|
|
3203
|
-
subject: subject,
|
|
3204
|
-
chapter: chapter,
|
|
3205
|
-
grade: grade,
|
|
3206
|
-
details: finalAssetTitle,
|
|
3207
|
-
});
|
|
3208
|
-
});
|
|
3209
|
-
}
|
|
3210
|
-
}
|
|
3450
|
+
var _g;
|
|
3451
|
+
(_g = _this.currentUserArray).push.apply(_g, __spread(_this.rowsForConsole(user, usersMetadata, resourcesMetadata)));
|
|
3211
3452
|
});
|
|
3212
3453
|
var currentUserIds = this.currentUserArray
|
|
3213
3454
|
.map(function (x) { return x.userId; })
|
|
@@ -3235,6 +3476,148 @@
|
|
|
3235
3476
|
this.currentTimeFrameUserArray = this.filterDataByCriteria(this.currentUserArray, userId, inputStartTime, inputEndTime);
|
|
3236
3477
|
console.log('smallData', this.currentTimeFrameUserArray);
|
|
3237
3478
|
};
|
|
3479
|
+
// every session of a timeline row, oldest first; sessions with nothing opened still get a line
|
|
3480
|
+
SmallTableViewComponent.prototype.loadRowSessions = function (request) {
|
|
3481
|
+
var _this = this;
|
|
3482
|
+
this.mode = 'all';
|
|
3483
|
+
var json = this.jsonResponse;
|
|
3484
|
+
var usersConsole = json.usersConsole.userConsole;
|
|
3485
|
+
var usersMetadata = json.usersMetadata.userMetadata;
|
|
3486
|
+
var resourcesMetadata = json.resourcesMetadata.resourceMetadata;
|
|
3487
|
+
var wanted = request.sessions;
|
|
3488
|
+
var entries = usersConsole
|
|
3489
|
+
.filter(function (c) { return wanted.some(function (s) { return s.userId === c.userId && s.ip === c.terminalIP && s.start === new Date(c.startTime).getTime(); }); })
|
|
3490
|
+
.sort(function (a, b) { return new Date(a.startTime).getTime() - new Date(b.startTime).getTime(); });
|
|
3491
|
+
var teacherName = function (id) { return (usersMetadata.find(function (u) { return u.userId === id; }) || {}).fullName || ''; };
|
|
3492
|
+
var roomLabel = function (ip) { return _this.getRoomName(ip) || ip; };
|
|
3493
|
+
this.otherColumn = request.isUserWise ? 'Room' : 'Teacher';
|
|
3494
|
+
var rows = [];
|
|
3495
|
+
entries.forEach(function (c) {
|
|
3496
|
+
var start = new Date(c.startTime);
|
|
3497
|
+
var end = new Date(c.endTime);
|
|
3498
|
+
var head = {
|
|
3499
|
+
sessionHead: true,
|
|
3500
|
+
sessionTime: _this.formatClock(start) + " \u2013 " + _this.formatClock(end),
|
|
3501
|
+
sessionDuration: _this.formatTime(Math.round((end.getTime() - start.getTime()) / 1000)),
|
|
3502
|
+
sessionOther: request.isUserWise ? roomLabel(c.terminalIP) : teacherName(c.userId),
|
|
3503
|
+
};
|
|
3504
|
+
var sessionRows = _this.rowsForConsole(c, usersMetadata, resourcesMetadata);
|
|
3505
|
+
if (sessionRows.length === 0) {
|
|
3506
|
+
rows.push(Object.assign(Object.assign({}, head), { empty: true }));
|
|
3507
|
+
}
|
|
3508
|
+
else {
|
|
3509
|
+
sessionRows.forEach(function (r, i) { return rows.push(i === 0 ? Object.assign(Object.assign({}, r), head) : r); });
|
|
3510
|
+
}
|
|
3511
|
+
});
|
|
3512
|
+
this.currentTimeFrameUserArray = rows;
|
|
3513
|
+
// time per teacher (or per room), in order of first appearance
|
|
3514
|
+
var timeByOther = new Map();
|
|
3515
|
+
entries.forEach(function (c) {
|
|
3516
|
+
var key = request.isUserWise ? roomLabel(c.terminalIP) : teacherName(c.userId);
|
|
3517
|
+
if (!key)
|
|
3518
|
+
return;
|
|
3519
|
+
var ms = new Date(c.endTime).getTime() - new Date(c.startTime).getTime();
|
|
3520
|
+
timeByOther.set(key, (timeByOther.get(key) || 0) + Math.max(ms, 0));
|
|
3521
|
+
});
|
|
3522
|
+
this.people = Array.from(timeByOther.entries()).map(function (_g) {
|
|
3523
|
+
var _h = __read(_g, 2), label = _h[0], ms = _h[1];
|
|
3524
|
+
return ({ label: label, time: _this.formatTime(Math.round(ms / 1000)) });
|
|
3525
|
+
});
|
|
3526
|
+
this.peopleTitle = request.isUserWise ? 'Rooms used' : 'Teachers in this room';
|
|
3527
|
+
// a bare room number reads better as "Room 39"
|
|
3528
|
+
this.allTitle = !request.isUserWise && /^\d+$/.test(String(request.label).trim()) ? "Room " + request.label : request.label;
|
|
3529
|
+
this.allSummary = [
|
|
3530
|
+
{ label: 'Sessions', value: "" + entries.length, icon: 'sessions', tone: 'lime' },
|
|
3531
|
+
// just the count here; the names are listed under the cards
|
|
3532
|
+
{ label: request.isUserWise ? 'Rooms' : 'Teachers', value: "" + this.people.length, icon: request.isUserWise ? 'room' : 'teacher', tone: 'sand' },
|
|
3533
|
+
{ label: 'First start', value: entries.length ? this.formatDate(new Date(entries[0].startTime)) : '—', icon: 'start', tone: 'sky' },
|
|
3534
|
+
{
|
|
3535
|
+
label: 'Last end',
|
|
3536
|
+
value: entries.length ? this.formatDate(new Date(Math.max.apply(Math, __spread(entries.map(function (c) { return new Date(c.endTime).getTime(); }))))) : '—',
|
|
3537
|
+
icon: 'end',
|
|
3538
|
+
tone: 'sky',
|
|
3539
|
+
},
|
|
3540
|
+
{ label: 'Total time', value: request.total || '—', icon: 'clock', tone: 'mint' },
|
|
3541
|
+
];
|
|
3542
|
+
};
|
|
3543
|
+
Object.defineProperty(SmallTableViewComponent.prototype, "sessionSummary", {
|
|
3544
|
+
// cards for a single session, read from the first row of that session
|
|
3545
|
+
get: function () {
|
|
3546
|
+
var first = this.currentTimeFrameUserArray[0] || {};
|
|
3547
|
+
return [
|
|
3548
|
+
{ label: 'Subject', value: first.subject || '—', icon: 'subject', tone: 'lime' },
|
|
3549
|
+
{ label: 'Room', value: first.roomName || first.room || '—', sub: first.roomName ? first.room : '', icon: 'room', tone: 'sand' },
|
|
3550
|
+
{ label: 'Start', value: first.startTime || '—', icon: 'start', tone: 'sky' },
|
|
3551
|
+
{ label: 'End', value: first.endtime || '—', icon: 'end', tone: 'sky' },
|
|
3552
|
+
{ label: 'Total time', value: first.totalDuration || '—', icon: 'clock', tone: 'mint' },
|
|
3553
|
+
];
|
|
3554
|
+
},
|
|
3555
|
+
enumerable: false,
|
|
3556
|
+
configurable: true
|
|
3557
|
+
});
|
|
3558
|
+
SmallTableViewComponent.prototype.formatClock = function (date) {
|
|
3559
|
+
var hours = date.getHours();
|
|
3560
|
+
return (hours % 12 || 12) + ":" + date.getMinutes().toString().padStart(2, '0') + " " + (hours >= 12 ? 'PM' : 'AM');
|
|
3561
|
+
};
|
|
3562
|
+
// one row per resource opened in a single console session
|
|
3563
|
+
SmallTableViewComponent.prototype.rowsForConsole = function (user, usersMetadata, resourcesMetadata) {
|
|
3564
|
+
var _this = this;
|
|
3565
|
+
var _a;
|
|
3566
|
+
var rows = [];
|
|
3567
|
+
var userDetails = usersMetadata.find(function (userMeta) { return userMeta.userId === user.userId; });
|
|
3568
|
+
if (user === null || user === void 0 ? void 0 : user.userConsoleResources) {
|
|
3569
|
+
var userConsoleResource = (_a = user.userConsoleResources) === null || _a === void 0 ? void 0 : _a.userConsoleResource;
|
|
3570
|
+
if (userConsoleResource && userConsoleResource.length > 0) {
|
|
3571
|
+
userConsoleResource.forEach(function (userResource, userIndex) {
|
|
3572
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3573
|
+
var resourceId = userResource.resourceId;
|
|
3574
|
+
var resourceDetails = resourcesMetadata.find(function (resource) { return resource.resourceId === resourceId &&
|
|
3575
|
+
userResource.type === resource.type; });
|
|
3576
|
+
var prefix = _this.getDisplayTypeValue(userResource.type);
|
|
3577
|
+
var title = (resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.title) || '';
|
|
3578
|
+
var tp = _this.decodeHtmlEntities((_a = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.teachingPoint) === null || _a === void 0 ? void 0 : _a.title);
|
|
3579
|
+
var subject = _this.decodeHtmlEntities((_b = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.subject) === null || _b === void 0 ? void 0 : _b.title);
|
|
3580
|
+
var chapter = _this.decodeHtmlEntities((_c = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.chapter) === null || _c === void 0 ? void 0 : _c.title);
|
|
3581
|
+
var grade = _this.decodeHtmlEntities((_d = resourceDetails === null || resourceDetails === void 0 ? void 0 : resourceDetails.grade) === null || _d === void 0 ? void 0 : _d.title);
|
|
3582
|
+
var startTime = new Date(user === null || user === void 0 ? void 0 : user.startTime);
|
|
3583
|
+
var endTime = new Date(user === null || user === void 0 ? void 0 : user.endTime);
|
|
3584
|
+
var totalDuration = _this.formatTime(Math.round((endTime.getTime() - startTime.getTime()) / 1000));
|
|
3585
|
+
var duration = parseInt((userResource === null || userResource === void 0 ? void 0 : userResource.duration) || '0');
|
|
3586
|
+
//duration = duration === 0 ? "<span class='dddd'>(Seen)</span>" : this.formatTime(duration);
|
|
3587
|
+
if (((_e = userResource === null || userResource === void 0 ? void 0 : userResource.type) === null || _e === void 0 ? void 0 : _e.includes('question')) || ((_f = userResource === null || userResource === void 0 ? void 0 : userResource.type) === null || _f === void 0 ? void 0 : _f.includes('cquestion'))) {
|
|
3588
|
+
duration = 0;
|
|
3589
|
+
}
|
|
3590
|
+
else {
|
|
3591
|
+
duration = duration === 0 ? "<span class='dddd'>(Seen)</span>" : _this.formatTime(duration);
|
|
3592
|
+
}
|
|
3593
|
+
var finalAssetTitle = prefix + " : " + title + " : " + duration;
|
|
3594
|
+
if (title === '') {
|
|
3595
|
+
finalAssetTitle = prefix + " : " + duration;
|
|
3596
|
+
}
|
|
3597
|
+
rows.push({
|
|
3598
|
+
userId: user.userId,
|
|
3599
|
+
teacherName: userIndex === 0 ? userDetails === null || userDetails === void 0 ? void 0 : userDetails.fullName : '',
|
|
3600
|
+
subjects: userIndex === 0 ? userDetails === null || userDetails === void 0 ? void 0 : userDetails.userSubjects : '',
|
|
3601
|
+
date: userIndex === 0 ? user === null || user === void 0 ? void 0 : user.selectedDate : '',
|
|
3602
|
+
startTime: userIndex === 0 ? _this.formatDate(startTime) : _this.formatDate(startTime),
|
|
3603
|
+
endtime: userIndex === 0 ? _this.formatDate(endTime) : _this.formatDate(endTime),
|
|
3604
|
+
// kept on every row: the popup reads it from whichever row comes first
|
|
3605
|
+
totalDuration: totalDuration,
|
|
3606
|
+
room: userIndex === 0 ? user === null || user === void 0 ? void 0 : user.terminalIP : '',
|
|
3607
|
+
roomName: userIndex === 0 ? _this.getRoomName(user === null || user === void 0 ? void 0 : user.terminalIP) : '',
|
|
3608
|
+
tp: tp,
|
|
3609
|
+
subject: subject,
|
|
3610
|
+
chapter: chapter,
|
|
3611
|
+
grade: grade,
|
|
3612
|
+
details: finalAssetTitle,
|
|
3613
|
+
ip: user === null || user === void 0 ? void 0 : user.terminalIP,
|
|
3614
|
+
sessionStart: startTime.getTime(),
|
|
3615
|
+
});
|
|
3616
|
+
});
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
return rows;
|
|
3620
|
+
};
|
|
3238
3621
|
SmallTableViewComponent.prototype.filterDataByCriteria = function (userData, inputUserId, inputStartTime, inputEndTime) {
|
|
3239
3622
|
var parseTime = function (timeString) {
|
|
3240
3623
|
if (!timeString)
|
|
@@ -3332,6 +3715,23 @@
|
|
|
3332
3715
|
? this.allUsers
|
|
3333
3716
|
: this.currentUserArray);
|
|
3334
3717
|
};
|
|
3718
|
+
// room name from schoolTerminals metadata, '' when not set
|
|
3719
|
+
SmallTableViewComponent.prototype.getRoomName = function (ip) {
|
|
3720
|
+
var _a, _b, _c;
|
|
3721
|
+
var terminals = ((_b = (_a = this.jsonResponse) === null || _a === void 0 ? void 0 : _a.schoolTerminals) === null || _b === void 0 ? void 0 : _b.schoolTerminal) || [];
|
|
3722
|
+
var terminal = terminals.find(function (t) { return t.terminalKey === ip; });
|
|
3723
|
+
try {
|
|
3724
|
+
return (terminal === null || terminal === void 0 ? void 0 : terminal.metadata) ? (((_c = JSON.parse(terminal.metadata)) === null || _c === void 0 ? void 0 : _c.location) || '').trim() : '';
|
|
3725
|
+
}
|
|
3726
|
+
catch (e) {
|
|
3727
|
+
return '';
|
|
3728
|
+
}
|
|
3729
|
+
};
|
|
3730
|
+
SmallTableViewComponent.prototype.onEscape = function () {
|
|
3731
|
+
if (this.isDisplay) {
|
|
3732
|
+
this.onCloseBtnClick();
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3335
3735
|
SmallTableViewComponent.prototype.onCloseBtnClick = function () {
|
|
3336
3736
|
this.isDisplay = false;
|
|
3337
3737
|
//this.pdService.openSmallTable.next(false);
|
|
@@ -3341,15 +3741,797 @@
|
|
|
3341
3741
|
SmallTableViewComponent.decorators = [
|
|
3342
3742
|
{ type: i0.Component, args: [{
|
|
3343
3743
|
selector: 'lib-small-table-view',
|
|
3344
|
-
template: "<div
|
|
3345
|
-
styles: ["
|
|
3744
|
+
template: "<div class=\"pd-detail-backdrop\" *ngIf=\"isDisplay\" (click)=\"onCloseBtnClick()\">\n <div id=\"pd-deatilViewContainer\" class=\"pd-detail-dialog\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"pd-detail-title\" (click)=\"$event.stopPropagation()\">\n <div class=\"pd-detail-header\">\n <div class=\"pd-detail-heading\">\n <span class=\"pd-detail-swatch\" *ngIf=\"accentColor\" [style.background-color]=\"accentColor\"></span>\n <div>\n <div id=\"pd-detail-title\" class=\"pd-detail-title\">{{ (mode === 'all' ? allTitle : currentTimeFrameUserArray[0]?.teacherName) || 'Details' }}</div>\n <div class=\"pd-detail-subtitle\">{{ mode === 'all' ? 'All Sessions Today' : 'Session Details' }}</div>\n </div>\n </div>\n <button type=\"button\" class=\"pd-detail-close\" aria-label=\"Close\" (click)=\"onCloseBtnClick()\">×</button>\n </div>\n\n <div class=\"pd-detail-summary\">\n <div class=\"pd-detail-card\" *ngFor=\"let card of (mode === 'all' ? allSummary : sessionSummary)\" [ngClass]=\"'pd-tone-' + card.tone\">\n <div class=\"pd-detail-card-label\">\n <span class=\"pd-card-icon\" [ngSwitch]=\"card.icon\" aria-hidden=\"true\">\n <svg *ngSwitchCase=\"'sessions'\" viewBox=\"0 0 24 24\"><path d=\"M4 6h16M4 12h16M4 18h10\" /></svg>\n <svg *ngSwitchCase=\"'room'\" viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" /><path d=\"M12 16v4M8 20h8\" /></svg>\n <svg *ngSwitchCase=\"'teacher'\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"8\" r=\"4\" /><path d=\"M4 20c0-4 3.6-6 8-6s8 2 8 6\" /></svg>\n <svg *ngSwitchCase=\"'subject'\" viewBox=\"0 0 24 24\"><path d=\"M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2V5z\" /><path d=\"M4 19a2 2 0 0 1 2-2h13\" /></svg>\n <svg *ngSwitchCase=\"'start'\" viewBox=\"0 0 24 24\"><path d=\"M14 4h4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-4\" /><path d=\"M4 12h11M11 8l4 4-4 4\" /></svg>\n <svg *ngSwitchCase=\"'end'\" viewBox=\"0 0 24 24\"><path d=\"M10 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h4\" /><path d=\"M9 12h11M16 8l4 4-4 4\" /></svg>\n <svg *ngSwitchCase=\"'clock'\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"M12 7v5l3 2\" /></svg>\n </span>\n {{ card.label }}\n </div>\n <div class=\"pd-detail-card-value\">\n {{ card.value }}\n <span class=\"pd-detail-muted\" *ngIf=\"card.sub\">{{ card.sub }}</span>\n </div>\n </div>\n </div>\n\n <div class=\"pd-people\" *ngIf=\"mode === 'all' && people.length\">\n <span class=\"pd-people-title\">{{ peopleTitle }}</span>\n <span class=\"pd-person\" *ngFor=\"let p of people\">{{ p.label }} <span class=\"pd-person-time\">{{ p.time }}</span></span>\n </div>\n\n <div class=\"pd-detail-body\">\n <div class=\"pd-detail-empty\" *ngIf=\"currentTimeFrameUserArray.length === 0\">No content was opened in this session.</div>\n <table class=\"pd-detail-table\" *ngIf=\"currentTimeFrameUserArray.length > 0\">\n <thead>\n <tr>\n <ng-container *ngIf=\"mode === 'all'\">\n <th>Time</th>\n <th>{{ otherColumn }}</th>\n </ng-container>\n <th>Subject</th>\n <th>Class</th>\n <th>Chapter</th>\n <th>Topic</th>\n <th>Asset details</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let item of currentTimeFrameUserArray\" [class.pd-session-start]=\"mode === 'all' && item.sessionHead\">\n <ng-container *ngIf=\"mode === 'all'\">\n <td class=\"pd-nowrap\">\n <ng-container *ngIf=\"item.sessionHead\">\n {{ item.sessionTime }}\n <div class=\"pd-detail-muted\">{{ item.sessionDuration }}</div>\n </ng-container>\n </td>\n <td>{{ item.sessionHead ? item.sessionOther : '' }}</td>\n </ng-container>\n <ng-container *ngIf=\"!item.empty\">\n <td>{{ item.subject || '\u2014' }}</td>\n <td class=\"pd-nowrap\">{{ item.grade || '\u2014' }}</td>\n <td>{{ item.chapter || '\u2014' }}</td>\n <td [class.pd-detail-muted]=\"!item.tp\">{{ item.tp || '\u2014' }}</td>\n <td [innerHTML]=\"item.details || ''\"></td>\n </ng-container>\n <td *ngIf=\"item.empty\" colspan=\"5\" class=\"pd-detail-muted\">No content was opened in this session.</td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</div>\n",
|
|
3745
|
+
styles: [".pd-detail-backdrop{position:fixed;inset:0;top:0;left:0;right:0;bottom:0;z-index:1000;background:rgba(17,24,39,.45);display:flex;align-items:center;justify-content:center;padding:16px;box-sizing:border-box}.pd-detail-dialog{background:#fff;border-radius:12px;box-shadow:0 20px 50px rgba(0,0,0,.25);width:900px;max-width:100%;height:600px;max-height:85vh;display:flex;flex-direction:column;overflow:hidden;font-family:Arial,sans-serif;font-size:13px;color:#1f2937}.pd-detail-header{flex:0 0 auto;display:flex;align-items:flex-start;justify-content:space-between;padding:18px 20px 12px;border-bottom:1px solid #e5e7eb}.pd-detail-title{font-size:20px;font-weight:700;line-height:1.3;color:#1f2937}.pd-detail-heading{display:flex;align-items:flex-start;gap:12px}.pd-detail-swatch{flex:0 0 auto;width:14px;height:14px;border-radius:50%;margin-top:6px}.pd-detail-subtitle{font-size:15px;font-weight:700;color:#c9952b;margin-top:4px}.pd-detail-close{border:none;background:#f3f4f6;color:#374151;width:32px;height:32px;border-radius:50%;font-size:22px;line-height:30px;cursor:pointer;flex-shrink:0}.pd-detail-close:hover{background:#e5e7eb}.pd-detail-summary{flex:0 0 auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;padding:14px 20px}.pd-detail-card{background:#f9fafb;border:1px solid #e5e7eb;border-radius:10px;padding:12px 14px;text-align:center}.pd-detail-card.pd-tone-lime{background:#eef6a3;border-color:#dfe98a}.pd-detail-card.pd-tone-sand{background:#f6ecd9;border-color:#ebdcc0}.pd-detail-card.pd-tone-sky{background:#e1edfb;border-color:#cbdcf3}.pd-detail-card.pd-tone-mint{background:#f3fbe6;border-color:#dfeecb}.pd-detail-card-label{display:flex;align-items:center;justify-content:center;gap:6px;font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:#6b7280;margin-bottom:6px}.pd-card-icon{display:inline-flex}.pd-card-icon svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.pd-detail-card-value{font-size:15px;font-weight:700;word-break:break-word}.pd-people{flex:0 0 auto;display:flex;flex-wrap:wrap;align-items:center;gap:6px;max-height:72px;overflow:auto;padding:0 20px 12px}.pd-people-title{font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:#6b7280;margin-right:4px}.pd-person{padding:4px 10px;border-radius:999px;background:#f6ecd9;border:1px solid #ebdcc0;font-size:12px;font-weight:700;color:#1f2937}.pd-person-time{font-weight:400;color:#6b7280;margin-left:4px}.pd-detail-muted{color:#9ca3af;font-weight:400}.pd-detail-body{overflow:auto;margin:0 20px 20px;flex:1 1 auto;min-height:0;border:1px solid #e5e7eb;border-radius:8px}.pd-detail-table{width:100%;border-collapse:separate;border-spacing:0}.pd-detail-table td,.pd-detail-table th{text-align:left;padding:9px 12px;border-bottom:1px solid #f0f0f0;vertical-align:top}.pd-detail-table th{position:sticky;top:0;z-index:1;background:#f3f4f6;font-size:12px;color:#4b5563;font-weight:700}.pd-detail-table tbody tr:nth-child(2n) td{background:#fafafa}.pd-detail-table tbody tr.pd-session-start:not(:first-child) td{border-top:2px solid #e5e7eb}.pd-detail-table tbody tr:last-child td{border-bottom:none}.pd-detail-table tbody tr:hover td{background:#eef2ff}.pd-nowrap{white-space:nowrap}.pd-detail-empty{padding:24px;text-align:center;color:#6b7280}:host ::ng-deep .dddd{color:#2563eb;font-style:italic}"]
|
|
3346
3746
|
},] }
|
|
3347
3747
|
];
|
|
3348
3748
|
SmallTableViewComponent.ctorParameters = function () { return [
|
|
3349
3749
|
{ type: PrincipalDashboardLibV2Service }
|
|
3350
3750
|
]; };
|
|
3351
3751
|
SmallTableViewComponent.propDecorators = {
|
|
3352
|
-
data: [{ type: i0.Input }]
|
|
3752
|
+
data: [{ type: i0.Input }],
|
|
3753
|
+
onEscape: [{ type: i0.HostListener, args: ['document:keydown.escape',] }]
|
|
3754
|
+
};
|
|
3755
|
+
|
|
3756
|
+
var TimelineComponent = /** @class */ (function () {
|
|
3757
|
+
function TimelineComponent() {
|
|
3758
|
+
this.rows = [];
|
|
3759
|
+
this.labelTitle = 'Name';
|
|
3760
|
+
this.barClick = new i0.EventEmitter();
|
|
3761
|
+
// clicking a row's total asks for every session in that row
|
|
3762
|
+
this.totalClick = new i0.EventEmitter();
|
|
3763
|
+
this.renderedRows = [];
|
|
3764
|
+
this.ticks = [];
|
|
3765
|
+
// :15 and :45 marks, drawn in the header only, without labels
|
|
3766
|
+
this.quarterTicks = [];
|
|
3767
|
+
// fixed width per hour so a full day scrolls horizontally instead of squeezing
|
|
3768
|
+
this.hourWidth = 160;
|
|
3769
|
+
this.minWidth = 0;
|
|
3770
|
+
this.nowLeft = null;
|
|
3771
|
+
this.sortKey = 'default';
|
|
3772
|
+
this.sortAsc = true;
|
|
3773
|
+
this.tooltip = null;
|
|
3774
|
+
this.rangeStart = 0;
|
|
3775
|
+
this.rangeEnd = 0;
|
|
3776
|
+
}
|
|
3777
|
+
TimelineComponent.prototype.ngOnChanges = function () {
|
|
3778
|
+
this.render();
|
|
3779
|
+
};
|
|
3780
|
+
TimelineComponent.prototype.render = function () {
|
|
3781
|
+
var _this = this;
|
|
3782
|
+
var rows = this.rows || [];
|
|
3783
|
+
var allBars = rows.reduce(function (acc, row) { return acc.concat(row.bars); }, []);
|
|
3784
|
+
if (allBars.length === 0) {
|
|
3785
|
+
this.ticks = [];
|
|
3786
|
+
this.quarterTicks = [];
|
|
3787
|
+
this.nowLeft = null;
|
|
3788
|
+
this.minWidth = 0;
|
|
3789
|
+
this.renderedRows = rows.map(function (row, i) { return _this.toRenderedRow(row, i); });
|
|
3790
|
+
this.applySort();
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
var minStart = Math.min.apply(Math, __spread(allBars.map(function (b) { return b.start.getTime(); })));
|
|
3794
|
+
var maxEnd = Math.max.apply(Math, __spread(allBars.map(function (b) { return b.end.getTime(); })));
|
|
3795
|
+
var hour = 3600 * 1000;
|
|
3796
|
+
var startDate = new Date(minStart);
|
|
3797
|
+
startDate.setMinutes(0, 0, 0);
|
|
3798
|
+
this.rangeStart = startDate.getTime();
|
|
3799
|
+
this.rangeEnd = Math.max(Math.ceil((maxEnd - this.rangeStart) / hour) * hour + this.rangeStart, this.rangeStart + hour);
|
|
3800
|
+
var spanHours = (this.rangeEnd - this.rangeStart) / hour;
|
|
3801
|
+
// label (170) + total (90) + track margins (48) + hours
|
|
3802
|
+
this.minWidth = 170 + 90 + 48 + spanHours * this.hourWidth;
|
|
3803
|
+
this.ticks = [];
|
|
3804
|
+
this.quarterTicks = [];
|
|
3805
|
+
for (var t = this.rangeStart; t <= this.rangeEnd; t += hour / 4) {
|
|
3806
|
+
var minutes = new Date(t).getMinutes();
|
|
3807
|
+
if (minutes === 15 || minutes === 45) {
|
|
3808
|
+
this.quarterTicks.push(this.toPercent(t));
|
|
3809
|
+
}
|
|
3810
|
+
else {
|
|
3811
|
+
this.ticks.push({ left: this.toPercent(t), label: this.formatClock(new Date(t)), major: minutes === 0 });
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
var now = Date.now();
|
|
3815
|
+
this.nowLeft = now >= this.rangeStart && now <= this.rangeEnd ? this.toPercent(now) : null;
|
|
3816
|
+
this.renderedRows = rows.map(function (row, i) { return _this.toRenderedRow(row, i); });
|
|
3817
|
+
this.applySort();
|
|
3818
|
+
};
|
|
3819
|
+
TimelineComponent.prototype.toggleSort = function (key) {
|
|
3820
|
+
if (this.sortKey === key) {
|
|
3821
|
+
if (this.sortAsc) {
|
|
3822
|
+
this.sortAsc = false;
|
|
3823
|
+
}
|
|
3824
|
+
else {
|
|
3825
|
+
this.sortKey = 'default';
|
|
3826
|
+
this.sortAsc = true;
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
else {
|
|
3830
|
+
this.sortKey = key;
|
|
3831
|
+
this.sortAsc = key === 'name';
|
|
3832
|
+
}
|
|
3833
|
+
this.applySort();
|
|
3834
|
+
};
|
|
3835
|
+
TimelineComponent.prototype.sortIcon = function (key) {
|
|
3836
|
+
if (this.sortKey !== key)
|
|
3837
|
+
return '';
|
|
3838
|
+
return this.sortAsc ? '▲' : '▼';
|
|
3839
|
+
};
|
|
3840
|
+
TimelineComponent.prototype.onBarClick = function (bar) {
|
|
3841
|
+
this.tooltip = null;
|
|
3842
|
+
this.barClick.emit({ index: bar.index, color: bar.color });
|
|
3843
|
+
};
|
|
3844
|
+
TimelineComponent.prototype.onTotalClick = function (row) {
|
|
3845
|
+
if (!row.bars.length)
|
|
3846
|
+
return;
|
|
3847
|
+
this.tooltip = null;
|
|
3848
|
+
this.totalClick.emit({ label: row.label, indexes: row.bars.map(function (b) { return b.index; }), color: row.color, total: row.total });
|
|
3849
|
+
};
|
|
3850
|
+
TimelineComponent.prototype.showTooltip = function (event, bar) {
|
|
3851
|
+
this.tooltip = { text: bar.tooltip, x: event.clientX + 12, y: event.clientY + 12 };
|
|
3852
|
+
};
|
|
3853
|
+
TimelineComponent.prototype.hideTooltip = function () {
|
|
3854
|
+
this.tooltip = null;
|
|
3855
|
+
};
|
|
3856
|
+
TimelineComponent.prototype.trackByLabel = function (index, row) {
|
|
3857
|
+
return row.label;
|
|
3858
|
+
};
|
|
3859
|
+
TimelineComponent.prototype.toRenderedRow = function (row, i) {
|
|
3860
|
+
var _this = this;
|
|
3861
|
+
var totalMs = this.mergedDuration(row.bars);
|
|
3862
|
+
var starts = row.bars.map(function (b) { return b.start.getTime(); });
|
|
3863
|
+
var ends = row.bars.map(function (b) { return b.end.getTime(); });
|
|
3864
|
+
var spanLeft = starts.length ? this.toPercent(Math.min.apply(Math, __spread(starts))) : 0;
|
|
3865
|
+
var spanWidth = ends.length ? this.toPercent(Math.max.apply(Math, __spread(ends))) - spanLeft : 0;
|
|
3866
|
+
return {
|
|
3867
|
+
spanLeft: spanLeft,
|
|
3868
|
+
spanWidth: spanWidth,
|
|
3869
|
+
label: row.label,
|
|
3870
|
+
color: this.rowColor(i),
|
|
3871
|
+
totalMs: totalMs,
|
|
3872
|
+
total: this.formatDuration(totalMs),
|
|
3873
|
+
order: i,
|
|
3874
|
+
bars: row.bars.map(function (bar) {
|
|
3875
|
+
var left = _this.toPercent(bar.start.getTime());
|
|
3876
|
+
return Object.assign(Object.assign({}, bar), { left: left, width: Math.max(_this.toPercent(bar.end.getTime()) - left, 0), color: _this.rowColor(i) });
|
|
3877
|
+
}),
|
|
3878
|
+
};
|
|
3879
|
+
};
|
|
3880
|
+
// unique soft colour per row: golden-angle hue steps never repeat and keep neighbouring rows apart
|
|
3881
|
+
TimelineComponent.prototype.rowColor = function (index) {
|
|
3882
|
+
var hue = Math.round((217 + index * 137.508) % 360);
|
|
3883
|
+
return "hsl(" + hue + ", 62%, 68%)";
|
|
3884
|
+
};
|
|
3885
|
+
TimelineComponent.prototype.applySort = function () {
|
|
3886
|
+
var _this = this;
|
|
3887
|
+
var dir = this.sortAsc ? 1 : -1;
|
|
3888
|
+
this.renderedRows = __spread(this.renderedRows).sort(function (a, b) {
|
|
3889
|
+
if (_this.sortKey === 'name') {
|
|
3890
|
+
return dir * a.label.localeCompare(b.label, undefined, { numeric: true });
|
|
3891
|
+
}
|
|
3892
|
+
if (_this.sortKey === 'total') {
|
|
3893
|
+
return dir * (a.totalMs - b.totalMs);
|
|
3894
|
+
}
|
|
3895
|
+
return a.order - b.order;
|
|
3896
|
+
});
|
|
3897
|
+
};
|
|
3898
|
+
// overlapping sessions in the same row are counted once
|
|
3899
|
+
TimelineComponent.prototype.mergedDuration = function (bars) {
|
|
3900
|
+
var sorted = __spread(bars).sort(function (a, b) { return a.start.getTime() - b.start.getTime(); });
|
|
3901
|
+
var total = 0;
|
|
3902
|
+
var curStart = null;
|
|
3903
|
+
var curEnd = null;
|
|
3904
|
+
sorted.forEach(function (bar) {
|
|
3905
|
+
var s = bar.start.getTime();
|
|
3906
|
+
var e = bar.end.getTime();
|
|
3907
|
+
if (curEnd === null || s > curEnd) {
|
|
3908
|
+
if (curEnd !== null)
|
|
3909
|
+
total += curEnd - curStart;
|
|
3910
|
+
curStart = s;
|
|
3911
|
+
curEnd = e;
|
|
3912
|
+
}
|
|
3913
|
+
else if (e > curEnd) {
|
|
3914
|
+
curEnd = e;
|
|
3915
|
+
}
|
|
3916
|
+
});
|
|
3917
|
+
if (curEnd !== null)
|
|
3918
|
+
total += curEnd - curStart;
|
|
3919
|
+
return total;
|
|
3920
|
+
};
|
|
3921
|
+
TimelineComponent.prototype.toPercent = function (time) {
|
|
3922
|
+
var span = this.rangeEnd - this.rangeStart;
|
|
3923
|
+
return span > 0 ? ((time - this.rangeStart) / span) * 100 : 0;
|
|
3924
|
+
};
|
|
3925
|
+
TimelineComponent.prototype.formatClock = function (date) {
|
|
3926
|
+
var hours = date.getHours();
|
|
3927
|
+
var minutes = date.getMinutes();
|
|
3928
|
+
var ampm = hours >= 12 ? 'PM' : 'AM';
|
|
3929
|
+
hours = hours % 12 || 12;
|
|
3930
|
+
return minutes === 0 ? hours + " " + ampm : hours + ":" + minutes.toString().padStart(2, '0');
|
|
3931
|
+
};
|
|
3932
|
+
TimelineComponent.prototype.formatDuration = function (ms) {
|
|
3933
|
+
var totalMinutes = Math.round(ms / 60000);
|
|
3934
|
+
var hours = Math.floor(totalMinutes / 60);
|
|
3935
|
+
var minutes = totalMinutes % 60;
|
|
3936
|
+
return hours + ":" + minutes.toString().padStart(2, '0') + " hrs";
|
|
3937
|
+
};
|
|
3938
|
+
return TimelineComponent;
|
|
3939
|
+
}());
|
|
3940
|
+
TimelineComponent.decorators = [
|
|
3941
|
+
{ type: i0.Component, args: [{
|
|
3942
|
+
selector: 'lib-timeline',
|
|
3943
|
+
template: "<div class=\"tl-container\" [style.min-width.px]=\"minWidth\">\n <div class=\"tl-row tl-header\">\n <div class=\"tl-label tl-sortable\" (click)=\"toggleSort('name')\">{{ labelTitle }} {{ sortIcon('name') }}</div>\n <div class=\"tl-track tl-axis\">\n <div class=\"tl-mark tl-mark-quarter\" *ngFor=\"let left of quarterTicks\" [style.left.%]=\"left\"></div>\n <div class=\"tl-mark\" *ngFor=\"let tick of ticks\" [class.tl-mark-hour]=\"tick.major\" [style.left.%]=\"tick.left\"></div>\n <div class=\"tl-tick\" *ngFor=\"let tick of ticks\" [class.tl-minor]=\"!tick.major\" [style.left.%]=\"tick.left\">{{ tick.label }}</div>\n </div>\n <div class=\"tl-total tl-sortable\" (click)=\"toggleSort('total')\">Total {{ sortIcon('total') }}</div>\n </div>\n\n <div class=\"tl-empty\" *ngIf=\"renderedRows.length === 0\">No usage data for this view.</div>\n\n <div class=\"tl-row\" *ngFor=\"let row of renderedRows; trackBy: trackByLabel; let odd = odd\" [class.tl-odd]=\"odd\">\n <div class=\"tl-label\" [title]=\"row.label\">{{ row.label }}</div>\n <div class=\"tl-track\">\n <div class=\"tl-gridline\" *ngFor=\"let tick of ticks\" [class.tl-minor]=\"!tick.major\" [style.left.%]=\"tick.left\"></div>\n <div class=\"tl-span\" *ngIf=\"row.bars.length\" [style.left.%]=\"row.spanLeft\" [style.width.%]=\"row.spanWidth\"></div>\n <div class=\"tl-now\" *ngIf=\"nowLeft !== null\" [style.left.%]=\"nowLeft\"></div>\n <div\n class=\"tl-bar\"\n *ngFor=\"let bar of row.bars\"\n [style.left.%]=\"bar.left\"\n [style.width.%]=\"bar.width\"\n [style.background-color]=\"bar.color\"\n (click)=\"onBarClick(bar)\"\n (mousemove)=\"showTooltip($event, bar)\"\n (mouseleave)=\"hideTooltip()\"\n ></div>\n </div>\n <div\n class=\"tl-total\"\n [class.tl-total-link]=\"row.bars.length\"\n [title]=\"row.bars.length ? 'Show all sessions' : ''\"\n (click)=\"onTotalClick(row)\"\n >{{ row.bars.length ? row.total : '\u2014' }}</div>\n </div>\n\n <div class=\"tl-tooltip\" *ngIf=\"tooltip\" [style.left.px]=\"tooltip.x\" [style.top.px]=\"tooltip.y\">{{ tooltip.text }}</div>\n</div>\n",
|
|
3944
|
+
styles: [".tl-container{font-family:Arial,sans-serif;font-size:13px;color:#1f2937;border:1px solid #e5e7eb;border-radius:8px;overflow:clip;min-width:900px;box-sizing:border-box;position:relative;isolation:isolate}.tl-row{display:flex;height:30px;border-bottom:1px solid #e2e6ec;background:#fff}.tl-row:hover:not(.tl-header){background:#eef2ff}.tl-odd{background:#f4f6f9}.tl-header{position:sticky;top:0;z-index:3;height:32px;background:#f8fafc;font-weight:700;color:#475569;border-bottom:1px solid #e5e7eb}.tl-label{flex:0 0 170px;overflow:hidden;text-overflow:ellipsis;border-right:1px solid #e5e7eb;left:0}.tl-label,.tl-total{padding:0 8px;line-height:30px;text-align:right;white-space:nowrap;position:sticky;z-index:2;background:inherit}.tl-total{flex:0 0 90px;font-variant-numeric:tabular-nums;color:#334155;border-left:1px solid #e5e7eb;right:0}.tl-total-link{cursor:pointer;color:#4338ca}.tl-total-link:hover{text-decoration:underline}.tl-sortable{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:32px}.tl-track{flex:1 1 auto;position:relative;margin:0 24px}.tl-axis .tl-tick{position:absolute;top:0;line-height:24px;transform:translateX(-50%);font-weight:400;font-size:11px;color:#64748b;white-space:nowrap}.tl-axis .tl-tick.tl-minor{font-size:10px;color:#94a3b8}.tl-axis .tl-mark{position:absolute;bottom:0;height:8px;border-left:2px solid #7c9cf5;transform:translateX(-1px)}.tl-axis .tl-mark.tl-mark-hour{height:10px;border-left:2px solid #475569;transform:translateX(-1px)}.tl-axis .tl-mark.tl-mark-quarter{height:8px;border-left:1px solid #c3cad6;transform:translateX(-.5px)}.tl-gridline{position:absolute;top:0;bottom:0;border-left:1px solid #d3d2d2;z-index:3}.tl-gridline.tl-minor{border-left:1px dashed #d3d2d2}.tl-span{position:absolute;top:5px;bottom:5px;background:#e4e8ee;border-radius:2px}.tl-now{top:0;bottom:0;border-left:2px solid #f43f5e}.tl-bar,.tl-now{position:absolute;z-index:1}.tl-bar{top:5px;bottom:5px;min-width:4px;border-radius:2px;cursor:pointer;box-shadow:inset 1px 0 0 hsla(0,0%,100%,.45);transition:filter .12s}.tl-bar:hover{filter:brightness(.82);z-index:2;box-shadow:0 2px 6px rgba(79,70,229,.35)}.tl-empty{padding:16px;text-align:center;color:#666}.tl-tooltip{position:fixed;z-index:1000;background:#1e293b;color:#fff;font-size:12px;padding:6px 10px;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);white-space:pre-line;pointer-events:none;max-width:320px}"]
|
|
3945
|
+
},] }
|
|
3946
|
+
];
|
|
3947
|
+
TimelineComponent.propDecorators = {
|
|
3948
|
+
rows: [{ type: i0.Input }],
|
|
3949
|
+
labelTitle: [{ type: i0.Input }],
|
|
3950
|
+
barClick: [{ type: i0.Output }],
|
|
3951
|
+
totalClick: [{ type: i0.Output }]
|
|
3952
|
+
};
|
|
3953
|
+
|
|
3954
|
+
var MINUTE = 60 * 1000;
|
|
3955
|
+
var HOUR = 60 * MINUTE;
|
|
3956
|
+
var SHORT_SESSION_MIN = 5;
|
|
3957
|
+
// width the page is laid out at for the PDF, so the export looks the same on any screen
|
|
3958
|
+
var PDF_RENDER_WIDTH = 1280;
|
|
3959
|
+
var InsightsComponent = /** @class */ (function () {
|
|
3960
|
+
function InsightsComponent(pdService, host) {
|
|
3961
|
+
this.pdService = pdService;
|
|
3962
|
+
this.host = host;
|
|
3963
|
+
this.schoolName = '';
|
|
3964
|
+
this.dayLabel = '';
|
|
3965
|
+
this.kpis = [];
|
|
3966
|
+
this.hourly = [];
|
|
3967
|
+
this.grades = [];
|
|
3968
|
+
this.topTeachers = [];
|
|
3969
|
+
// donut of subject share: each segment is a dash along one circle
|
|
3970
|
+
this.subjectDonut = { total: '', segments: [] };
|
|
3971
|
+
this.donutRadius = 52;
|
|
3972
|
+
// columns per class, in class order
|
|
3973
|
+
this.gradeColumns = [];
|
|
3974
|
+
// one tile per room, shaded by share of the school day in use
|
|
3975
|
+
this.roomTiles = [];
|
|
3976
|
+
this.idleRooms = [];
|
|
3977
|
+
this.inactiveTeachers = [];
|
|
3978
|
+
this.contentMix = [];
|
|
3979
|
+
this.chapters = [];
|
|
3980
|
+
this.attention = [];
|
|
3981
|
+
this.hasSessions = false;
|
|
3982
|
+
this.isExporting = false;
|
|
3983
|
+
// accordion: the full follow-up lists open below the summary tiles
|
|
3984
|
+
this.detailsOpen = false;
|
|
3985
|
+
this.eligibleCount = 0;
|
|
3986
|
+
this.classroomCount = 0;
|
|
3987
|
+
this.fileDate = '';
|
|
3988
|
+
// ---------- count-up for the headline numbers
|
|
3989
|
+
this.countFrame = 0;
|
|
3990
|
+
}
|
|
3991
|
+
Object.defineProperty(InsightsComponent.prototype, "data", {
|
|
3992
|
+
set: function (res) {
|
|
3993
|
+
if (res) {
|
|
3994
|
+
this.build(typeof res === 'string' ? JSON.parse(res) : res);
|
|
3995
|
+
}
|
|
3996
|
+
},
|
|
3997
|
+
enumerable: false,
|
|
3998
|
+
configurable: true
|
|
3999
|
+
});
|
|
4000
|
+
InsightsComponent.prototype.ngAfterViewInit = function () {
|
|
4001
|
+
var _this = this;
|
|
4002
|
+
setTimeout(function () { return _this.fitHeight(); });
|
|
4003
|
+
};
|
|
4004
|
+
// fill from where the page starts down to the bottom of the window and scroll inside it
|
|
4005
|
+
InsightsComponent.prototype.fitHeight = function () {
|
|
4006
|
+
var page = this.host.nativeElement.querySelector('.in-page');
|
|
4007
|
+
if (!page)
|
|
4008
|
+
return;
|
|
4009
|
+
var top = page.getBoundingClientRect().top;
|
|
4010
|
+
page.style.height = Math.max(window.innerHeight - top, 240) + 'px';
|
|
4011
|
+
};
|
|
4012
|
+
InsightsComponent.prototype.build = function (json) {
|
|
4013
|
+
var _this = this;
|
|
4014
|
+
var users = this.list(json, 'usersMetadata', 'userMetadata');
|
|
4015
|
+
var consoles = this.list(json, 'usersConsole', 'userConsole');
|
|
4016
|
+
var resources = this.list(json, 'resourcesMetadata', 'resourceMetadata');
|
|
4017
|
+
var terminals = this.list(json, 'schoolTerminals', 'schoolTerminal');
|
|
4018
|
+
this.schoolName = (json.schoolMetadata && json.schoolMetadata.school && json.schoolMetadata.school.schoolName) || '';
|
|
4019
|
+
var userById = new Map();
|
|
4020
|
+
users.forEach(function (u) { return userById.set(u.userId, u); });
|
|
4021
|
+
var resourceById = new Map();
|
|
4022
|
+
resources.forEach(function (r) { return resourceById.set(r.resourceId, r); });
|
|
4023
|
+
var roomByIp = new Map();
|
|
4024
|
+
terminals.forEach(function (t) { return roomByIp.set(t.terminalKey, _this.pdService.getRoomLabel(_this.location(t.metadata), t.terminalKey)); });
|
|
4025
|
+
var classrooms = terminals.filter(function (t) { return t.terminalType === 'classroom'; });
|
|
4026
|
+
var sessions = consoles
|
|
4027
|
+
.map(function (c) { return ({
|
|
4028
|
+
userId: c.userId,
|
|
4029
|
+
ip: c.terminalIP,
|
|
4030
|
+
start: _this.parseTime(c.startTime),
|
|
4031
|
+
end: _this.parseTime(c.endTime),
|
|
4032
|
+
resources: ((c.userConsoleResources && c.userConsoleResources.userConsoleResource) || []).map(function (r) { return ({
|
|
4033
|
+
resourceId: r.resourceId,
|
|
4034
|
+
type: r.type,
|
|
4035
|
+
}); }),
|
|
4036
|
+
}); })
|
|
4037
|
+
.filter(function (s) { return !isNaN(s.start) && !isNaN(s.end) && s.end >= s.start; });
|
|
4038
|
+
// zero-length entries are logins with no class time; keep them out of time-based figures
|
|
4039
|
+
var timed = sessions.filter(function (s) { return s.end > s.start; });
|
|
4040
|
+
this.hasSessions = sessions.length > 0;
|
|
4041
|
+
var first = sessions.length ? new Date(Math.min.apply(Math, __spread(sessions.map(function (s) { return s.start; })))) : null;
|
|
4042
|
+
this.fileDate = first
|
|
4043
|
+
? [first.getDate(), first.getMonth() + 1].map(function (n) { return String(n).padStart(2, '0'); }).join('-') + '-' + first.getFullYear()
|
|
4044
|
+
: '';
|
|
4045
|
+
this.dayLabel = first ? first.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'short', year: 'numeric' }) : '';
|
|
4046
|
+
// ---- teachers
|
|
4047
|
+
var eligible = users.filter(function (u) { return (u.userSubjects || '') !== ''; });
|
|
4048
|
+
var timeByUser = this.groupTime(timed, function (s) { return s.userId; });
|
|
4049
|
+
var sessionsByUser = this.countBy(timed, function (s) { return s.userId; });
|
|
4050
|
+
var activeUserIds = new Set(sessions.map(function (s) { return s.userId; }));
|
|
4051
|
+
var totalTeachingMs = Array.from(timeByUser.values()).reduce(function (a, b) { return a + b; }, 0);
|
|
4052
|
+
var activeEligible = eligible.filter(function (u) { return activeUserIds.has(u.userId); }).length;
|
|
4053
|
+
this.eligibleCount = eligible.length;
|
|
4054
|
+
this.classroomCount = classrooms.length;
|
|
4055
|
+
this.topTeachers = this.toBars(Array.from(timeByUser.entries()).map(function (_a) {
|
|
4056
|
+
var _b = __read(_a, 2), id = _b[0], ms = _b[1];
|
|
4057
|
+
return ({
|
|
4058
|
+
label: _this.userName(userById.get(id), id),
|
|
4059
|
+
sub: (sessionsByUser.get(id) || 0) + " sessions",
|
|
4060
|
+
value: ms,
|
|
4061
|
+
});
|
|
4062
|
+
}), function (ms) { return _this.formatDuration(ms); }, 8);
|
|
4063
|
+
this.inactiveTeachers = eligible
|
|
4064
|
+
.filter(function (u) { return !activeUserIds.has(u.userId); })
|
|
4065
|
+
.map(function (u) { return _this.userName(u, u.userId); })
|
|
4066
|
+
.sort(function (a, b) { return a.localeCompare(b); });
|
|
4067
|
+
// ---- rooms
|
|
4068
|
+
var timeByRoom = this.groupTime(timed, function (s) { return s.ip; });
|
|
4069
|
+
var usedIps = new Set(sessions.map(function (s) { return s.ip; }));
|
|
4070
|
+
var usedClassrooms = classrooms.filter(function (t) { return usedIps.has(t.terminalKey); }).length;
|
|
4071
|
+
var daySpan = timed.length ? Math.max.apply(Math, __spread(timed.map(function (s) { return s.end; }))) - Math.min.apply(Math, __spread(timed.map(function (s) { return s.start; }))) : 0;
|
|
4072
|
+
// every installed classroom plus any other room that was used, in room order
|
|
4073
|
+
var tileIps = classrooms.map(function (t) { return t.terminalKey; }).concat(Array.from(timeByRoom.keys()).filter(function (ip) { return !classrooms.some(function (t) { return t.terminalKey === ip; }); }));
|
|
4074
|
+
var maxRoomMs = Math.max.apply(Math, __spread(Array.from(timeByRoom.values()), [1]));
|
|
4075
|
+
this.roomTiles = tileIps
|
|
4076
|
+
.map(function (ip) {
|
|
4077
|
+
var ms = timeByRoom.get(ip) || 0;
|
|
4078
|
+
var share = daySpan ? Math.round((ms / daySpan) * 100) : 0;
|
|
4079
|
+
return {
|
|
4080
|
+
label: roomByIp.get(ip) || ip,
|
|
4081
|
+
display: ms ? _this.formatDuration(ms) + " \u00B7 " + share + "% of the day" : 'Not used today',
|
|
4082
|
+
share: share,
|
|
4083
|
+
// pale blue for little use through to deep navy for the busiest room
|
|
4084
|
+
shade: share ? _this.navyShade(ms / maxRoomMs) : '',
|
|
4085
|
+
dark: !!share && Math.pow(ms / maxRoomMs, 1.8) > 0.5,
|
|
4086
|
+
// shown as an outlined tile: unused, or used for under 1% of the day
|
|
4087
|
+
idle: !share,
|
|
4088
|
+
// long names ("science lab", "127.0.0.1") take extra columns so they show in full
|
|
4089
|
+
span: Math.min(Math.ceil(((roomByIp.get(ip) || ip).length + 2) / 5), 4),
|
|
4090
|
+
};
|
|
4091
|
+
})
|
|
4092
|
+
.sort(function (a, b) { return a.label.localeCompare(b.label, undefined, { numeric: true }); });
|
|
4093
|
+
this.idleRooms = classrooms
|
|
4094
|
+
.filter(function (t) { return !usedIps.has(t.terminalKey); })
|
|
4095
|
+
.map(function (t) { return roomByIp.get(t.terminalKey); })
|
|
4096
|
+
.sort(function (a, b) { return a.localeCompare(b, undefined, { numeric: true }); });
|
|
4097
|
+
// ---- through the day: distinct teachers in a session during each hour
|
|
4098
|
+
this.hourly = [];
|
|
4099
|
+
if (timed.length) {
|
|
4100
|
+
var startHour = new Date(Math.min.apply(Math, __spread(timed.map(function (s) { return s.start; }))));
|
|
4101
|
+
startHour.setMinutes(0, 0, 0);
|
|
4102
|
+
var lastEnd = Math.max.apply(Math, __spread(timed.map(function (s) { return s.end; })));
|
|
4103
|
+
var counts = [];
|
|
4104
|
+
var _loop_1 = function (t) {
|
|
4105
|
+
var teachers = new Set(timed.filter(function (s) { return s.start < t + HOUR && s.end > t; }).map(function (s) { return s.userId; }));
|
|
4106
|
+
counts.push({ label: this_1.formatHour(new Date(t)), value: teachers.size });
|
|
4107
|
+
};
|
|
4108
|
+
var this_1 = this;
|
|
4109
|
+
for (var t = startHour.getTime(); t < lastEnd; t += HOUR) {
|
|
4110
|
+
_loop_1(t);
|
|
4111
|
+
}
|
|
4112
|
+
var max_1 = Math.max.apply(Math, __spread(counts.map(function (c) { return c.value; }), [1]));
|
|
4113
|
+
this.hourly = counts.map(function (c) { return (Object.assign(Object.assign({}, c), { percent: (c.value / max_1) * 100, peak: c.value === max_1, color: _this.utilisationColor(c.value / max_1) })); });
|
|
4114
|
+
}
|
|
4115
|
+
var peak = this.hourly.reduce(function (best, h) { return (!best || h.value > best.value ? h : best); }, null);
|
|
4116
|
+
// ---- what was taught: session time split evenly across the subjects / grades it touched
|
|
4117
|
+
var subjectTime = new Map();
|
|
4118
|
+
var gradeTime = new Map();
|
|
4119
|
+
timed.forEach(function (s) {
|
|
4120
|
+
var metas = s.resources.map(function (r) { return resourceById.get(r.resourceId); }).filter(function (m) { return !!m; });
|
|
4121
|
+
_this.share(subjectTime, metas.map(function (m) { return _this.title(m.subject); }), s.end - s.start);
|
|
4122
|
+
_this.share(gradeTime, metas.map(function (m) { return _this.title(m.grade); }), s.end - s.start);
|
|
4123
|
+
});
|
|
4124
|
+
this.subjectDonut = this.buildDonut(this.entries(subjectTime), 7);
|
|
4125
|
+
this.grades = this.toBars(this.entries(gradeTime).sort(function (a, b) { return a.label.localeCompare(b.label, undefined, { numeric: true }); }), function (ms) { return _this.formatDuration(ms); }, 0, false);
|
|
4126
|
+
this.gradeColumns = this.grades.map(function (g) { return (Object.assign(Object.assign({}, g), { short: _this.shortGrade(g.label) })); });
|
|
4127
|
+
// ---- content
|
|
4128
|
+
var launches = sessions.reduce(function (acc, s) { return acc.concat(s.resources); }, []);
|
|
4129
|
+
var typeCounts = this.countBy(launches, function (r) { return _this.typeLabel(r.type); });
|
|
4130
|
+
this.contentMix = this.toBars(Array.from(typeCounts.entries()).map(function (_a) {
|
|
4131
|
+
var _b = __read(_a, 2), label = _b[0], n = _b[1];
|
|
4132
|
+
return ({ label: label, value: n });
|
|
4133
|
+
}), function (n) { return "" + n; }, 0).map(function (item, i) { return (Object.assign(Object.assign({}, item), { color: _this.color(i), percent: (item.value / Math.max(launches.length, 1)) * 100 })); });
|
|
4134
|
+
var chapterCounts = new Map();
|
|
4135
|
+
launches.forEach(function (r) {
|
|
4136
|
+
var m = resourceById.get(r.resourceId);
|
|
4137
|
+
var chapter = m && _this.title(m.chapter);
|
|
4138
|
+
if (!chapter)
|
|
4139
|
+
return;
|
|
4140
|
+
var key = _this.title(m.subject) + "|" + _this.title(m.grade) + "|" + chapter;
|
|
4141
|
+
var cur = chapterCounts.get(key) || { n: 0, sub: [_this.title(m.subject), _this.title(m.grade)].filter(function (x) { return x; }).join(' · ') };
|
|
4142
|
+
cur.n++;
|
|
4143
|
+
chapterCounts.set(key, cur);
|
|
4144
|
+
});
|
|
4145
|
+
this.chapters = this.toBars(Array.from(chapterCounts.entries()).map(function (_a) {
|
|
4146
|
+
var _b = __read(_a, 2), key = _b[0], v = _b[1];
|
|
4147
|
+
return ({ label: key.split('|')[2], sub: v.sub, value: v.n });
|
|
4148
|
+
}), function (n) { return n + " uses"; }, 8);
|
|
4149
|
+
// ---- headline numbers
|
|
4150
|
+
var avgSession = timed.length ? totalTeachingMs / timed.length : 0;
|
|
4151
|
+
var topics = new Set(launches.filter(function (r) { return r.type === 'tp'; }).map(function (r) { return r.resourceId; }));
|
|
4152
|
+
this.kpis = [
|
|
4153
|
+
{
|
|
4154
|
+
label: 'Active Teachers',
|
|
4155
|
+
value: activeEligible + " / " + eligible.length,
|
|
4156
|
+
hint: this.pct(activeEligible, eligible.length) + " of eligible teachers",
|
|
4157
|
+
},
|
|
4158
|
+
{
|
|
4159
|
+
label: 'Classrooms Used',
|
|
4160
|
+
value: usedClassrooms + " / " + classrooms.length,
|
|
4161
|
+
hint: this.pct(usedClassrooms, classrooms.length) + " of classrooms",
|
|
4162
|
+
},
|
|
4163
|
+
{
|
|
4164
|
+
label: 'Teaching Time',
|
|
4165
|
+
value: this.formatDuration(totalTeachingMs),
|
|
4166
|
+
hint: this.formatDuration(activeUserIds.size ? totalTeachingMs / activeUserIds.size : 0) + " per active teacher",
|
|
4167
|
+
},
|
|
4168
|
+
{
|
|
4169
|
+
label: 'Sessions',
|
|
4170
|
+
value: "" + timed.length,
|
|
4171
|
+
hint: this.formatDuration(avgSession) + " on average",
|
|
4172
|
+
},
|
|
4173
|
+
{
|
|
4174
|
+
label: 'Content Used',
|
|
4175
|
+
value: "" + launches.length,
|
|
4176
|
+
hint: topics.size + " distinct topics",
|
|
4177
|
+
},
|
|
4178
|
+
{
|
|
4179
|
+
label: 'Peak Hour',
|
|
4180
|
+
value: peak ? peak.label : '—',
|
|
4181
|
+
hint: peak ? peak.value + " teachers in class" : 'No sessions',
|
|
4182
|
+
},
|
|
4183
|
+
];
|
|
4184
|
+
this.attention = [
|
|
4185
|
+
{
|
|
4186
|
+
label: 'Teachers Not Active',
|
|
4187
|
+
icon: 'teacher',
|
|
4188
|
+
value: this.inactiveTeachers.length,
|
|
4189
|
+
hint: 'Eligible teachers with no session today',
|
|
4190
|
+
},
|
|
4191
|
+
{
|
|
4192
|
+
label: 'Classrooms Not Used',
|
|
4193
|
+
icon: 'room',
|
|
4194
|
+
value: this.idleRooms.length,
|
|
4195
|
+
hint: 'Installed classrooms with no session today',
|
|
4196
|
+
},
|
|
4197
|
+
{
|
|
4198
|
+
label: "Sessions Under " + SHORT_SESSION_MIN + " Min",
|
|
4199
|
+
icon: 'clock',
|
|
4200
|
+
value: timed.filter(function (s) { return s.end - s.start < SHORT_SESSION_MIN * MINUTE; }).length,
|
|
4201
|
+
hint: 'May be accidental log-ins',
|
|
4202
|
+
},
|
|
4203
|
+
{
|
|
4204
|
+
label: 'Sessions Without Content',
|
|
4205
|
+
icon: 'book',
|
|
4206
|
+
value: timed.filter(function (s) { return s.resources.length === 0; }).length,
|
|
4207
|
+
hint: 'Logged in but nothing was used',
|
|
4208
|
+
},
|
|
4209
|
+
];
|
|
4210
|
+
this.countUp();
|
|
4211
|
+
};
|
|
4212
|
+
// biggest slices first; anything past `keep` is grouped as "Other"
|
|
4213
|
+
InsightsComponent.prototype.buildDonut = function (items, keep) {
|
|
4214
|
+
var _this = this;
|
|
4215
|
+
var sorted = __spread(items).sort(function (a, b) { return b.value - a.value; });
|
|
4216
|
+
var shown = sorted.slice(0, keep);
|
|
4217
|
+
var rest = sorted.slice(keep).reduce(function (sum, i) { return sum + i.value; }, 0);
|
|
4218
|
+
if (rest > 0)
|
|
4219
|
+
shown.push({ label: 'Other', value: rest });
|
|
4220
|
+
var total = shown.reduce(function (sum, i) { return sum + i.value; }, 0);
|
|
4221
|
+
var circumference = 2 * Math.PI * this.donutRadius;
|
|
4222
|
+
var used = 0;
|
|
4223
|
+
var segments = shown.map(function (item, i) {
|
|
4224
|
+
var length = total ? (item.value / total) * circumference : 0;
|
|
4225
|
+
var segment = Object.assign(Object.assign({}, item), { display: _this.formatDuration(item.value), percent: total ? Math.round((item.value / total) * 100) : 0, color: item.label === 'Other' ? '#c9d2e3' : _this.color(i),
|
|
4226
|
+
// small gap between slices
|
|
4227
|
+
dash: Math.max(length - 2, 0) + " " + circumference, offset: -used });
|
|
4228
|
+
used += length;
|
|
4229
|
+
return segment;
|
|
4230
|
+
});
|
|
4231
|
+
return { total: this.formatDuration(total), segments: segments };
|
|
4232
|
+
};
|
|
4233
|
+
// 0 = quiet (light red), 0.5 = moderate (warm yellow), 1 = busiest (green)
|
|
4234
|
+
// `soft` lightens the colour so dark text on tiles stays readable
|
|
4235
|
+
InsightsComponent.prototype.utilisationColor = function (ratio, soft) {
|
|
4236
|
+
if (soft === void 0) { soft = false; }
|
|
4237
|
+
var stops = [
|
|
4238
|
+
{ at: 0, h: 4, s: 82, l: 74 },
|
|
4239
|
+
{ at: 0.5, h: 43, s: 90, l: 62 },
|
|
4240
|
+
{ at: 1, h: 88, s: 45, l: 56 },
|
|
4241
|
+
];
|
|
4242
|
+
var r = Math.min(Math.max(ratio, 0), 1);
|
|
4243
|
+
var _a = __read(r <= 0.5 ? [stops[0], stops[1]] : [stops[1], stops[2]], 2), a = _a[0], b = _a[1];
|
|
4244
|
+
var t = (r - a.at) / (b.at - a.at);
|
|
4245
|
+
var mix = function (x, y) { return Math.round(x + (y - x) * t); };
|
|
4246
|
+
var light = mix(a.l, b.l) + (soft ? 12 : 0);
|
|
4247
|
+
return "hsl(" + mix(a.h, b.h) + ", " + mix(a.s, b.s) + "%, " + light + "%)";
|
|
4248
|
+
};
|
|
4249
|
+
// 0 = near-white blue, 1 = deep navy
|
|
4250
|
+
InsightsComponent.prototype.navyShade = function (ratio) {
|
|
4251
|
+
var from = [234, 241, 251];
|
|
4252
|
+
var to = [22, 43, 87];
|
|
4253
|
+
// eased so low and mid use stay light and only the busiest rooms turn dark
|
|
4254
|
+
var t = Math.pow(Math.min(Math.max(ratio, 0), 1), 1.8);
|
|
4255
|
+
var c = from.map(function (f, i) { return Math.round(f + (to[i] - f) * t); });
|
|
4256
|
+
return "rgb(" + c[0] + ", " + c[1] + ", " + c[2] + ")";
|
|
4257
|
+
};
|
|
4258
|
+
// "Class 7" -> "7", "Early Childhood Education" -> "ECE"
|
|
4259
|
+
InsightsComponent.prototype.shortGrade = function (label) {
|
|
4260
|
+
var match = /^class\s+(.+)$/i.exec(label);
|
|
4261
|
+
if (match)
|
|
4262
|
+
return match[1];
|
|
4263
|
+
return label.split(/\s+/).filter(function (w) { return w; }).map(function (w) { return w.charAt(0).toUpperCase(); }).join('').slice(0, 4);
|
|
4264
|
+
};
|
|
4265
|
+
Object.defineProperty(InsightsComponent.prototype, "activityNote", {
|
|
4266
|
+
// ---------- notes under charts: one takeaway from today's data
|
|
4267
|
+
get: function () {
|
|
4268
|
+
if (!this.hourly.length)
|
|
4269
|
+
return '';
|
|
4270
|
+
var peak = this.hourly.reduce(function (a, b) { return (b.value > a.value ? b : a); });
|
|
4271
|
+
var quiet = this.hourly.reduce(function (a, b) { return (b.value < a.value ? b : a); });
|
|
4272
|
+
return "Busiest at " + peak.label + " with " + peak.value + " teachers in class; quietest at " + quiet.label + " with " + quiet.value + ".";
|
|
4273
|
+
},
|
|
4274
|
+
enumerable: false,
|
|
4275
|
+
configurable: true
|
|
4276
|
+
});
|
|
4277
|
+
Object.defineProperty(InsightsComponent.prototype, "chaptersNote", {
|
|
4278
|
+
get: function () {
|
|
4279
|
+
var top = this.chapters[0];
|
|
4280
|
+
return top ? "Most used: " + top.label + (top.sub ? ' (' + top.sub + ')' : '') + ", " + top.display + "." : '';
|
|
4281
|
+
},
|
|
4282
|
+
enumerable: false,
|
|
4283
|
+
configurable: true
|
|
4284
|
+
});
|
|
4285
|
+
Object.defineProperty(InsightsComponent.prototype, "subjectNote", {
|
|
4286
|
+
get: function () {
|
|
4287
|
+
var top = this.subjectDonut.segments.find(function (s) { return s.label !== 'Other'; });
|
|
4288
|
+
return top ? top.label + " took the largest share of teaching time today (" + top.percent + "%, " + top.display + ")." : '';
|
|
4289
|
+
},
|
|
4290
|
+
enumerable: false,
|
|
4291
|
+
configurable: true
|
|
4292
|
+
});
|
|
4293
|
+
// every number inside a value ("42 / 77", "48h 53m") rises from 0 together
|
|
4294
|
+
InsightsComponent.prototype.countUp = function () {
|
|
4295
|
+
var _this = this;
|
|
4296
|
+
cancelAnimationFrame(this.countFrame);
|
|
4297
|
+
var reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
4298
|
+
var apply = function (progress) {
|
|
4299
|
+
_this.kpis.forEach(function (k) { return (k.shown = k.value.replace(/\d+/g, function (n) { return "" + Math.round(+n * progress); })); });
|
|
4300
|
+
_this.attention.forEach(function (a) { return (a.shown = Math.round(a.value * progress)); });
|
|
4301
|
+
};
|
|
4302
|
+
if (reduced) {
|
|
4303
|
+
apply(1);
|
|
4304
|
+
return;
|
|
4305
|
+
}
|
|
4306
|
+
var duration = 900;
|
|
4307
|
+
var start = performance.now();
|
|
4308
|
+
var step = function (now) {
|
|
4309
|
+
var t = Math.min((now - start) / duration, 1);
|
|
4310
|
+
apply(1 - Math.pow(1 - t, 3));
|
|
4311
|
+
if (t < 1)
|
|
4312
|
+
_this.countFrame = requestAnimationFrame(step);
|
|
4313
|
+
};
|
|
4314
|
+
apply(0);
|
|
4315
|
+
this.countFrame = requestAnimationFrame(step);
|
|
4316
|
+
};
|
|
4317
|
+
InsightsComponent.prototype.closeDetails = function () {
|
|
4318
|
+
this.detailsOpen = false;
|
|
4319
|
+
};
|
|
4320
|
+
// "Mrs Alisa Dsouza" -> "AD"
|
|
4321
|
+
InsightsComponent.prototype.initials = function (name) {
|
|
4322
|
+
var words = (name || '').split(/\s+/).filter(function (w) { return w && !/^(mr|mrs|miss|ms|dr)\.?$/i.test(w); });
|
|
4323
|
+
return words.length ? (words[0][0] + (words.length > 1 ? words[words.length - 1][0] : '')).toUpperCase() : '?';
|
|
4324
|
+
};
|
|
4325
|
+
// ---------- PDF export
|
|
4326
|
+
InsightsComponent.prototype.downloadPdf = function () {
|
|
4327
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
4328
|
+
var page, wrapper, copy, top_1, breaks, canvas;
|
|
4329
|
+
return __generator(this, function (_a) {
|
|
4330
|
+
switch (_a.label) {
|
|
4331
|
+
case 0:
|
|
4332
|
+
page = this.host.nativeElement.querySelector('.in-page');
|
|
4333
|
+
if (!page || this.isExporting)
|
|
4334
|
+
return [2 /*return*/];
|
|
4335
|
+
this.isExporting = true;
|
|
4336
|
+
wrapper = document.createElement('div');
|
|
4337
|
+
wrapper.setAttribute('data-pdf-wrapper', '');
|
|
4338
|
+
wrapper.style.cssText = 'position:fixed;left:0;top:0;width:0;height:0;overflow:hidden;z-index:-1;';
|
|
4339
|
+
copy = page.cloneNode(true);
|
|
4340
|
+
copy.classList.add('in-exporting');
|
|
4341
|
+
copy.style.width = PDF_RENDER_WIDTH + 'px';
|
|
4342
|
+
wrapper.appendChild(copy);
|
|
4343
|
+
page.parentElement.appendChild(wrapper);
|
|
4344
|
+
_a.label = 1;
|
|
4345
|
+
case 1:
|
|
4346
|
+
_a.trys.push([1, , 3, 4]);
|
|
4347
|
+
top_1 = copy.getBoundingClientRect().top;
|
|
4348
|
+
breaks = Array.from(copy.querySelectorAll('.in-card'))
|
|
4349
|
+
.map(function (card) { return Math.round(card.getBoundingClientRect().top - top_1 - 8); })
|
|
4350
|
+
.filter(function (y, i, all) { return y > 0 && all.indexOf(y) === i; })
|
|
4351
|
+
.sort(function (a, b) { return a - b; });
|
|
4352
|
+
return [4 /*yield*/, html2canvas__default['default'](copy, {
|
|
4353
|
+
scale: 2,
|
|
4354
|
+
backgroundColor: '#ffffff',
|
|
4355
|
+
onclone: function (doc) {
|
|
4356
|
+
var clonedWrapper = doc.querySelector('[data-pdf-wrapper]');
|
|
4357
|
+
if (clonedWrapper) {
|
|
4358
|
+
clonedWrapper.style.overflow = 'visible';
|
|
4359
|
+
}
|
|
4360
|
+
},
|
|
4361
|
+
})];
|
|
4362
|
+
case 2:
|
|
4363
|
+
canvas = _a.sent();
|
|
4364
|
+
this.savePdf(canvas, breaks.map(function (y) { return y * 2; }));
|
|
4365
|
+
return [3 /*break*/, 4];
|
|
4366
|
+
case 3:
|
|
4367
|
+
wrapper.remove();
|
|
4368
|
+
this.isExporting = false;
|
|
4369
|
+
return [7 /*endfinally*/];
|
|
4370
|
+
case 4: return [2 /*return*/];
|
|
4371
|
+
}
|
|
4372
|
+
});
|
|
4373
|
+
});
|
|
4374
|
+
};
|
|
4375
|
+
// A4 portrait; each page takes whole rows of cards and long content is sliced as a last resort
|
|
4376
|
+
InsightsComponent.prototype.savePdf = function (canvas, breaks) {
|
|
4377
|
+
var _this = this;
|
|
4378
|
+
var pdf = new jspdf.jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
|
|
4379
|
+
var margin = 10;
|
|
4380
|
+
var pageWidth = pdf.internal.pageSize.getWidth();
|
|
4381
|
+
var pageHeight = pdf.internal.pageSize.getHeight();
|
|
4382
|
+
var contentWidth = pageWidth - margin * 2;
|
|
4383
|
+
var mmPerPx = contentWidth / canvas.width;
|
|
4384
|
+
var maxSlice = Math.floor((pageHeight - margin * 2 - 6) / mmPerPx);
|
|
4385
|
+
var slices = [];
|
|
4386
|
+
var start = 0;
|
|
4387
|
+
var _loop_2 = function () {
|
|
4388
|
+
var end = Math.min(start + maxSlice, canvas.height);
|
|
4389
|
+
if (end < canvas.height) {
|
|
4390
|
+
var fit = breaks.filter(function (b) { return b > start && b <= end; });
|
|
4391
|
+
if (fit.length)
|
|
4392
|
+
end = fit[fit.length - 1];
|
|
4393
|
+
}
|
|
4394
|
+
slices.push([start, end]);
|
|
4395
|
+
start = end;
|
|
4396
|
+
};
|
|
4397
|
+
while (start < canvas.height) {
|
|
4398
|
+
_loop_2();
|
|
4399
|
+
}
|
|
4400
|
+
slices.forEach(function (_a, i) {
|
|
4401
|
+
var _b = __read(_a, 2), from = _b[0], to = _b[1];
|
|
4402
|
+
var part = document.createElement('canvas');
|
|
4403
|
+
part.width = canvas.width;
|
|
4404
|
+
part.height = to - from;
|
|
4405
|
+
part.getContext('2d').drawImage(canvas, 0, from, canvas.width, to - from, 0, 0, canvas.width, to - from);
|
|
4406
|
+
if (i > 0)
|
|
4407
|
+
pdf.addPage();
|
|
4408
|
+
pdf.addImage(part.toDataURL('image/jpeg', 0.92), 'JPEG', margin, margin, contentWidth, part.height * mmPerPx);
|
|
4409
|
+
pdf.setFontSize(8);
|
|
4410
|
+
pdf.setTextColor(140);
|
|
4411
|
+
pdf.text(_this.schoolName + " \u00B7 Usage insights", margin, pageHeight - 5);
|
|
4412
|
+
pdf.text("Page " + (i + 1) + " of " + slices.length, pageWidth - margin, pageHeight - 5, { align: 'right' });
|
|
4413
|
+
});
|
|
4414
|
+
pdf.save("Insights-" + (this.fileDate || 'report') + ".pdf");
|
|
4415
|
+
};
|
|
4416
|
+
// ---------- helpers
|
|
4417
|
+
InsightsComponent.prototype.list = function (json, outer, inner) {
|
|
4418
|
+
var value = json && json[outer] && json[outer][inner];
|
|
4419
|
+
return Array.isArray(value) ? value : [];
|
|
4420
|
+
};
|
|
4421
|
+
InsightsComponent.prototype.location = function (metadata) {
|
|
4422
|
+
try {
|
|
4423
|
+
return (typeof metadata === 'string' ? JSON.parse(metadata) : metadata || {}).location || '';
|
|
4424
|
+
}
|
|
4425
|
+
catch (e) {
|
|
4426
|
+
return '';
|
|
4427
|
+
}
|
|
4428
|
+
};
|
|
4429
|
+
// "2024-12-10 07:01:24.0" is not valid ISO for every browser, so add the "T"
|
|
4430
|
+
InsightsComponent.prototype.parseTime = function (value) {
|
|
4431
|
+
return value ? new Date(String(value).replace(' ', 'T')).getTime() : NaN;
|
|
4432
|
+
};
|
|
4433
|
+
InsightsComponent.prototype.title = function (item) {
|
|
4434
|
+
return (item && item.title ? String(item.title) : '').trim();
|
|
4435
|
+
};
|
|
4436
|
+
// known types use the dashboard's labels; others like "casset_weblink" become "Weblink"
|
|
4437
|
+
InsightsComponent.prototype.typeLabel = function (type) {
|
|
4438
|
+
if (!type)
|
|
4439
|
+
return 'Other';
|
|
4440
|
+
var label = this.pdService.getDisplaytypeValue(type);
|
|
4441
|
+
if (label !== type)
|
|
4442
|
+
return label;
|
|
4443
|
+
var words = type.replace(/^c?asset_/, '').replace(/_/g, ' ');
|
|
4444
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
4445
|
+
};
|
|
4446
|
+
InsightsComponent.prototype.userName = function (user, fallback) {
|
|
4447
|
+
return user ? this.pdService.getName(user) : fallback;
|
|
4448
|
+
};
|
|
4449
|
+
// overlapping sessions for the same key are counted once
|
|
4450
|
+
InsightsComponent.prototype.groupTime = function (sessions, key) {
|
|
4451
|
+
var _this = this;
|
|
4452
|
+
var grouped = new Map();
|
|
4453
|
+
sessions.forEach(function (s) {
|
|
4454
|
+
var k = key(s);
|
|
4455
|
+
grouped.set(k, (grouped.get(k) || []).concat({ start: s.start, end: s.end }));
|
|
4456
|
+
});
|
|
4457
|
+
var result = new Map();
|
|
4458
|
+
grouped.forEach(function (intervals, k) { return result.set(k, _this.mergedDuration(intervals)); });
|
|
4459
|
+
return result;
|
|
4460
|
+
};
|
|
4461
|
+
InsightsComponent.prototype.mergedDuration = function (intervals) {
|
|
4462
|
+
var sorted = __spread(intervals).sort(function (a, b) { return a.start - b.start; });
|
|
4463
|
+
var total = 0;
|
|
4464
|
+
var cur = null;
|
|
4465
|
+
sorted.forEach(function (i) {
|
|
4466
|
+
if (!cur || i.start > cur.end) {
|
|
4467
|
+
if (cur)
|
|
4468
|
+
total += cur.end - cur.start;
|
|
4469
|
+
cur = Object.assign({}, i);
|
|
4470
|
+
}
|
|
4471
|
+
else if (i.end > cur.end) {
|
|
4472
|
+
cur.end = i.end;
|
|
4473
|
+
}
|
|
4474
|
+
});
|
|
4475
|
+
return cur ? total + cur.end - cur.start : total;
|
|
4476
|
+
};
|
|
4477
|
+
InsightsComponent.prototype.countBy = function (items, key) {
|
|
4478
|
+
var result = new Map();
|
|
4479
|
+
items.forEach(function (item) { return result.set(key(item), (result.get(key(item)) || 0) + 1); });
|
|
4480
|
+
return result;
|
|
4481
|
+
};
|
|
4482
|
+
InsightsComponent.prototype.share = function (target, labels, ms) {
|
|
4483
|
+
var unique = Array.from(new Set(labels.filter(function (l) { return l; })));
|
|
4484
|
+
unique.forEach(function (l) { return target.set(l, (target.get(l) || 0) + ms / unique.length); });
|
|
4485
|
+
};
|
|
4486
|
+
InsightsComponent.prototype.entries = function (map) {
|
|
4487
|
+
return Array.from(map.entries()).map(function (_a) {
|
|
4488
|
+
var _b = __read(_a, 2), label = _b[0], value = _b[1];
|
|
4489
|
+
return ({ label: label, value: value });
|
|
4490
|
+
});
|
|
4491
|
+
};
|
|
4492
|
+
// limit 0 = show all; bar length is relative to the largest value
|
|
4493
|
+
InsightsComponent.prototype.toBars = function (items, display, limit, sortByValue) {
|
|
4494
|
+
if (sortByValue === void 0) { sortByValue = true; }
|
|
4495
|
+
var sorted = sortByValue ? __spread(items).sort(function (a, b) { return b.value - a.value; }) : items;
|
|
4496
|
+
var shown = limit ? sorted.slice(0, limit) : sorted;
|
|
4497
|
+
var max = Math.max.apply(Math, __spread(shown.map(function (i) { return i.value; }), [1]));
|
|
4498
|
+
return shown.map(function (i) { return (Object.assign(Object.assign({}, i), { display: display(i.value), percent: (i.value / max) * 100 })); });
|
|
4499
|
+
};
|
|
4500
|
+
// blue and yellow first to match the page, then supporting tones
|
|
4501
|
+
InsightsComponent.prototype.color = function (index) {
|
|
4502
|
+
var palette = ['#7c9cf5', '#f6d27e', '#a9bffa', '#6fc6ba', '#f4a98a', '#c0aef7', '#f3a6c8', '#b4bfcf', '#fbe7b4'];
|
|
4503
|
+
return palette[index % palette.length];
|
|
4504
|
+
};
|
|
4505
|
+
InsightsComponent.prototype.pct = function (part, whole) {
|
|
4506
|
+
return whole ? Math.round((part / whole) * 100) + "%" : '0%';
|
|
4507
|
+
};
|
|
4508
|
+
InsightsComponent.prototype.formatHour = function (date) {
|
|
4509
|
+
var h = date.getHours();
|
|
4510
|
+
return (h % 12 || 12) + " " + (h >= 12 ? 'PM' : 'AM');
|
|
4511
|
+
};
|
|
4512
|
+
InsightsComponent.prototype.formatDuration = function (ms) {
|
|
4513
|
+
var minutes = Math.round(ms / MINUTE);
|
|
4514
|
+
var h = Math.floor(minutes / 60);
|
|
4515
|
+
var m = minutes % 60;
|
|
4516
|
+
return h ? h + "h " + m + "m" : m + "m";
|
|
4517
|
+
};
|
|
4518
|
+
return InsightsComponent;
|
|
4519
|
+
}());
|
|
4520
|
+
InsightsComponent.decorators = [
|
|
4521
|
+
{ type: i0.Component, args: [{
|
|
4522
|
+
selector: 'lib-insights',
|
|
4523
|
+
template: "<div class=\"in-page\">\n <!-- title and headline numbers stay in view while the cards below scroll -->\n <div class=\"in-sticky\">\n <div class=\"in-heading\">\n <div class=\"in-heading-text\">{{ schoolName }}<span *ngIf=\"schoolName && dayLabel\"> \u00B7 </span>{{ dayLabel }}</div>\n <button\n type=\"button\"\n class=\"in-pdf-btn\"\n *ngIf=\"hasSessions\"\n data-html2canvas-ignore=\"true\"\n [disabled]=\"isExporting\"\n (click)=\"downloadPdf()\"\n >{{ isExporting ? 'Preparing PDF\u2026' : 'Download PDF' }}</button>\n </div>\n\n <div class=\"in-kpis\" *ngIf=\"hasSessions\">\n <div class=\"in-kpi in-anim\" *ngFor=\"let kpi of kpis; let i = index; let last = last\" [class.in-kpi-accent]=\"last\" [style.animation-delay.ms]=\"i * 60\">\n <span class=\"in-kpi-icon\">\n <svg viewBox=\"0 0 10 10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"><path d=\"M2.5 7.5l5-5M3.5 2.5h4v4\" /></svg>\n </span>\n <div class=\"in-kpi-label\">{{ kpi.label }}</div>\n <div class=\"in-kpi-value\">{{ kpi.shown || kpi.value }}</div>\n <div class=\"in-kpi-hint\">{{ kpi.hint }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"in-empty\" *ngIf=\"!hasSessions\">No usage was recorded on this day.</div>\n\n <ng-container *ngIf=\"hasSessions\">\n\n <!-- primary: what to act on, and who is using the system -->\n <div class=\"in-grid\">\n <section [style.animation-delay.ms]=\"120\" class=\"in-anim in-card in-wide in-primary\">\n <div class=\"in-card-title\">Needs Attention</div>\n <div class=\"in-card-sub\">Who and what to follow up on today</div>\n <div class=\"in-attention\">\n <div class=\"in-attention-item in-anim-row\" *ngFor=\"let a of attention; let i = index\" [style.animation-delay.ms]=\"300 + i * 80\">\n <div class=\"in-attention-value\" [class.in-zero]=\"a.value === 0\">{{ a.shown != null ? a.shown : a.value }}</div>\n <div>\n <div class=\"in-attention-label\">\n <span class=\"in-inline-icon\" [ngSwitch]=\"a.icon\" aria-hidden=\"true\">\n <svg *ngSwitchCase=\"'teacher'\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"8\" r=\"4\" /><path d=\"M4 20c0-4 3.6-6 8-6s8 2 8 6\" /></svg>\n <svg *ngSwitchCase=\"'room'\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" /><path d=\"M12 16v4M8 20h8M7 9h6\" /></svg>\n <svg *ngSwitchCase=\"'clock'\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"M12 7v5l3 2\" /></svg>\n <svg *ngSwitchCase=\"'book'\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2V5z\" /><path d=\"M4 19a2 2 0 0 1 2-2h13\" /></svg>\n </span>\n {{ a.label }}\n </div>\n <div class=\"in-muted\">{{ a.hint }}</div>\n </div>\n </div>\n </div>\n <!-- who to follow up: big tiles that shrink to slim bars when the lists open below (accordion) -->\n <div class=\"in-follow\" [class.in-follow-compact]=\"detailsOpen\">\n <button type=\"button\" class=\"in-follow-tile in-follow-teachers\" [attr.aria-expanded]=\"detailsOpen\" aria-controls=\"in-follow-details\" (click)=\"detailsOpen = !detailsOpen\">\n <span class=\"in-follow-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"8\" r=\"4\" /><path d=\"M4 20c0-4 3.6-6 8-6s8 2 8 6\" /></svg>\n </span>\n <span class=\"in-follow-number\">{{ attention[0]?.shown != null ? attention[0].shown : inactiveTeachers.length }}</span>\n <span class=\"in-follow-label-big\">Teachers Not Active</span>\n <span class=\"in-muted\">of {{ eligibleCount }} eligible teachers</span>\n <span class=\"in-avatars\" *ngIf=\"inactiveTeachers.length\">\n <span class=\"in-avatar\" *ngFor=\"let name of inactiveTeachers.slice(0, 7)\" [title]=\"name\">{{ initials(name) }}</span>\n <span class=\"in-avatar in-avatar-more\" *ngIf=\"inactiveTeachers.length > 7\">+{{ inactiveTeachers.length - 7 }}</span>\n </span>\n </button>\n <button type=\"button\" class=\"in-follow-tile in-follow-rooms\" [attr.aria-expanded]=\"detailsOpen\" aria-controls=\"in-follow-details\" (click)=\"detailsOpen = !detailsOpen\">\n <span class=\"in-follow-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" /><path d=\"M12 16v4M8 20h8M7 9h6\" /></svg>\n </span>\n <span class=\"in-follow-number\">{{ attention[1]?.shown != null ? attention[1].shown : idleRooms.length }}</span>\n <span class=\"in-follow-label-big\">Classrooms Not Used</span>\n <span class=\"in-muted\">of {{ classroomCount }} installed classrooms</span>\n <span class=\"in-room-chips\" *ngIf=\"idleRooms.length\">\n <span class=\"in-room-chip\" *ngFor=\"let room of idleRooms.slice(0, 6)\">{{ room }}</span>\n <span class=\"in-room-chip in-avatar-more\" *ngIf=\"idleRooms.length > 6\">+{{ idleRooms.length - 6 }}</span>\n </span>\n </button>\n </div>\n <div class=\"in-follow-details\" id=\"in-follow-details\" *ngIf=\"detailsOpen\">\n <ng-container *ngTemplateOutlet=\"followLists\"></ng-container>\n </div>\n <div class=\"in-follow-foot\" data-html2canvas-ignore=\"true\">\n <button type=\"button\" class=\"in-link-btn\" [attr.aria-expanded]=\"detailsOpen\" aria-controls=\"in-follow-details\" (click)=\"detailsOpen = !detailsOpen\">\n {{ detailsOpen ? 'Hide details' : 'Show details' }}\n <span class=\"in-link-chevron\" [class.in-link-chevron-up]=\"detailsOpen\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <!-- the PDF can't open a modal, so it prints the full lists here instead -->\n <div class=\"in-print-only\">\n <ng-container *ngTemplateOutlet=\"followLists\"></ng-container>\n </div>\n </section>\n <section [style.animation-delay.ms]=\"180\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Most Active Teachers</div>\n <div class=\"in-card-sub\">Time in class, overlapping sessions counted once</div>\n <ng-container *ngTemplateOutlet=\"bars; context: { $implicit: topTeachers, color: '#8BC34A' }\"></ng-container>\n </section>\n </div>\n\n <!-- supporting detail -->\n <div class=\"in-grid\">\n <section [style.animation-delay.ms]=\"240\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Activity Through the Day</div>\n <div class=\"in-card-sub\">Number of teachers in a session during each hour</div>\n <div class=\"in-hours\">\n <div class=\"in-hour\" *ngFor=\"let h of hourly; let i = index\" [title]=\"h.label + ': ' + h.value + ' teachers'\">\n <div class=\"in-hour-value\">\n <svg class=\"in-hour-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"8\" r=\"4\" /><path d=\"M4 20c0-4 3.6-6 8-6s8 2 8 6\" /></svg>\n {{ h.value }}\n </div>\n <div class=\"in-hour-track\">\n <div class=\"in-hour-bar\" [class.in-peak]=\"h.peak\" [style.height.%]=\"h.percent\" [style.background-color]=\"h.color\" [style.animation-delay.ms]=\"250 + i * 50\"></div>\n </div>\n <div class=\"in-hour-label\">{{ h.label }}</div>\n </div>\n </div>\n <div class=\"in-util-legend\">\n <span class=\"in-muted\">Low</span>\n <span class=\"in-util-scale\"></span>\n <span class=\"in-muted\">High</span>\n </div>\n <div class=\"in-card-note\">\n <svg class=\"in-note-icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"M12 11v5M12 8h.01\" /></svg>\n <div>\n <div class=\"in-note-insight\" *ngIf=\"activityNote\">{{ activityNote }}</div>\n <div>Each column counts the teachers who were in a session at any point in that hour. Colour runs from red (quiet) to green (busiest hour).</div>\n </div>\n </div>\n </section>\n <section [style.animation-delay.ms]=\"300\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Most Used Chapters</div>\n <div class=\"in-card-sub\">Chapters and their topics used today</div>\n <ng-container *ngTemplateOutlet=\"bars; context: { $implicit: chapters, color: '#f4a98a' }\"></ng-container>\n <div class=\"in-card-note\">\n <svg class=\"in-note-icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"M12 11v5M12 8h.01\" /></svg>\n <div>\n <div class=\"in-note-insight\" *ngIf=\"chaptersNote\">{{ chaptersNote }}</div>\n <div>Counts how many times each chapter, or a topic inside it, was opened in class today. Bars are relative to the most used chapter.</div>\n </div>\n </div>\n </section>\n <section [style.animation-delay.ms]=\"360\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Content Utilisation</div>\n <div class=\"in-card-sub\">What teachers used in class</div>\n <div class=\"in-stack\">\n <div\n class=\"in-stack-part\"\n *ngFor=\"let c of contentMix; let i = index\"\n [style.animation-delay.ms]=\"300 + i * 60\"\n [style.width.%]=\"c.percent\"\n [style.background-color]=\"c.color\"\n [title]=\"c.label + ': ' + c.display\"\n ></div>\n </div>\n <div class=\"in-legend\">\n <div class=\"in-legend-item\" *ngFor=\"let c of contentMix\">\n <span class=\"in-dot\" [style.background-color]=\"c.color\"></span>\n <span class=\"in-legend-label\">{{ c.label }}</span>\n <span class=\"in-legend-value\">{{ c.display }}</span>\n </div>\n </div>\n </section>\n </div>\n\n <!-- what was taught, and where -->\n <div class=\"in-grid\">\n <section [style.animation-delay.ms]=\"420\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Time by Subject</div>\n <div class=\"in-card-sub\">Share of session time by subject</div>\n <div class=\"in-donut-wrap\">\n <svg class=\"in-donut\" viewBox=\"0 0 140 140\" role=\"img\" aria-label=\"Time by subject\">\n <circle cx=\"70\" cy=\"70\" [attr.r]=\"donutRadius\" class=\"in-donut-track\"></circle>\n <circle\n *ngFor=\"let s of subjectDonut.segments; let i = index\"\n class=\"in-donut-seg\"\n cx=\"70\"\n cy=\"70\"\n [attr.r]=\"donutRadius\"\n [attr.stroke]=\"s.color\"\n [attr.stroke-dasharray]=\"s.dash\"\n [attr.stroke-dashoffset]=\"s.offset\"\n [style.animation-delay.ms]=\"300 + i * 90\"\n >\n <title>{{ s.label }}: {{ s.display }} ({{ s.percent }}%)</title>\n </circle>\n </svg>\n <div class=\"in-donut-center\">\n <div class=\"in-donut-total\">{{ subjectDonut.total }}</div>\n <div class=\"in-muted\" title=\"Session time where content was used\">with content</div>\n </div>\n </div>\n <div class=\"in-legend in-legend-compact\">\n <div class=\"in-legend-item\" *ngFor=\"let s of subjectDonut.segments\">\n <span class=\"in-dot\" [style.background-color]=\"s.color\"></span>\n <span class=\"in-legend-label\" [title]=\"s.label\">{{ s.label }}</span>\n <span class=\"in-legend-value\">{{ s.percent }}%</span>\n </div>\n </div>\n <div class=\"in-card-note\">\n <svg class=\"in-note-icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"M12 11v5M12 8h.01\" /></svg>\n <div>\n <div class=\"in-note-insight\" *ngIf=\"subjectNote\">{{ subjectNote }}</div>\n <div>Each session's time is split equally across the subjects opened in it. Sessions where nothing was opened have no subject, so this total is lower than Teaching Time.</div>\n </div>\n </div>\n </section>\n <section [style.animation-delay.ms]=\"480\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Classroom Usage</div>\n <div class=\"in-card-sub\">Each classroom's utilisation by time</div>\n <div class=\"in-tiles\">\n <div\n class=\"in-tile\"\n *ngFor=\"let r of roomTiles; let i = index\"\n [class.in-tile-idle]=\"r.idle\"\n [class.in-tile-dark]=\"r.dark\"\n [style.grid-column]=\"'span ' + r.span\"\n [style.background-color]=\"r.shade\"\n [style.animation-delay.ms]=\"300 + i * 15\"\n [title]=\"r.label + ': ' + r.display\"\n >\n <span class=\"in-tile-name\">\n <svg class=\"in-tile-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" /><path d=\"M12 16v4M8 20h8\" /></svg>{{ r.label }}\n </span>\n <span class=\"in-tile-value\">{{ r.share }}%</span>\n </div>\n </div>\n <div class=\"in-tiles-legend\">\n <span class=\"in-tile in-tile-key in-tile-idle\"></span><span class=\"in-muted\">0% / not used</span>\n <span class=\"in-scale\"></span><span class=\"in-muted\">Low \u2192 high utilisation</span>\n </div>\n </section>\n <section [style.animation-delay.ms]=\"540\" class=\"in-anim in-card\">\n <div class=\"in-card-title\">Time by Class</div>\n <div class=\"in-card-sub\">Session time per class</div>\n <div class=\"in-columns\">\n <div class=\"in-column\" *ngFor=\"let g of gradeColumns; let i = index\" [title]=\"g.label + ': ' + g.display\">\n <div class=\"in-column-track\">\n <div class=\"in-column-bar\" [style.height.%]=\"g.percent\" [style.animation-delay.ms]=\"300 + i * 50\"></div>\n </div>\n <div class=\"in-column-label\">{{ g.short }}</div>\n </div>\n </div>\n <div class=\"in-columns-caption\">Class</div>\n <div class=\"in-column-top\" *ngIf=\"gradeColumns.length\">\n <span class=\"in-muted\">Most time</span>\n <ng-container *ngFor=\"let g of gradeColumns\">\n <strong *ngIf=\"g.percent === 100\">{{ g.label }} \u00B7 {{ g.display }}</strong>\n </ng-container>\n </div>\n </section>\n </div>\n </ng-container>\n\n</div>\n\n<ng-template #followLists>\n <div class=\"in-follow-cols\">\n <div class=\"in-follow-col\">\n <div class=\"in-follow-label\">Teachers Not Active <span class=\"in-count\">{{ inactiveTeachers.length }}</span></div>\n <ul class=\"in-name-list\" *ngIf=\"inactiveTeachers.length\">\n <li *ngFor=\"let name of inactiveTeachers\">{{ name }}</li>\n </ul>\n <span class=\"in-muted\" *ngIf=\"inactiveTeachers.length === 0\">Every eligible teacher used the system today.</span>\n </div>\n <div class=\"in-follow-col\">\n <div class=\"in-follow-label\">Classrooms Not Used <span class=\"in-count\">{{ idleRooms.length }}</span></div>\n <ul class=\"in-name-list in-room-list\" *ngIf=\"idleRooms.length\">\n <li *ngFor=\"let room of idleRooms\">{{ room }}</li>\n </ul>\n <span class=\"in-muted\" *ngIf=\"idleRooms.length === 0\">Every classroom was used today.</span>\n </div>\n </div>\n</ng-template>\n\n<!-- each section passes its own bar colour so neighbouring cards are easy to tell apart -->\n<ng-template #bars let-items let-color=\"color\">\n <div class=\"in-bars\">\n <div class=\"in-muted\" *ngIf=\"items.length === 0\">No data</div>\n <div class=\"in-bar-row\" *ngFor=\"let item of items; let i = index\">\n <div class=\"in-bar-head\">\n <span class=\"in-bar-label\" [title]=\"item.label\">{{ item.label }}</span>\n <span class=\"in-bar-value\">{{ item.display }}</span>\n </div>\n <div class=\"in-bar-sub\" *ngIf=\"item.sub\">{{ item.sub }}</div>\n <div class=\"in-bar-track\"><div class=\"in-bar-fill\" [style.width.%]=\"item.percent\" [style.background-color]=\"color\" [style.animation-delay.ms]=\"300 + i * 60\"></div></div>\n </div>\n </div>\n</ng-template>\n",
|
|
4524
|
+
styles: ["@import url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap\");.in-page{font-family:Poppins,Segoe UI,Arial,sans-serif;font-size:13px;color:#1e2437;padding:0 20px 24px;box-sizing:border-box;text-align:left;overflow-y:auto;background:#eef2f9}.in-sticky{position:sticky;top:0;z-index:2;margin:0 -20px 16px;padding:16px 20px;background:#eef2f9;box-shadow:0 6px 12px -10px rgba(30,36,55,.25)}.in-heading{position:relative;margin-bottom:14px;min-height:34px;display:flex;align-items:center;justify-content:center}.in-heading-text{font-size:17px;font-weight:600;color:#1e2437;text-align:center;padding:0 150px}.in-pdf-btn{position:absolute;right:0;top:50%;transform:translateY(-50%);height:34px;padding:0 16px;border:none;border-radius:10px;background:#5b84ec;color:#fff;font:500 13px Poppins,Segoe UI,Arial,sans-serif;cursor:pointer;box-shadow:0 4px 10px rgba(91,132,236,.22)}.in-pdf-btn:hover:not([disabled]){background:#406fe9}.in-pdf-btn[disabled]{cursor:progress;background:#b3c6f5;box-shadow:none}.in-page.in-exporting{height:auto!important;overflow:visible}.in-page.in-exporting *,.in-page.in-exporting :after,.in-page.in-exporting :before{-webkit-animation:none!important;animation:none!important}.in-page.in-exporting .in-sticky{position:static;box-shadow:none}.in-page.in-exporting .in-chips{max-height:none;overflow:visible}.in-page.in-exporting .in-print-only{display:block}.in-page.in-exporting .in-follow-details{display:none}.in-card-sub,.in-muted{font-size:12px;color:#8a93a6}.in-empty{padding:40px;text-align:center;color:#8a93a6}.in-kpis{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:12px}.in-kpi{position:relative;min-width:0;padding:12px 14px;border-radius:14px;background:#fff;box-shadow:0 1px 3px rgba(30,36,55,.06);color:#1e2437;box-sizing:border-box}.in-kpi.in-kpi-accent{background:#5b84ec;color:#fff}.in-kpi.in-kpi-accent .in-kpi-hint,.in-kpi.in-kpi-accent .in-kpi-label{color:hsla(0,0%,100%,.85)}.in-kpi.in-kpi-accent .in-kpi-icon{border-color:#fff;color:#fff}.in-kpi-icon{position:absolute;top:12px;right:12px;width:20px;height:20px;border:2px solid #1e2437;border-radius:50%;box-sizing:border-box;display:flex;align-items:center;justify-content:center;color:#1e2437}.in-kpi-icon svg{width:10px;height:10px}.in-kpi-label{padding-right:24px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:12px;font-weight:500;color:rgba(30,36,55,.75)}.in-kpi-value{white-space:nowrap;font-size:22px;font-weight:700;margin:2px 0;font-variant-numeric:tabular-nums}.in-kpi-hint{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:11px;color:rgba(30,36,55,.7)}.in-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}.in-grid+.in-grid{margin-top:16px}.in-card{background:#fff;border-radius:16px;box-shadow:0 1px 3px rgba(30,36,55,.06);padding:18px 20px;min-width:0;box-sizing:border-box}.in-card,.in-wide{display:flex;flex-direction:column}.in-wide{grid-column:span 2}.in-card-note{margin-top:auto;padding-top:14px;border-top:1px solid #eef1f6;display:flex;align-items:flex-start;gap:8px;font-size:12px;line-height:1.45;color:#8a93a6}.in-note-icon{flex:0 0 auto;width:15px;height:15px;margin-top:1px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}.in-note-insight{color:#1e2437;font-weight:500;margin-bottom:2px}.in-card-title{font-size:16px;font-weight:600;color:#1e2437}.in-card-sub{margin:2px 0 16px}.in-count{display:inline-block;min-width:22px;padding:0 8px;margin-left:6px;border-radius:11px;background:#fff6de;color:#a46b00;font-size:12px;font-weight:600;text-align:center;line-height:22px;vertical-align:middle}.in-hours{flex:1 1 auto;display:flex;align-items:stretch;gap:4px;min-height:200px;max-height:320px}.in-hour{flex:1 1 0;flex-direction:column;min-width:0}.in-hour,.in-hour-value{display:flex;align-items:center}.in-hour-value{gap:3px;font-size:12px;font-weight:600;color:#1e2437;margin-bottom:6px;white-space:nowrap}.in-hour-icon{width:12px;height:12px;color:#8a93a6;flex:0 0 auto}.in-hour-track{flex:1 1 auto;max-width:44px;display:flex;align-items:flex-end;background:#f1f4f9;overflow:hidden}.in-hour-bar,.in-hour-track{width:100%;border-radius:999px}.in-hour-bar{min-height:6px;background:#fbe0a0}.in-util-legend{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:12px}.in-util-scale{width:90px;height:8px;border-radius:999px;background:linear-gradient(90deg,#f38e86,#f5c447,#92c15c)}.in-hour-label{margin-top:8px;font-size:10px;color:#8a93a6;white-space:nowrap}.in-bars{display:flex;flex-direction:column;gap:12px}.in-bar-head{display:flex;justify-content:space-between;gap:12px}.in-bar-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.in-bar-value{flex:0 0 auto;color:#1e2437;font-weight:600;font-variant-numeric:tabular-nums}.in-bar-sub{font-size:11px;color:#8a93a6}.in-bar-track{height:8px;margin-top:6px;background:#f1f4f9;border-radius:999px;overflow:hidden}.in-bar-fill{height:100%;border-radius:999px;background:#5b84ec}.in-donut-wrap{position:relative;width:150px;height:150px;margin:0 auto 14px}.in-donut{width:100%;height:100%;transform:rotate(-90deg)}.in-donut circle{fill:none;stroke-width:18}.in-donut-track{stroke:#f1f4f9}.in-donut-seg{stroke-linecap:butt;transition:stroke-width .15s;-webkit-animation:in-draw 1s cubic-bezier(.22,1,.36,1) both;animation:in-draw 1s cubic-bezier(.22,1,.36,1) both}.in-donut-seg:hover{stroke-width:22}@-webkit-keyframes in-draw{0%{stroke-dasharray:0 400}}@keyframes in-draw{0%{stroke-dasharray:0 400}}.in-donut-center{position:absolute;inset:0;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;pointer-events:none}.in-donut-total{font-size:18px;font-weight:700}.in-legend-compact{gap:6px}.in-legend-compact .in-legend-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.in-columns{flex:1 1 auto;display:flex;align-items:stretch;gap:5px;min-height:180px;max-height:340px}.in-column{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center}.in-column-track{flex:1 1 auto;width:100%;max-width:22px;display:flex;align-items:flex-end;background:#f1f4f9;border-radius:999px;overflow:hidden}.in-column-bar{width:100%;min-height:4px;border-radius:999px;background:#f3cb6c;-webkit-animation:in-grow-height .8s cubic-bezier(.22,1,.36,1) both;animation:in-grow-height .8s cubic-bezier(.22,1,.36,1) both}.in-column:hover .in-column-bar{background:#f0be46}.in-column-label{margin-top:6px;font-size:11px;font-weight:500;color:#8a93a6;white-space:nowrap}.in-columns-caption{text-align:center;font-size:11px;color:#8a93a6;margin-top:2px}.in-column-top{margin-top:14px;padding:10px 12px;border-radius:10px;background:#fff6de;display:flex;justify-content:space-between;gap:8px;font-size:12px}.in-tiles{display:grid;grid-auto-flow:row dense;grid-template-columns:repeat(auto-fill,minmax(58px,1fr));gap:8px}.in-tile{height:58px;border-radius:12px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;color:#162b57;cursor:default;-webkit-animation:in-pop .4s ease-out both;animation:in-pop .4s ease-out both;transition:transform .12s}.in-tile:hover{transform:scale(1.06)}.in-tile.in-tile-dark{color:#fff}.in-tile.in-tile-idle{background:#f4f7fd;border:2px solid #162b57;color:#162b57}@-webkit-keyframes in-pop{0%{opacity:0;transform:scale(.7)}}@keyframes in-pop{0%{opacity:0;transform:scale(.7)}}.in-tile-icon{width:13px;height:13px;margin-right:4px;vertical-align:-1px}.in-tile-name{max-width:100%;padding:0 4px;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:15px;font-weight:700}.in-tile-value{font-size:12px;font-weight:500;opacity:.85}.in-tiles-legend{display:flex;align-items:center;gap:6px;margin-top:14px;flex-wrap:wrap}.in-tiles-legend .in-tile-key{width:14px;height:14px;border-radius:4px;-webkit-animation:none;animation:none}.in-scale{width:46px;height:10px;margin-left:8px;border-radius:999px;background:linear-gradient(90deg,#eaf1fb,#162b57)}.in-primary .in-attention{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.in-primary .in-attention-item{gap:14px;padding:12px 14px}.in-primary .in-attention-value{flex:0 0 42px;height:42px;line-height:42px;border-radius:10px;background:#ef6a3a;color:#fff;font-size:16px}.in-primary .in-attention-value.in-zero{background:#8bc34a;color:#fff}.in-primary .in-attention-label{display:flex;align-items:center;gap:6px;font-size:14px}.in-primary .in-attention-item .in-muted{font-size:12px;margin-top:2px}.in-inline-icon{display:inline-flex;color:#ef6a3a}.in-inline-icon svg{width:16px;height:16px}.in-follow{flex:1 1 auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-top:18px}.in-follow-tile{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;min-width:0;padding:18px 20px;border:none;border-radius:32px;font:inherit;color:inherit;text-align:center;cursor:pointer;transition:transform .15s,box-shadow .15s}.in-follow-tile:hover{transform:translateY(-2px);box-shadow:0 6px 16px rgba(30,36,55,.08)}.in-follow-teachers{background:#eaf0fd}.in-follow-teachers .in-follow-icon{color:#5b84ec}.in-follow-rooms{background:#eaf0fd}.in-follow-rooms .in-follow-icon{color:#5b84ec}.in-follow-icon{margin-bottom:6px;display:flex;align-items:center;justify-content:center}.in-follow-icon svg{width:40px;height:40px}.in-follow-number{font-size:34px;font-weight:700;line-height:1.1;font-variant-numeric:tabular-nums}.in-follow-tile>.in-muted{font-size:15px;color:#1e2437}.in-follow-label-big{font-size:18px;font-weight:600}.in-avatars{flex-wrap:wrap;margin-top:12px;padding-left:8px}.in-avatar,.in-avatars{display:flex;justify-content:center}.in-avatar{width:34px;height:34px;margin-left:-6px;border-radius:50%;border:1.5px solid #5b84ec;background:#fff;color:#3f5fae;font-size:11px;font-weight:600;align-items:center;box-sizing:border-box}.in-avatar-more{background:#5b84ec;color:#fff}.in-room-chips{flex-wrap:wrap;gap:6px;margin-top:12px}.in-room-chip,.in-room-chips{display:flex;justify-content:center}.in-room-chip{min-width:34px;height:34px;padding:0 10px;border-radius:999px;border:1.5px solid #5b84ec;background:#fff;color:#5b84ec;font-size:12px;font-weight:600;align-items:center;box-sizing:border-box}.in-room-chip.in-avatar-more{background:#5b84ec;color:#fff}.in-follow-foot{display:flex;justify-content:flex-end;margin-top:10px}.in-link-btn{border:none;background:transparent;padding:6px 4px;font:600 13px Poppins,Segoe UI,Arial,sans-serif;color:#5b84ec;cursor:pointer}.in-link-btn:hover{text-decoration:underline}.in-print-only{display:none;margin-top:16px}.in-follow-compact{flex:none}.in-follow-compact .in-follow-tile{flex-direction:row;justify-content:flex-start;gap:12px;padding:10px 16px;text-align:left}.in-follow-compact .in-follow-icon{margin:0}.in-follow-compact .in-follow-icon svg{width:24px;height:24px}.in-follow-compact .in-follow-number{font-size:22px}.in-follow-compact .in-avatars,.in-follow-compact .in-follow-tile>.in-muted,.in-follow-compact .in-room-chips{display:none}.in-follow-details{flex:none;margin-top:12px;padding:14px 16px;border:1px solid #eef1f6;border-radius:12px;-webkit-animation:in-rise .3s ease-out both;animation:in-rise .3s ease-out both}.in-link-chevron{display:inline-block;width:6px;height:6px;margin-left:6px;border-right:2px solid;border-bottom:2px solid;transform:rotate(45deg) translateY(-2px);transition:transform .2s}.in-link-chevron.in-link-chevron-up{transform:rotate(-135deg) translateY(-1px)}.in-follow-cols{display:grid;grid-template-columns:3fr 1fr;gap:24px}.in-follow-col{min-width:0}.in-follow-col+.in-follow-col{border-left:1px solid #e3e8f0;padding-left:24px}.in-follow-label{font-size:13px;font-weight:600;margin:2px 0 10px}.in-name-list{margin:0;padding:0;list-style:none;-moz-column-width:160px;column-width:160px;-moz-column-gap:20px;column-gap:20px}.in-name-list li{position:relative;padding:3px 0 3px 14px;-moz-column-break-inside:avoid;break-inside:avoid;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.in-name-list li:before{content:\"\";position:absolute;left:0;top:50%;width:6px;height:6px;margin-top:-3px;border-radius:50%;background:#a9bffa}.in-room-list li:before{background:#fbe0a0}.in-attention{display:flex;flex-direction:column;gap:10px}.in-attention-item{display:flex;align-items:center;gap:12px;padding:8px;border-radius:12px;background:#f7f9fc}.in-attention-value{flex:0 0 44px;height:40px;line-height:40px;text-align:center;border-radius:10px;background:#fbe0a0;color:#1e2437;font-size:16px;font-weight:700}.in-attention-value.in-zero{background:#eaf0fd;color:#5b84ec}.in-attention-label{font-weight:600}.in-stack{display:flex;height:14px;border-radius:999px;overflow:hidden;background:#f1f4f9;margin-bottom:16px}.in-stack-part{height:100%;box-shadow:inset -2px 0 0 #fff}.in-legend{display:flex;flex-direction:column;gap:8px}.in-legend-item{display:flex;align-items:center;gap:10px}.in-dot{flex:0 0 auto;width:10px;height:10px;border-radius:3px}.in-legend-label{flex:1 1 auto}.in-legend-value{font-weight:600;color:#1e2437;font-variant-numeric:tabular-nums}.in-chips{display:flex;flex-wrap:wrap;gap:8px;max-height:230px;overflow:auto}.in-chip{padding:5px 12px;border-radius:999px;background:#eaf0fd;color:#3f5fae;font-size:12px;font-weight:500}@-webkit-keyframes in-rise{0%{opacity:0;transform:translateY(14px)}}@keyframes in-rise{0%{opacity:0;transform:translateY(14px)}}@-webkit-keyframes in-fade-right{0%{opacity:0;transform:translateX(-10px)}}@keyframes in-fade-right{0%{opacity:0;transform:translateX(-10px)}}@-webkit-keyframes in-grow-width{0%{width:0}}@keyframes in-grow-width{0%{width:0}}@-webkit-keyframes in-grow-height{0%{height:0}}@keyframes in-grow-height{0%{height:0}}.in-anim{-webkit-animation:in-rise .5s cubic-bezier(.22,1,.36,1) both;animation:in-rise .5s cubic-bezier(.22,1,.36,1) both}.in-anim-row{-webkit-animation:in-fade-right .45s ease-out both;animation:in-fade-right .45s ease-out both}.in-bar-fill,.in-stack-part{-webkit-animation:in-grow-width .9s cubic-bezier(.22,1,.36,1) both;animation:in-grow-width .9s cubic-bezier(.22,1,.36,1) both}.in-hour-bar{-webkit-animation:in-grow-height .8s cubic-bezier(.22,1,.36,1) both;animation:in-grow-height .8s cubic-bezier(.22,1,.36,1) both}@media (prefers-reduced-motion:reduce){.in-anim,.in-anim-row,.in-bar-fill,.in-column-bar,.in-donut-seg,.in-hour-bar,.in-stack-part,.in-tile{-webkit-animation:none;animation:none}}@media (max-width:900px){.in-kpis{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (max-width:1100px){.in-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.in-grid>.in-card:last-child:nth-child(odd),.in-wide+.in-card{grid-column:span 2}}@media (max-width:760px){.in-heading-text{padding:0;text-align:left;flex:1 1 auto}.in-pdf-btn{position:static;transform:none}.in-grid>.in-card:last-child:nth-child(odd),.in-wide,.in-wide+.in-card{grid-column:auto}.in-follow,.in-follow-cols,.in-primary .in-attention{grid-template-columns:1fr}.in-follow-col+.in-follow-col{border-left:none;padding-left:0;border-top:1px solid #e3e8f0;padding-top:16px}.in-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}.in-grid{grid-template-columns:1fr}}"]
|
|
4525
|
+
},] }
|
|
4526
|
+
];
|
|
4527
|
+
InsightsComponent.ctorParameters = function () { return [
|
|
4528
|
+
{ type: PrincipalDashboardLibV2Service },
|
|
4529
|
+
{ type: i0.ElementRef }
|
|
4530
|
+
]; };
|
|
4531
|
+
InsightsComponent.propDecorators = {
|
|
4532
|
+
data: [{ type: i0.Input }],
|
|
4533
|
+
fitHeight: [{ type: i0.HostListener, args: ['window:resize',] }],
|
|
4534
|
+
closeDetails: [{ type: i0.HostListener, args: ['document:keydown.escape',] }]
|
|
3353
4535
|
};
|
|
3354
4536
|
|
|
3355
4537
|
var PrincipalDashboardLibV2Module = /** @class */ (function () {
|
|
@@ -3367,7 +4549,9 @@
|
|
|
3367
4549
|
TableviewComponent,
|
|
3368
4550
|
PrincipalDashboardLibV2Component,
|
|
3369
4551
|
FullTableViewComponent,
|
|
3370
|
-
SmallTableViewComponent
|
|
4552
|
+
SmallTableViewComponent,
|
|
4553
|
+
TimelineComponent,
|
|
4554
|
+
InsightsComponent
|
|
3371
4555
|
],
|
|
3372
4556
|
imports: [
|
|
3373
4557
|
common.CommonModule,
|
|
@@ -3399,6 +4583,8 @@
|
|
|
3399
4583
|
exports.ɵf = TableviewComponent;
|
|
3400
4584
|
exports.ɵg = FullTableViewComponent;
|
|
3401
4585
|
exports.ɵh = SmallTableViewComponent;
|
|
4586
|
+
exports.ɵi = TimelineComponent;
|
|
4587
|
+
exports.ɵj = InsightsComponent;
|
|
3402
4588
|
|
|
3403
4589
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
3404
4590
|
|