Skip to content

Commit ad8daa6

Browse files
fix: resolve runtime errors - remove broken modulepreload hints, uswds-init.js 404, and Node-only json2csv
- Remove hardcoded uswds-init.js script tag from index.html (already bundled) - Remove chart.js from global scripts array (imported via ng2-charts ESM, was causing broken @kurkle/color and helpers.dataset.js modulepreloads) - Replace json2csv (requires Node os/stream) with inline CSV formatter - Remove externalDependencies for os/stream (created broken require() in browser)
1 parent c8aefc6 commit ad8daa6

3 files changed

Lines changed: 96 additions & 94 deletions

File tree

angular.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
"options": {
1414
"allowedCommonJsDependencies": [
1515
"os",
16-
"stream"
17-
],
18-
"externalDependencies": [
1916
"stream",
20-
"os"
17+
"file-saver",
18+
"mammoth",
19+
"moment",
20+
"@kurkle/color"
2121
],
2222
"outputPath": {
2323
"base": "dist",
@@ -41,7 +41,6 @@
4141
],
4242
"scripts": [
4343
"node_modules/jquery/dist/jquery.min.js",
44-
"node_modules/chart.js/dist/chart.js",
4544
"node_modules/@uswds/uswds/dist/js/uswds-init.min.js",
4645
"node_modules/@uswds/uswds/dist/js/uswds.min.js"
4746
],

src/app/admin/admin-reports/login-reports.component.ts

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import {Component, OnInit} from '@angular/core';
2-
import {LoginReportService} from './login-report.service';
3-
import {SelectItem} from 'primeng/api';
4-
import {saveAs} from 'file-saver';
5-
import {parse} from 'json2csv';
1+
import { Component, OnInit } from '@angular/core';
2+
import { LoginReportService } from './login-report.service';
3+
import { SelectItem } from 'primeng/api';
4+
import { saveAs } from 'file-saver';
65
import { enUS } from 'date-fns/locale';
76
import 'chartjs-adapter-date-fns';
87
interface TimeSelection {
98
days: number;
109
}
1110

1211
@Component({
13-
selector: 'app-login-reports',
14-
templateUrl: './login-reports.component.html',
15-
styleUrls: ['./login-reports.component.scss'],
16-
standalone: false
12+
selector: 'app-login-reports',
13+
templateUrl: './login-reports.component.html',
14+
styleUrls: ['./login-reports.component.scss'],
15+
standalone: false
1716
})
1817

1918
export class LoginReportsComponent implements OnInit {
@@ -34,15 +33,15 @@ export class LoginReportsComponent implements OnInit {
3433
this.today.setHours(0, 0, 0, 0); // dates from db don't include timestamp, so remove that from our 'today' var
3534

3635
this.timeSelection = [
37-
{label: 'Show 7 days', value: {days: 7}},
38-
{label: 'Show 14 days', value: {days: 14}},
39-
{label: 'Show 30 days', value: {days: 30}},
40-
{label: 'Show 60 days', value: {days: 60}},
41-
{label: 'Show 90 days', value: {days: 90}},
42-
{label: 'Show 180 days', value: {days: 180}},
43-
{label: 'Show 365 days', value: {days: 365}}
36+
{ label: 'Show 7 days', value: { days: 7 } },
37+
{ label: 'Show 14 days', value: { days: 14 } },
38+
{ label: 'Show 30 days', value: { days: 30 } },
39+
{ label: 'Show 60 days', value: { days: 60 } },
40+
{ label: 'Show 90 days', value: { days: 90 } },
41+
{ label: 'Show 180 days', value: { days: 180 } },
42+
{ label: 'Show 365 days', value: { days: 365 } }
4443
];
45-
this.selection = {days: 30};
44+
this.selection = { days: 30 };
4645

4746
this.chartOptions = {
4847
plugins: {
@@ -59,9 +58,9 @@ export class LoginReportsComponent implements OnInit {
5958
}
6059
},
6160
x: {
62-
adapters: {
61+
adapters: {
6362
date: {
64-
locale: enUS,
63+
locale: enUS,
6564
},
6665
},
6766
display: true,
@@ -80,11 +79,11 @@ export class LoginReportsComponent implements OnInit {
8079

8180

8281
this.userChartCols = [
83-
{ field: 'email', header: 'Email Address'},
84-
{ field: 'lastLogin', header: 'Last Login'},
85-
{ field: 'sevenDays', header: 'Logins Last 7 Days'},
86-
{ field: 'thirtyDays', header: 'Logins Last 30 Days'},
87-
{ field: 'totalLogins', header: 'Total Logins All Time'}
82+
{ field: 'email', header: 'Email Address' },
83+
{ field: 'lastLogin', header: 'Last Login' },
84+
{ field: 'sevenDays', header: 'Logins Last 7 Days' },
85+
{ field: 'thirtyDays', header: 'Logins Last 30 Days' },
86+
{ field: 'totalLogins', header: 'Total Logins All Time' }
8887
];
8988

9089
loginReportService.getLoginReport()
@@ -117,9 +116,9 @@ export class LoginReportsComponent implements OnInit {
117116
labels: [],
118117
datasets: [
119118
{
120-
label: 'User Logins',
121-
data: [],
122-
fill: false,
119+
label: 'User Logins',
120+
data: [],
121+
fill: false,
123122
backgroundColor: '#2C81C0'
124123
}],
125124
};
@@ -129,31 +128,31 @@ export class LoginReportsComponent implements OnInit {
129128
let current_date = new Date();
130129
current_date.setHours(0, 0, 0, 0);
131130
let empty_dates = [];
132-
133-
for (let i = 0; i <= this.selection.days ; i++) {
131+
132+
for (let i = 0; i <= this.selection.days; i++) {
134133
empty_dates.push(new Date(current_date));
135134
current_date.setDate(current_date.getDate() - 1);
136135
}
137-
136+
138137
return empty_dates.reverse();
139138
})();
140139

141140
let chartLoginData = Array(this.selection.days).fill(0);
142141

143142
this.loginData.labels = chartLabelData;
144-
143+
145144
this.readerSupplement = '<table style="border: 1px black solid"><thead><tr><th>Date</th><th>Login Count</th></tr></thead>';
146145

147146
Object.keys(data).forEach(date => {
148147
const dateLogin = new Date(date);
149-
148+
150149
let index;
151-
if ((index = chartLabelData.findIndex(
150+
if ((index = chartLabelData.findIndex(
152151
function (x) {
153-
// Need to look at Value of Date because the Date object is different
154-
return x.valueOf() === dateLogin.valueOf();
155-
}
156-
)) != -1) {
152+
// Need to look at Value of Date because the Date object is different
153+
return x.valueOf() === dateLogin.valueOf();
154+
}
155+
)) != -1) {
157156
let loginsForDay = 0;
158157
Object.keys(data[date]).forEach(email => {
159158
loginsForDay += data[date][email];
@@ -185,8 +184,8 @@ export class LoginReportsComponent implements OnInit {
185184
Object.keys(data).forEach(date => {
186185

187186
Object.keys(data[date]).forEach(email => {
188-
if (! userAccumulator[email]) {
189-
userAccumulator[email] = { email: email, totalLogins: 0, sevenDays: 0, thirtyDays: 0, lastLogin: date};
187+
if (!userAccumulator[email]) {
188+
userAccumulator[email] = { email: email, totalLogins: 0, sevenDays: 0, thirtyDays: 0, lastLogin: date };
190189
}
191190
userAccumulator[email].totalLogins += data[date][email];
192191
totals.totalLogins += data[date][email];
@@ -212,7 +211,7 @@ export class LoginReportsComponent implements OnInit {
212211
});
213212
});
214213

215-
Object.keys(userAccumulator).forEach( email => {
214+
Object.keys(userAccumulator).forEach(email => {
216215
this.userData.push(userAccumulator[email]);
217216
});
218217
this.userData.push(totals);
@@ -226,17 +225,20 @@ export class LoginReportsComponent implements OnInit {
226225
downloadLoginData(data: any) {
227226

228227
const flatData = [];
229-
Object.keys(data).forEach( day => {
230-
Object.keys(data[day]).forEach( email => {
228+
Object.keys(data).forEach(day => {
229+
Object.keys(data[day]).forEach(email => {
231230
flatData.push(
232-
{date: day, email: email, 'number of logins': data[day][email]}
231+
{ date: day, email: email, 'number of logins': data[day][email] }
233232
);
234233
});
235234

236235
});
237236

238-
const csv = parse(flatData, ['email', 'date', 'number of logins']);
239-
saveAs(new Blob([csv], {type: 'text/csv; charset=utf-8'}), 'srt-login-report.csv');
237+
const fields = ['email', 'date', 'number of logins'];
238+
const header = fields.join(',');
239+
const rows = flatData.map(row => fields.map(f => '"' + String(row[f] ?? '').replace(/"/g, '""') + '"').join(','));
240+
const csv = [header, ...rows].join('\n');
241+
saveAs(new Blob([csv], { type: 'text/csv; charset=utf-8' }), 'srt-login-report.csv');
240242
}
241243

242244
ngOnInit() {

src/index.html

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,74 @@
11
<!doctype html>
22
<html lang="en">
3+
34
<head>
4-
5+
56
<meta charset="utf-8">
6-
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
7+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
78
<title>Solicitation Review Tool</title>
89
<base href="/">
910
<meta name="viewport" content="width=device-width, initial-scale=1">
1011
<link rel="icon" type="image/x-icon" href="favicon.ico">
1112

1213
<!-- Latest compiled and minified CSS -->
13-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
14-
14+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
15+
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
16+
1517
<!-- Bootstrap Icons -->
1618
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
1719

1820
<script>
19-
__Zone_enable_cross_context_check = true;
21+
__Zone_enable_cross_context_check = true;
2022
</script>
2123

2224

2325
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
2426
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
2527
</head>
28+
2629
<body>
2730
<!-- Google Tag Manager (noscript) -->
28-
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-T3PKVPJ5"
29-
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
31+
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-T3PKVPJ5" height="0" width="0"
32+
style="display:none;visibility:hidden"></iframe></noscript>
3033
<!-- End Google Tag Manager (noscript) -->
3134

3235
<app-root>Loading...</app-root>
3336

3437
<!-- Latest compiled and minified JavaScript -->
35-
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
38+
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
39+
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
40+
crossorigin="anonymous"></script>
3641
<script src="https://use.fontawesome.com/22ad9bb71f.js"></script>
3742

3843

3944
<script>
4045

4146
function casCheck() {
42-
const ticketParam = window.location.search.substr(1).split('&').map(function (x) {
43-
return x.split('=');
44-
}).filter(function (x) {
45-
return x[0] === 'token';
46-
});
47-
48-
var url_string = window.location.href;
49-
console.log(url_string);
50-
var url = new URL(url_string);
51-
var info = url.searchParams.get("info");
52-
const data = JSON.parse(decodeURIComponent(info));
53-
54-
if (data) {
55-
console.log('setting data');
56-
if (data.agency !== undefined) localStorage.setItem('agency', data.agency);
57-
if (data.email !== undefined) localStorage.setItem('email', data.email);
58-
if (data.firstName !== undefined) localStorage.setItem('firstName', data.firstName);
59-
if (data.id !== undefined) localStorage.setItem('id', data.id);
60-
if (data.lastName !== undefined) localStorage.setItem('lastName', data.lastName);
61-
if (data.position !== undefined) localStorage.setItem('position', data.position);
62-
if (data.token !== undefined) localStorage.setItem('token', data.token);
63-
if (data.userRole !== undefined) localStorage.setItem('userRole', data.userRole);
64-
if (data.loginMethod !== undefined) localStorage.setItem('loginMethod', data.loginMethod);
65-
66-
window.location = '/';
47+
const ticketParam = window.location.search.substr(1).split('&').map(function (x) {
48+
return x.split('=');
49+
}).filter(function (x) {
50+
return x[0] === 'token';
51+
});
52+
53+
var url_string = window.location.href;
54+
console.log(url_string);
55+
var url = new URL(url_string);
56+
var info = url.searchParams.get("info");
57+
const data = JSON.parse(decodeURIComponent(info));
58+
59+
if (data) {
60+
console.log('setting data');
61+
if (data.agency !== undefined) localStorage.setItem('agency', data.agency);
62+
if (data.email !== undefined) localStorage.setItem('email', data.email);
63+
if (data.firstName !== undefined) localStorage.setItem('firstName', data.firstName);
64+
if (data.id !== undefined) localStorage.setItem('id', data.id);
65+
if (data.lastName !== undefined) localStorage.setItem('lastName', data.lastName);
66+
if (data.position !== undefined) localStorage.setItem('position', data.position);
67+
if (data.token !== undefined) localStorage.setItem('token', data.token);
68+
if (data.userRole !== undefined) localStorage.setItem('userRole', data.userRole);
69+
if (data.loginMethod !== undefined) localStorage.setItem('loginMethod', data.loginMethod);
70+
71+
window.location = '/';
6772
}
6873
return false;
6974
}
@@ -76,20 +81,16 @@
7681
function errorUpdater() {
7782
const urlParams = new URLSearchParams(window.location.search);
7883
if (urlParams.has("error")) {
79-
const el = document.getElementById("login-error");
80-
const p = document.createElement('p');
81-
p.textContent = urlParams.get('error');
82-
el.appendChild(p);
84+
const el = document.getElementById("login-error");
85+
const p = document.createElement('p');
86+
p.textContent = urlParams.get('error');
87+
el.appendChild(p);
8388
}
8489
}
85-
setTimeout( errorUpdater, 1000);
90+
setTimeout(errorUpdater, 1000);
8691

8792

8893
</script>
89-
90-
<!-- uswds-init.js -->
91-
<script src="uswds-init.js"></script>
92-
93-
9494
</body>
95-
</html>
95+
96+
</html>

0 commit comments

Comments
 (0)