diff --git a/API/API.csproj b/API/API.csproj
index 0e494734e..29686bf30 100644
--- a/API/API.csproj
+++ b/API/API.csproj
@@ -76,6 +76,17 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs
index 9442ff9d8..c691817bd 100644
--- a/API/Controllers/AccountController.cs
+++ b/API/Controllers/AccountController.cs
@@ -603,7 +603,7 @@ public class AccountController : BaseApiController
{
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
- return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-already-registered", invitedUser!.UserName));
+ return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-already-registered", invitedUser.UserName));
return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-already-invited"));
}
@@ -684,7 +684,6 @@ public class AccountController : BaseApiController
{
var emailLink = await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", dto.Email);
_logger.LogCritical("[Invite User]: Email Link for {UserName}: {Link}", user.UserName, emailLink);
- _logger.LogCritical("[Invite User]: Token {UserName}: {Token}", user.UserName, user.ConfirmationToken);
if (!_emailService.IsValidEmail(dto.Email))
{
@@ -706,7 +705,6 @@ public class AccountController : BaseApiController
InvitingUser = adminUser.UserName!,
ServerConfirmationLink = emailLink
}));
-
}
return Ok(new InviteUserResponse
@@ -834,13 +832,13 @@ public class AccountController : BaseApiController
public async Task> ConfirmForgotPassword(ConfirmPasswordResetDto dto)
{
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
+ if (user == null)
+ {
+ return BadRequest(await _localizationService.Get("en", "bad-credentials"));
+ }
+
try
{
- if (user == null)
- {
- return BadRequest(await _localizationService.Get("en", "bad-credentials"));
- }
-
var result = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultProvider,
"ResetPassword", dto.Token);
if (!result)
diff --git a/API/DTOs/MemberDto.cs b/API/DTOs/MemberDto.cs
index 31b5e62be..226d47eae 100644
--- a/API/DTOs/MemberDto.cs
+++ b/API/DTOs/MemberDto.cs
@@ -18,7 +18,9 @@ public class MemberDto
public bool IsPending { get; init; }
public AgeRestrictionDto? AgeRestriction { get; init; }
public DateTime Created { get; init; }
+ public DateTime CreatedUtc { get; init; }
public DateTime LastActive { get; init; }
+ public DateTime LastActiveUtc { get; init; }
public IEnumerable? Libraries { get; init; }
public IEnumerable? Roles { get; init; }
}
diff --git a/API/Data/Repositories/UserRepository.cs b/API/Data/Repositories/UserRepository.cs
index e230eba09..0b604e59e 100644
--- a/API/Data/Repositories/UserRepository.cs
+++ b/API/Data/Repositories/UserRepository.cs
@@ -665,7 +665,9 @@ public class UserRepository : IUserRepository
Username = u.UserName,
Email = u.Email,
Created = u.Created,
+ CreatedUtc = u.CreatedUtc,
LastActive = u.LastActive,
+ LastActiveUtc = u.LastActiveUtc,
Roles = u.UserRoles.Select(r => r.Role.Name).ToList(),
IsPending = !u.EmailConfirmed,
AgeRestriction = new AgeRestrictionDto()
diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs
index 488d58ad1..b807e4dcd 100644
--- a/API/Data/Seed.cs
+++ b/API/Data/Seed.cs
@@ -120,6 +120,7 @@ public static class Seed
}
});
+
public static async Task SeedRoles(RoleManager roleManager)
{
var roles = typeof(PolicyConstants)
diff --git a/API/Services/StatisticService.cs b/API/Services/StatisticService.cs
index 2c8552749..7c48ac5dd 100644
--- a/API/Services/StatisticService.cs
+++ b/API/Services/StatisticService.cs
@@ -78,10 +78,8 @@ public class StatisticService : IStatisticService
.CountAsync();
var lastActive = await _context.AppUserProgresses
- .OrderByDescending(p => p.LastModified)
.Where(p => p.AppUserId == userId)
- .Select(p => p.LastModified)
- .FirstOrDefaultAsync();
+ .MaxAsync(p => p.LastModified);
// First get the total pages per library
@@ -103,15 +101,28 @@ public class StatisticService : IStatisticService
})
.ToListAsync();
- var averageReadingTimePerWeek = _context.AppUserProgresses
+
+ // New solution. Calculate total hours then divide by number of weeks from time account was created (or min reading event) till now
+ var averageReadingTimePerWeek = await _context.AppUserProgresses
.Where(p => p.AppUserId == userId)
.Join(_context.Chapter, p => p.ChapterId, c => c.Id,
(p, c) => new
{
- AverageReadingHours = Math.Min((float) p.PagesRead / (float) c.Pages, 1.0) * ((float) c.AvgHoursToRead)
+ AverageReadingHours = Math.Min((float) p.PagesRead / (float) c.Pages, 1.0) *
+ ((float) c.AvgHoursToRead)
})
.Select(x => x.AverageReadingHours)
- .Average() * 7.0;
+ .SumAsync();
+
+ var earliestReadDate = await _context.AppUserProgresses
+ .Where(p => p.AppUserId == userId)
+ .MinAsync(p => p.Created);
+
+ var timeDifference = DateTime.Now - earliestReadDate;
+ var deltaWeeks = (int)Math.Ceiling(timeDifference.TotalDays / 7);
+
+ averageReadingTimePerWeek /= deltaWeeks;
+
return new UserReadStatistics()
{
diff --git a/UI/Web/angular.json b/UI/Web/angular.json
index 30a197ec3..7ce634e46 100644
--- a/UI/Web/angular.json
+++ b/UI/Web/angular.json
@@ -47,11 +47,7 @@
"src/styles.scss",
"node_modules/@fortawesome/fontawesome-free/css/all.min.css"
],
- "scripts": [
- "node_modules/lazysizes/lazysizes.min.js",
- "node_modules/lazysizes/plugins/rias/ls.rias.min.js",
- "node_modules/lazysizes/plugins/attrchange/ls.attrchange.min.js"
- ],
+ "scripts": [],
"sourceMap": {
"hidden": false,
"scripts": true,
diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json
index 03e677260..8cb067001 100644
--- a/UI/Web/package-lock.json
+++ b/UI/Web/package-lock.json
@@ -8,23 +8,23 @@
"name": "kavita-webui",
"version": "0.4.2",
"dependencies": {
- "@angular/animations": "^16.2.9",
- "@angular/cdk": "^16.2.8",
- "@angular/common": "^16.2.9",
- "@angular/compiler": "^16.2.9",
- "@angular/core": "^16.2.9",
- "@angular/forms": "^16.2.9",
- "@angular/localize": "^16.2.9",
- "@angular/platform-browser": "^16.2.9",
- "@angular/platform-browser-dynamic": "^16.2.9",
- "@angular/router": "^16.2.9",
+ "@angular/animations": "^16.2.12",
+ "@angular/cdk": "^16.2.11",
+ "@angular/common": "^16.2.12",
+ "@angular/compiler": "^16.2.12",
+ "@angular/core": "^16.2.12",
+ "@angular/forms": "^16.2.12",
+ "@angular/localize": "^16.2.12",
+ "@angular/platform-browser": "^16.2.12",
+ "@angular/platform-browser-dynamic": "^16.2.12",
+ "@angular/router": "^16.2.12",
"@fortawesome/fontawesome-free": "^6.4.2",
"@iharbeck/ngx-virtual-scroller": "^16.0.0",
"@iplab/ngx-file-upload": "^16.0.2",
"@lithiumjs/angular": "^7.3.0",
"@lithiumjs/ngx-virtual-scroll": "^0.3.0",
"@microsoft/signalr": "^7.0.12",
- "@ng-bootstrap/ng-bootstrap": "^15.1.1",
+ "@ng-bootstrap/ng-bootstrap": "^15.1.2",
"@ngneat/transloco": "^6.0.0",
"@ngneat/transloco-locale": "^5.1.1",
"@ngneat/transloco-persist-lang": "^5.0.0",
@@ -33,16 +33,18 @@
"@popperjs/core": "^2.11.7",
"@swimlane/ngx-charts": "^20.1.2",
"@tweenjs/tween.js": "^21.0.0",
- "@types/file-saver": "^2.0.5",
+ "@types/file-saver": "^2.0.6",
+ "angular-animations": "^0.11.0",
"bootstrap": "^5.3.1",
+ "charts.css": "^1.1.0",
"eventsource": "^2.0.2",
"file-saver": "^2.0.5",
- "lazysizes": "^5.3.2",
"luxon": "^3.4.3",
"ng-circle-progress": "^1.7.1",
+ "ng-lazyload-image": "^9.1.3",
"ng-select2-component": "^13.0.9",
"ngx-color-picker": "^15.0.0",
- "ngx-extended-pdf-viewer": "^18.0.2",
+ "ngx-extended-pdf-viewer": "^18.1.4",
"ngx-file-drop": "^16.0.0",
"ngx-slider-v2": "^16.0.2",
"ngx-stars": "^1.6.5",
@@ -54,20 +56,20 @@
"zone.js": "^0.13.0"
},
"devDependencies": {
- "@angular-devkit/build-angular": "^16.2.6",
+ "@angular-devkit/build-angular": "^16.2.9",
"@angular-eslint/builder": "^16.2.0",
"@angular-eslint/eslint-plugin": "^16.2.0",
"@angular-eslint/eslint-plugin-template": "^16.2.0",
"@angular-eslint/schematics": "^16.2.0",
"@angular-eslint/template-parser": "^16.2.0",
- "@angular/cli": "^16.2.6",
- "@angular/compiler-cli": "^16.2.9",
- "@types/d3": "^7.4.1",
- "@types/luxon": "^3.3.2",
- "@types/node": "^20.8.6",
+ "@angular/cli": "^16.2.9",
+ "@angular/compiler-cli": "^16.2.12",
+ "@types/d3": "^7.4.2",
+ "@types/luxon": "^3.3.3",
+ "@types/node": "^20.8.10",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
- "eslint": "^8.51.0",
+ "eslint": "^8.52.0",
"jsonminify": "^0.4.2",
"karma-coverage": "~2.2.0",
"ts-node": "~10.9.1",
@@ -97,12 +99,12 @@
}
},
"node_modules/@angular-devkit/architect": {
- "version": "0.1602.6",
- "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.6.tgz",
- "integrity": "sha512-b1NNV3yNg6Rt86ms20bJIroWUI8ihaEwv5k+EoijEXLoMs4eNs5PhqL+QE8rTj+q9pa1gSrWf2blXor2JGwf1g==",
+ "version": "0.1602.9",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.9.tgz",
+ "integrity": "sha512-U3vfb/e2sFfg0D9FyyRBXRPP7g4FBFtGK8Q3JPmvAVsHHwi5AUFRNR7YBChB/T5TMNY077HcTyEirVh2FeUpdA==",
"dev": true,
"dependencies": {
- "@angular-devkit/core": "16.2.6",
+ "@angular-devkit/core": "16.2.9",
"rxjs": "7.8.1"
},
"engines": {
@@ -112,15 +114,15 @@
}
},
"node_modules/@angular-devkit/build-angular": {
- "version": "16.2.6",
- "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.6.tgz",
- "integrity": "sha512-QdU/q77K1P8CPEEZGxw1QqLcnA9ofboDWS7vcLRBmFmk2zydtLTApbK0P8GNDRbnmROOKkoaLo+xUTDJz9gvPA==",
+ "version": "16.2.9",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.9.tgz",
+ "integrity": "sha512-S1C4UYxRVyNt3C0wCxbT2jZ1dN5i37kS0mol3PQjbR8gQ0GQzHmzhjTBl1oImo8aouET9yhrk9etk65oat4mBQ==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "2.2.1",
- "@angular-devkit/architect": "0.1602.6",
- "@angular-devkit/build-webpack": "0.1602.6",
- "@angular-devkit/core": "16.2.6",
+ "@angular-devkit/architect": "0.1602.9",
+ "@angular-devkit/build-webpack": "0.1602.9",
+ "@angular-devkit/core": "16.2.9",
"@babel/core": "7.22.9",
"@babel/generator": "7.22.9",
"@babel/helper-annotate-as-pure": "7.22.5",
@@ -132,7 +134,7 @@
"@babel/runtime": "7.22.6",
"@babel/template": "7.22.5",
"@discoveryjs/json-ext": "0.5.7",
- "@ngtools/webpack": "16.2.6",
+ "@ngtools/webpack": "16.2.9",
"@vitejs/plugin-basic-ssl": "1.0.1",
"ansi-colors": "4.1.3",
"autoprefixer": "10.4.14",
@@ -702,12 +704,12 @@
"dev": true
},
"node_modules/@angular-devkit/build-webpack": {
- "version": "0.1602.6",
- "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.6.tgz",
- "integrity": "sha512-BJPR6xdq7gRJ6bVWnZ81xHyH75j7lyLbegCXbvUNaM8TWVBkwWsSdqr2NQ717dNLLn5umg58SFpU/pWMq6CxMQ==",
+ "version": "0.1602.9",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.9.tgz",
+ "integrity": "sha512-+3IxovfBPR2Vy730mGa0SVKkd5LQVom85gjXOs7WcnnnZmfc1q/BtFlqTgW1UWvTxP8IQdm7UYWVclQfL/WExw==",
"dev": true,
"dependencies": {
- "@angular-devkit/architect": "0.1602.6",
+ "@angular-devkit/architect": "0.1602.9",
"rxjs": "7.8.1"
},
"engines": {
@@ -721,9 +723,9 @@
}
},
"node_modules/@angular-devkit/core": {
- "version": "16.2.6",
- "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.6.tgz",
- "integrity": "sha512-iez/8NYXQT6fqVQLlKmZUIRkFUEZ88ACKbTwD4lBmk0+hXW+bQBxI7JOnE3C4zkcM2YeuTXIYsC5SebTKYiR4Q==",
+ "version": "16.2.9",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.9.tgz",
+ "integrity": "sha512-dcHWjHBNGm3yCeNz19y8A1At4KgyC6XHNnbFL0y+nnZYiaESXjUoXJYKASedI6A+Bpl0HNq2URhH6bL6Af3+4w==",
"dev": true,
"dependencies": {
"ajv": "8.12.0",
@@ -748,12 +750,12 @@
}
},
"node_modules/@angular-devkit/schematics": {
- "version": "16.2.6",
- "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.6.tgz",
- "integrity": "sha512-PhpRYHCJ3WvZXmng6Qk8TXeQf83jeBMAf7AIzI8h0fgeBocOl97Xf7bZpLg6GymiU+rVn15igQ4Rz9rKAay8bQ==",
+ "version": "16.2.9",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.9.tgz",
+ "integrity": "sha512-lB51CGCILpcSI37CwKUAGDLxMqh7zmuRbiPo9s9mSkCM4ccqxFlaL+VFTq2/laneARD6aikpOHnkVm5myNzQPw==",
"dev": true,
"dependencies": {
- "@angular-devkit/core": "16.2.6",
+ "@angular-devkit/core": "16.2.9",
"jsonc-parser": "3.2.0",
"magic-string": "0.30.1",
"ora": "5.4.1",
@@ -864,9 +866,9 @@
}
},
"node_modules/@angular/animations": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.9.tgz",
- "integrity": "sha512-J+nsc2x/ZQuh+YwwTzxXUrV+7SBpJq6DDStfTFkZls9PWGRj9fjqQeRCWrfNLllpxopAEjhFkoyK06oSjcwqAw==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.12.tgz",
+ "integrity": "sha512-MD0ElviEfAJY8qMOd6/jjSSvtqER2RDAi0lxe6EtUacC1DHCYkaPrKW4vLqY+tmZBg1yf+6n+uS77pXcHHcA3w==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -874,13 +876,13 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/core": "16.2.9"
+ "@angular/core": "16.2.12"
}
},
"node_modules/@angular/cdk": {
- "version": "16.2.8",
- "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.8.tgz",
- "integrity": "sha512-DvqxH909mgSSxWbc5xM5xKLjDMPXY3pzzSVAllngvc9KGPFw240WCs3tSpPaVJI50Esbzdu5O0CyTBfu9jUy4g==",
+ "version": "16.2.11",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-16.2.11.tgz",
+ "integrity": "sha512-FcJ9xd9ptjULdScnBNg7YkVnY9NKePFfmvvs2zt841Hd489L8BUkTUdbvtCLhMJTTSN+k+D+RYFhevZuhPKVVg==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -894,15 +896,15 @@
}
},
"node_modules/@angular/cli": {
- "version": "16.2.6",
- "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.6.tgz",
- "integrity": "sha512-9poPvUEmlufOAW1Cjk+aA5e2x3mInLtbYYSL/EYviDN2ugmavsSIvxAE/WLnxq6cPWqhNDbHDaqvcmqkcFM3Cw==",
+ "version": "16.2.9",
+ "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-16.2.9.tgz",
+ "integrity": "sha512-wkpV/Ni26LUeDmhee2TPXXEq3feEdZMSG8+nkfUK9kqIcxm0IjI1GLPeiVOX7aQobuKNe2cCAFNwsrXWjj+2og==",
"dev": true,
"dependencies": {
- "@angular-devkit/architect": "0.1602.6",
- "@angular-devkit/core": "16.2.6",
- "@angular-devkit/schematics": "16.2.6",
- "@schematics/angular": "16.2.6",
+ "@angular-devkit/architect": "0.1602.9",
+ "@angular-devkit/core": "16.2.9",
+ "@angular-devkit/schematics": "16.2.9",
+ "@schematics/angular": "16.2.9",
"@yarnpkg/lockfile": "1.1.0",
"ansi-colors": "4.1.3",
"ini": "4.1.1",
@@ -961,9 +963,9 @@
"dev": true
},
"node_modules/@angular/common": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.9.tgz",
- "integrity": "sha512-5Lh5KsxCkaoBDeSAghKNF5lCi0083ug4X2X7wnafsSd6Z3xt/rDjH9hDOP5SF5IDLtCVjJgHfs3cCLSTjRuNwg==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.12.tgz",
+ "integrity": "sha512-B+WY/cT2VgEaz9HfJitBmgdk4I333XG/ybC98CMC4Wz8E49T8yzivmmxXB3OD6qvjcOB6ftuicl6WBqLbZNg2w==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -971,14 +973,14 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/core": "16.2.9",
+ "@angular/core": "16.2.12",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/@angular/compiler": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.9.tgz",
- "integrity": "sha512-lh799pnbdvzTVShJHOY1JC6c1pwBsZC4UIgB3Itklo9dskGybQma/gP+lE6RhqM4FblNfaaBXGlCMUuY8HkmEQ==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-16.2.12.tgz",
+ "integrity": "sha512-6SMXUgSVekGM7R6l1Z9rCtUGtlg58GFmgbpMCsGf+VXxP468Njw8rjT2YZkf5aEPxEuRpSHhDYjqz7n14cwCXQ==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -986,7 +988,7 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/core": "16.2.9"
+ "@angular/core": "16.2.12"
},
"peerDependenciesMeta": {
"@angular/core": {
@@ -995,12 +997,12 @@
}
},
"node_modules/@angular/compiler-cli": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.9.tgz",
- "integrity": "sha512-ecH2oOlijJdDqioD9IfgdqJGoRRHI6hAx5rwBxIaYk01ywj13KzvXWPrXbCIupeWtV/XUZUlbwf47nlmL5gxZg==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-16.2.12.tgz",
+ "integrity": "sha512-pWSrr152562ujh6lsFZR8NfNc5Ljj+zSTQO44DsuB0tZjwEpnRcjJEgzuhGXr+CoiBf+jTSPZKemtSktDk5aaA==",
"dev": true,
"dependencies": {
- "@babel/core": "7.22.5",
+ "@babel/core": "7.23.2",
"@jridgewell/sourcemap-codec": "^1.4.14",
"chokidar": "^3.0.0",
"convert-source-map": "^1.5.1",
@@ -1018,14 +1020,14 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/compiler": "16.2.9",
+ "@angular/compiler": "16.2.12",
"typescript": ">=4.9.3 <5.2"
}
},
"node_modules/@angular/core": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.9.tgz",
- "integrity": "sha512-chvPX29ZBcMDuh7rLIgb0Cru6oJ/0FaqRzfOI3wT4W2F9W1HOlCtipovzmPYaUAmXBWfVP4EBO9TOWnpog0S0w==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.12.tgz",
+ "integrity": "sha512-GLLlDeke/NjroaLYOks0uyzFVo6HyLl7VOm0K1QpLXnYvW63W9Ql/T3yguRZa7tRkOAeFZ3jw+1wnBD4O8MoUA==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1038,9 +1040,9 @@
}
},
"node_modules/@angular/forms": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.9.tgz",
- "integrity": "sha512-rxlg2iNJNBH/uc7b5YqybfYc8BkLzzPv1d/nMsQUlY0O2UV2zwNRpcIiWbWd7+ZaKjcyPynVe9FsXC8wgWIABw==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.12.tgz",
+ "integrity": "sha512-1Eao89hlBgLR3v8tU91vccn21BBKL06WWxl7zLpQmG6Hun+2jrThgOE4Pf3os4fkkbH4Apj0tWL2fNIWe/blbw==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1048,18 +1050,18 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/common": "16.2.9",
- "@angular/core": "16.2.9",
- "@angular/platform-browser": "16.2.9",
+ "@angular/common": "16.2.12",
+ "@angular/core": "16.2.12",
+ "@angular/platform-browser": "16.2.12",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/@angular/localize": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-16.2.9.tgz",
- "integrity": "sha512-t5002NgBj+wjd81IXwg+yc2ypaBk6OWLAka1GXmWua3x7hwGw1yMtPFmzOE1cCNdXgWlluLxWclFjCUrAbGEww==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-16.2.12.tgz",
+ "integrity": "sha512-sNIHDlZKENPQqx64qGF99g2sOCy9i9O4VOmjKD/FZbeE8O5qBbaQlkwOlFoQIt35/cnvtAtf7oQF6tqmiVtS2w==",
"dependencies": {
- "@babel/core": "7.22.5",
+ "@babel/core": "7.23.2",
"fast-glob": "3.3.0",
"yargs": "^17.2.1"
},
@@ -1072,8 +1074,8 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/compiler": "16.2.9",
- "@angular/compiler-cli": "16.2.9"
+ "@angular/compiler": "16.2.12",
+ "@angular/compiler-cli": "16.2.12"
}
},
"node_modules/@angular/localize/node_modules/fast-glob": {
@@ -1092,9 +1094,9 @@
}
},
"node_modules/@angular/platform-browser": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.9.tgz",
- "integrity": "sha512-9Je7+Jmx0AOyRzBBumraVJG3M0R6YbT4c9jTUbLGJCcPxwDI3/u2ZzvW3rBqpmrDaqLxN5f1LcZeTZx287QeqQ==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-16.2.12.tgz",
+ "integrity": "sha512-NnH7ju1iirmVEsUq432DTm0nZBGQsBrU40M3ZeVHMQ2subnGiyUs3QyzDz8+VWLL/T5xTxWLt9BkDn65vgzlIQ==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1102,9 +1104,9 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/animations": "16.2.9",
- "@angular/common": "16.2.9",
- "@angular/core": "16.2.9"
+ "@angular/animations": "16.2.12",
+ "@angular/common": "16.2.12",
+ "@angular/core": "16.2.12"
},
"peerDependenciesMeta": {
"@angular/animations": {
@@ -1113,9 +1115,9 @@
}
},
"node_modules/@angular/platform-browser-dynamic": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.9.tgz",
- "integrity": "sha512-ztpo0939vTZ/5CWVSvo41Yl6YPoTZ0If+yTrs7dk1ce0vFgaZXMlc+y5ZwjJIiMM5CvHbhL48Uk+HJNIojP98A==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-16.2.12.tgz",
+ "integrity": "sha512-ya54jerNgreCVAR278wZavwjrUWImMr2F8yM5n9HBvsMBbFaAQ83anwbOEiHEF2BlR+gJiEBLfpuPRMw20pHqw==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1123,16 +1125,16 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/common": "16.2.9",
- "@angular/compiler": "16.2.9",
- "@angular/core": "16.2.9",
- "@angular/platform-browser": "16.2.9"
+ "@angular/common": "16.2.12",
+ "@angular/compiler": "16.2.12",
+ "@angular/core": "16.2.12",
+ "@angular/platform-browser": "16.2.12"
}
},
"node_modules/@angular/router": {
- "version": "16.2.9",
- "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.2.9.tgz",
- "integrity": "sha512-5vrJNMblTDx3WC3dtaqLddWNtR0P9iwpqffeZL1uobBIwP4hbJx+8Dos3TwxGR4hnopFKahoDQ5nC0NOQslyog==",
+ "version": "16.2.12",
+ "resolved": "https://registry.npmjs.org/@angular/router/-/router-16.2.12.tgz",
+ "integrity": "sha512-aU6QnYSza005V9P3W6PpkieL56O0IHps96DjqI1RS8yOJUl3THmokqYN4Fm5+HXy4f390FN9i6ftadYQDKeWmA==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1140,9 +1142,9 @@
"node": "^16.14.0 || >=18.10.0"
},
"peerDependencies": {
- "@angular/common": "16.2.9",
- "@angular/core": "16.2.9",
- "@angular/platform-browser": "16.2.9",
+ "@angular/common": "16.2.12",
+ "@angular/core": "16.2.12",
+ "@angular/platform-browser": "16.2.12",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
@@ -1173,25 +1175,25 @@
}
},
"node_modules/@babel/core": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
- "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
+ "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.5",
- "@babel/helper-compilation-targets": "^7.22.5",
- "@babel/helper-module-transforms": "^7.22.5",
- "@babel/helpers": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.5",
- "@babel/types": "^7.22.5",
- "convert-source-map": "^1.7.0",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-compilation-targets": "^7.22.15",
+ "@babel/helper-module-transforms": "^7.23.0",
+ "@babel/helpers": "^7.23.2",
+ "@babel/parser": "^7.23.0",
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0",
+ "convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
- "json5": "^2.2.2",
- "semver": "^6.3.0"
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
@@ -1201,6 +1203,38 @@
"url": "https://opencollective.com/babel"
}
},
+ "node_modules/@babel/core/node_modules/@babel/generator": {
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
+ "dependencies": {
+ "@babel/types": "^7.23.0",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/@babel/template": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "dependencies": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
+ },
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -1213,6 +1247,7 @@
"version": "7.22.9",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
"integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+ "dev": true,
"dependencies": {
"@babel/types": "^7.22.5",
"@jridgewell/gen-mapping": "^0.3.2",
@@ -1571,13 +1606,26 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
- "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
+ "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
"dependencies": {
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.6",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.23.2",
+ "@babel/types": "^7.23.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers/node_modules/@babel/template": {
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "dependencies": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
@@ -2863,6 +2911,7 @@
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
"integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "dev": true,
"dependencies": {
"@babel/code-frame": "^7.22.5",
"@babel/parser": "^7.22.5",
@@ -3417,9 +3466,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.51.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz",
- "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==",
+ "version": "8.52.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz",
+ "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3435,12 +3484,12 @@
}
},
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.11",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
- "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
+ "version": "0.11.13",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
+ "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
"dev": true,
"dependencies": {
- "@humanwhocodes/object-schema": "^1.2.1",
+ "@humanwhocodes/object-schema": "^2.0.1",
"debug": "^4.1.1",
"minimatch": "^3.0.5"
},
@@ -3462,9 +3511,9 @@
}
},
"node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
+ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
"node_modules/@iharbeck/ngx-virtual-scroller": {
@@ -3711,9 +3760,9 @@
}
},
"node_modules/@ng-bootstrap/ng-bootstrap": {
- "version": "15.1.1",
- "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-15.1.1.tgz",
- "integrity": "sha512-nZlIMMggtI3IHkGs0XPrUIUdpeEzQvfGV9M4I9IvCqiS2n4RwWoUvWK1ICo4csZqFNBDlCQx956gO6ZZUSL2mw==",
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-15.1.2.tgz",
+ "integrity": "sha512-mM2yiGnt9o7KZLIFp8K1vjfmVfu7HR3d8dhH5SszfArbgn9DvvQ4P5D5TDGygzyBSzeyZe18p7I8rX8vgA6DKw==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -3817,9 +3866,9 @@
}
},
"node_modules/@ngtools/webpack": {
- "version": "16.2.6",
- "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.6.tgz",
- "integrity": "sha512-d8ZlZL6dOtWmHdjG9PTGBkdiJMcsXD2tp6WeFRVvTEuvCI3XvKsUXBvJDE+mZOhzn5pUEYt+1TR5DHjDZbME3w==",
+ "version": "16.2.9",
+ "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.9.tgz",
+ "integrity": "sha512-rOclD7FfT4OSwVA0nDnULbJS6TORJ0+sQiuT2ebaNFErYr3LOm6Zut05tnmzFw8q1cePrILbG+xpnbggNr9Pyw==",
"dev": true,
"engines": {
"node": "^16.14.0 || >=18.10.0",
@@ -4243,13 +4292,13 @@
}
},
"node_modules/@schematics/angular": {
- "version": "16.2.6",
- "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.6.tgz",
- "integrity": "sha512-fM09WPqST+nhVGV5Q3fhG7WKo96kgSVMsbz3wGS0DmTn4zge7ZWnrW3VvbxnMapmGoKa9DFPqdqNln4ADcdIMQ==",
+ "version": "16.2.9",
+ "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.9.tgz",
+ "integrity": "sha512-uiU2YbZRVHgk1N1DDsek/5CKhfpZ8myJYNJk8eHV5LswnXOP3aqvH23VhneaAgOYwK5fISC7eMG0pLVKMvFfZQ==",
"dev": true,
"dependencies": {
- "@angular-devkit/core": "16.2.6",
- "@angular-devkit/schematics": "16.2.6",
+ "@angular-devkit/core": "16.2.9",
+ "@angular-devkit/schematics": "16.2.9",
"jsonc-parser": "3.2.0"
},
"engines": {
@@ -4434,9 +4483,9 @@
}
},
"node_modules/@types/d3": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.1.tgz",
- "integrity": "sha512-lBpYmbHTCtFKO1DB1R7E9dXp9/g1F3JXSGOF7iKPZ+wRmYg/Q6tCRHODGOc5Qk25fJRe2PI60EDRf2HLPUncMA==",
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.2.tgz",
+ "integrity": "sha512-Y4g2Yb30ZJmmtqAJTqMRaqXwRawfvpdpVmyEYEcyGNhrQI/Zvkq3k7yE1tdN07aFSmNBfvmegMQ9Fe2qy9ZMhw==",
"dev": true,
"dependencies": {
"@types/d3-array": "*",
@@ -4737,9 +4786,9 @@
}
},
"node_modules/@types/file-saver": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
- "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ=="
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.6.tgz",
+ "integrity": "sha512-Mw671DVqoMHbjw0w4v2iiOro01dlT/WhWp5uwecBa0Wg8c+bcZOjgF1ndBnlaxhtvFCgTRBtsGivSVhrK/vnag=="
},
"node_modules/@types/geojson": {
"version": "7946.0.10",
@@ -4769,9 +4818,9 @@
"dev": true
},
"node_modules/@types/luxon": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.2.tgz",
- "integrity": "sha512-l5cpE57br4BIjK+9BSkFBOsWtwv6J9bJpC7gdXIzZyI0vuKvNTk0wZZrkQxMGsUAuGW9+WMNWF2IJMD7br2yeQ==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.3.tgz",
+ "integrity": "sha512-/BJF3NT0pRMuxrenr42emRUF67sXwcZCd+S1ksG/Fcf9O7C3kKCY4uJSbKBE4KDUIYr3WMsvfmWD8hRjXExBJQ==",
"dev": true
},
"node_modules/@types/mime": {
@@ -4781,12 +4830,12 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.8.6",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz",
- "integrity": "sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==",
+ "version": "20.8.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz",
+ "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==",
"dev": true,
"dependencies": {
- "undici-types": "~5.25.1"
+ "undici-types": "~5.26.4"
}
},
"node_modules/@types/qs": {
@@ -5322,6 +5371,12 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true
+ },
"node_modules/@vitejs/plugin-basic-ssl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz",
@@ -5839,6 +5894,17 @@
"ajv": "^8.8.2"
}
},
+ "node_modules/angular-animations": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/angular-animations/-/angular-animations-0.11.0.tgz",
+ "integrity": "sha512-P2RuOe+T97bhgGDLtOYK9V45QA5y+kFUxoJfRAua8Ymo0bI5lWyw8oiVmBoEIZUU+nooYoJvQXgVKuZJA7/z3g==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "@angular/animations": ">=6.0.0"
+ }
+ },
"node_modules/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -6458,6 +6524,11 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
+ "node_modules/charts.css": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/charts.css/-/charts.css-1.1.0.tgz",
+ "integrity": "sha512-K1Qyb8ZKsu5cDrVbZeHECk/xSq6iOl8IDTR35uaMdhr/Vyyxvg9nYQy3KNB3aidxJ2E251afX5q2725N0uL3Vw=="
+ },
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -6724,7 +6795,8 @@
"node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "dev": true
},
"node_modules/cookie": {
"version": "0.5.0",
@@ -7852,18 +7924,19 @@
}
},
"node_modules/eslint": {
- "version": "8.51.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz",
- "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==",
+ "version": "8.52.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz",
+ "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "8.51.0",
- "@humanwhocodes/config-array": "^0.11.11",
+ "@eslint/js": "8.52.0",
+ "@humanwhocodes/config-array": "^0.11.13",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -10285,11 +10358,6 @@
"shell-quote": "^1.8.1"
}
},
- "node_modules/lazysizes": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/lazysizes/-/lazysizes-5.3.2.tgz",
- "integrity": "sha512-22UzWP+Vedi/sMeOr8O7FWimRVtiNJV2HCa+V8+peZOw6QbswN9k58VUhd7i6iK5bw5QkYrF01LJbeJe0PV8jg=="
- },
"node_modules/less": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz",
@@ -11160,6 +11228,19 @@
"rxjs": ">=6.4.0"
}
},
+ "node_modules/ng-lazyload-image": {
+ "version": "9.1.3",
+ "resolved": "https://registry.npmjs.org/ng-lazyload-image/-/ng-lazyload-image-9.1.3.tgz",
+ "integrity": "sha512-GlajmzbKhQCvg9pcrASq4fe/MNv9KoifGe6N+xRbseaBrNj2uwU4Vwic041NlmAQFEkpDM1H2EJCAjjmJeF7Hg==",
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "peerDependencies": {
+ "@angular/common": ">=11.0.0",
+ "@angular/core": ">=11.0.0",
+ "rxjs": ">=6.0.0"
+ }
+ },
"node_modules/ng-select2-component": {
"version": "13.0.9",
"resolved": "https://registry.npmjs.org/ng-select2-component/-/ng-select2-component-13.0.9.tgz",
@@ -11188,9 +11269,9 @@
}
},
"node_modules/ngx-extended-pdf-viewer": {
- "version": "18.0.2",
- "resolved": "https://registry.npmjs.org/ngx-extended-pdf-viewer/-/ngx-extended-pdf-viewer-18.0.2.tgz",
- "integrity": "sha512-CgRR39Fb0ZLsuzvNbiFPXuJL72bAqnvJyhytVQjsOo66ZQMnQA9dkU/YbkDKr25Btk/+PtAJmSkbBpPgyNxj1Q==",
+ "version": "18.1.4",
+ "resolved": "https://registry.npmjs.org/ngx-extended-pdf-viewer/-/ngx-extended-pdf-viewer-18.1.4.tgz",
+ "integrity": "sha512-adKahqatF/AgUfDLkEIpT1SQoBjDKgr+/0Tzdsy13uWvPgECw/2hzg1f0m0JvWkR2zeAUY44/yK5BBrOBnVbbQ==",
"dependencies": {
"lodash.deburr": "^4.1.0",
"tslib": "^2.3.0"
@@ -14481,9 +14562,9 @@
}
},
"node_modules/undici-types": {
- "version": "5.25.3",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz",
- "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==",
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/unicode-canonical-property-names-ecmascript": {
diff --git a/UI/Web/package.json b/UI/Web/package.json
index ba4128128..f384f90b2 100644
--- a/UI/Web/package.json
+++ b/UI/Web/package.json
@@ -13,23 +13,23 @@
},
"private": true,
"dependencies": {
- "@angular/animations": "^16.2.9",
- "@angular/cdk": "^16.2.8",
- "@angular/common": "^16.2.9",
- "@angular/compiler": "^16.2.9",
- "@angular/core": "^16.2.9",
- "@angular/forms": "^16.2.9",
- "@angular/localize": "^16.2.9",
- "@angular/platform-browser": "^16.2.9",
- "@angular/platform-browser-dynamic": "^16.2.9",
- "@angular/router": "^16.2.9",
+ "@angular/animations": "^16.2.12",
+ "@angular/cdk": "^16.2.11",
+ "@angular/common": "^16.2.12",
+ "@angular/compiler": "^16.2.12",
+ "@angular/core": "^16.2.12",
+ "@angular/forms": "^16.2.12",
+ "@angular/localize": "^16.2.12",
+ "@angular/platform-browser": "^16.2.12",
+ "@angular/platform-browser-dynamic": "^16.2.12",
+ "@angular/router": "^16.2.12",
"@fortawesome/fontawesome-free": "^6.4.2",
"@iharbeck/ngx-virtual-scroller": "^16.0.0",
"@iplab/ngx-file-upload": "^16.0.2",
"@lithiumjs/angular": "^7.3.0",
"@lithiumjs/ngx-virtual-scroll": "^0.3.0",
"@microsoft/signalr": "^7.0.12",
- "@ng-bootstrap/ng-bootstrap": "^15.1.1",
+ "@ng-bootstrap/ng-bootstrap": "^15.1.2",
"@ngneat/transloco": "^6.0.0",
"@ngneat/transloco-locale": "^5.1.1",
"@ngneat/transloco-persist-lang": "^5.0.0",
@@ -38,16 +38,18 @@
"@popperjs/core": "^2.11.7",
"@swimlane/ngx-charts": "^20.1.2",
"@tweenjs/tween.js": "^21.0.0",
- "@types/file-saver": "^2.0.5",
+ "@types/file-saver": "^2.0.6",
+ "angular-animations": "^0.11.0",
"bootstrap": "^5.3.1",
+ "charts.css": "^1.1.0",
"eventsource": "^2.0.2",
"file-saver": "^2.0.5",
- "lazysizes": "^5.3.2",
"luxon": "^3.4.3",
"ng-circle-progress": "^1.7.1",
+ "ng-lazyload-image": "^9.1.3",
"ng-select2-component": "^13.0.9",
"ngx-color-picker": "^15.0.0",
- "ngx-extended-pdf-viewer": "^18.0.2",
+ "ngx-extended-pdf-viewer": "^18.1.4",
"ngx-file-drop": "^16.0.0",
"ngx-slider-v2": "^16.0.2",
"ngx-stars": "^1.6.5",
@@ -59,20 +61,20 @@
"zone.js": "^0.13.0"
},
"devDependencies": {
- "@angular-devkit/build-angular": "^16.2.6",
+ "@angular-devkit/build-angular": "^16.2.9",
"@angular-eslint/builder": "^16.2.0",
"@angular-eslint/eslint-plugin": "^16.2.0",
"@angular-eslint/eslint-plugin-template": "^16.2.0",
"@angular-eslint/schematics": "^16.2.0",
"@angular-eslint/template-parser": "^16.2.0",
- "@angular/cli": "^16.2.6",
- "@angular/compiler-cli": "^16.2.9",
- "@types/d3": "^7.4.1",
- "@types/luxon": "^3.3.2",
- "@types/node": "^20.8.6",
+ "@angular/cli": "^16.2.9",
+ "@angular/compiler-cli": "^16.2.12",
+ "@types/d3": "^7.4.2",
+ "@types/luxon": "^3.3.3",
+ "@types/node": "^20.8.10",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
- "eslint": "^8.51.0",
+ "eslint": "^8.52.0",
"jsonminify": "^0.4.2",
"karma-coverage": "~2.2.0",
"ts-node": "~10.9.1",
diff --git a/UI/Web/src/app/_guards/admin.guard.ts b/UI/Web/src/app/_guards/admin.guard.ts
index 9de2cfe44..9ab6dea95 100644
--- a/UI/Web/src/app/_guards/admin.guard.ts
+++ b/UI/Web/src/app/_guards/admin.guard.ts
@@ -22,7 +22,7 @@ export class AdminGuard implements CanActivate {
}
this.toastr.error(this.translocoService.translate('toasts.unauthorized-1'));
- this.router.navigateByUrl('/libraries');
+ this.router.navigateByUrl('/home');
return false;
})
);
diff --git a/UI/Web/src/app/_models/auth/member.ts b/UI/Web/src/app/_models/auth/member.ts
index a9b50d110..5c9002e9f 100644
--- a/UI/Web/src/app/_models/auth/member.ts
+++ b/UI/Web/src/app/_models/auth/member.ts
@@ -6,9 +6,11 @@ export interface Member {
username: string;
email: string;
lastActive: string; // datetime
+ lastActiveUtc: string; // datetime
created: string; // datetime
+ createdUtc: string; // datetime
roles: string[];
libraries: Library[];
ageRestriction: AgeRestriction;
isPending: boolean;
-}
\ No newline at end of file
+}
diff --git a/UI/Web/src/app/pipe/age-rating.pipe.ts b/UI/Web/src/app/_pipes/age-rating.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/age-rating.pipe.ts
rename to UI/Web/src/app/_pipes/age-rating.pipe.ts
diff --git a/UI/Web/src/app/pipe/bytes.pipe.ts b/UI/Web/src/app/_pipes/bytes.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/bytes.pipe.ts
rename to UI/Web/src/app/_pipes/bytes.pipe.ts
diff --git a/UI/Web/src/app/reading-list/_pipes/cbl-conflict-reason.pipe.ts b/UI/Web/src/app/_pipes/cbl-conflict-reason.pipe.ts
similarity index 100%
rename from UI/Web/src/app/reading-list/_pipes/cbl-conflict-reason.pipe.ts
rename to UI/Web/src/app/_pipes/cbl-conflict-reason.pipe.ts
diff --git a/UI/Web/src/app/reading-list/_pipes/cbl-import-result.pipe.ts b/UI/Web/src/app/_pipes/cbl-import-result.pipe.ts
similarity index 100%
rename from UI/Web/src/app/reading-list/_pipes/cbl-import-result.pipe.ts
rename to UI/Web/src/app/_pipes/cbl-import-result.pipe.ts
diff --git a/UI/Web/src/app/pipe/compact-number.pipe.ts b/UI/Web/src/app/_pipes/compact-number.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/compact-number.pipe.ts
rename to UI/Web/src/app/_pipes/compact-number.pipe.ts
diff --git a/UI/Web/src/app/statistics/_pipes/day-of-week.pipe.ts b/UI/Web/src/app/_pipes/day-of-week.pipe.ts
similarity index 82%
rename from UI/Web/src/app/statistics/_pipes/day-of-week.pipe.ts
rename to UI/Web/src/app/_pipes/day-of-week.pipe.ts
index f3387c107..f2fd9c0fe 100644
--- a/UI/Web/src/app/statistics/_pipes/day-of-week.pipe.ts
+++ b/UI/Web/src/app/_pipes/day-of-week.pipe.ts
@@ -1,10 +1,10 @@
-import {inject, Pipe, PipeTransform} from '@angular/core';
+import {Pipe, PipeTransform} from '@angular/core';
import { DayOfWeek } from 'src/app/_services/statistics.service';
-import {translate, TranslocoService} from "@ngneat/transloco";
+import {translate} from "@ngneat/transloco";
@Pipe({
- name: 'dayOfWeek',
- standalone: true
+ name: 'dayOfWeek',
+ standalone: true
})
export class DayOfWeekPipe implements PipeTransform {
diff --git a/UI/Web/src/app/pipe/default-date.pipe.ts b/UI/Web/src/app/_pipes/default-date.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/default-date.pipe.ts
rename to UI/Web/src/app/_pipes/default-date.pipe.ts
diff --git a/UI/Web/src/app/pipe/default-value.pipe.ts b/UI/Web/src/app/_pipes/default-value.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/default-value.pipe.ts
rename to UI/Web/src/app/_pipes/default-value.pipe.ts
diff --git a/UI/Web/src/app/user-settings/_pipes/device-platform.pipe.ts b/UI/Web/src/app/_pipes/device-platform.pipe.ts
similarity index 100%
rename from UI/Web/src/app/user-settings/_pipes/device-platform.pipe.ts
rename to UI/Web/src/app/_pipes/device-platform.pipe.ts
diff --git a/UI/Web/src/app/metadata-filter/_pipes/filter-comparison.pipe.ts b/UI/Web/src/app/_pipes/filter-comparison.pipe.ts
similarity index 100%
rename from UI/Web/src/app/metadata-filter/_pipes/filter-comparison.pipe.ts
rename to UI/Web/src/app/_pipes/filter-comparison.pipe.ts
diff --git a/UI/Web/src/app/metadata-filter/_pipes/filter-field.pipe.ts b/UI/Web/src/app/_pipes/filter-field.pipe.ts
similarity index 100%
rename from UI/Web/src/app/metadata-filter/_pipes/filter-field.pipe.ts
rename to UI/Web/src/app/_pipes/filter-field.pipe.ts
diff --git a/UI/Web/src/app/pipe/filter.pipe.ts b/UI/Web/src/app/_pipes/filter.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/filter.pipe.ts
rename to UI/Web/src/app/_pipes/filter.pipe.ts
diff --git a/UI/Web/src/app/manga-reader/_pipes/fitting-icon.pipe.ts b/UI/Web/src/app/_pipes/fitting-icon.pipe.ts
similarity index 86%
rename from UI/Web/src/app/manga-reader/_pipes/fitting-icon.pipe.ts
rename to UI/Web/src/app/_pipes/fitting-icon.pipe.ts
index f0f2a3152..2123a910c 100644
--- a/UI/Web/src/app/manga-reader/_pipes/fitting-icon.pipe.ts
+++ b/UI/Web/src/app/_pipes/fitting-icon.pipe.ts
@@ -1,5 +1,5 @@
import { Pipe, PipeTransform } from '@angular/core';
-import { FITTING_OPTION } from '../_models/reader-enums';
+import { FITTING_OPTION } from '../manga-reader/_models/reader-enums';
@Pipe({
name: 'fittingIcon',
diff --git a/UI/Web/src/app/manga-reader/_pipes/fullscreen-icon.pipe.ts b/UI/Web/src/app/_pipes/fullscreen-icon.pipe.ts
similarity index 100%
rename from UI/Web/src/app/manga-reader/_pipes/fullscreen-icon.pipe.ts
rename to UI/Web/src/app/_pipes/fullscreen-icon.pipe.ts
diff --git a/UI/Web/src/app/pipe/language-name.pipe.ts b/UI/Web/src/app/_pipes/language-name.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/language-name.pipe.ts
rename to UI/Web/src/app/_pipes/language-name.pipe.ts
diff --git a/UI/Web/src/app/manga-reader/_pipes/layout-mode-icon.pipe.ts b/UI/Web/src/app/_pipes/layout-mode-icon.pipe.ts
similarity index 88%
rename from UI/Web/src/app/manga-reader/_pipes/layout-mode-icon.pipe.ts
rename to UI/Web/src/app/_pipes/layout-mode-icon.pipe.ts
index ce7abdf82..8c9c3951e 100644
--- a/UI/Web/src/app/manga-reader/_pipes/layout-mode-icon.pipe.ts
+++ b/UI/Web/src/app/_pipes/layout-mode-icon.pipe.ts
@@ -1,5 +1,5 @@
import { Pipe, PipeTransform } from '@angular/core';
-import { LayoutMode } from '../_models/layout-mode';
+import { LayoutMode } from '../manga-reader/_models/layout-mode';
@Pipe({
name: 'layoutModeIcon',
diff --git a/UI/Web/src/app/pipe/library-type.pipe.ts b/UI/Web/src/app/_pipes/library-type.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/library-type.pipe.ts
rename to UI/Web/src/app/_pipes/library-type.pipe.ts
diff --git a/UI/Web/src/app/pipe/manga-format-icon.pipe.ts b/UI/Web/src/app/_pipes/manga-format-icon.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/manga-format-icon.pipe.ts
rename to UI/Web/src/app/_pipes/manga-format-icon.pipe.ts
diff --git a/UI/Web/src/app/pipe/manga-format.pipe.ts b/UI/Web/src/app/_pipes/manga-format.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/manga-format.pipe.ts
rename to UI/Web/src/app/_pipes/manga-format.pipe.ts
diff --git a/UI/Web/src/app/pipe/person-role.pipe.ts b/UI/Web/src/app/_pipes/person-role.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/person-role.pipe.ts
rename to UI/Web/src/app/_pipes/person-role.pipe.ts
diff --git a/UI/Web/src/app/pipe/provider-image.pipe.ts b/UI/Web/src/app/_pipes/provider-image.pipe.ts
similarity index 97%
rename from UI/Web/src/app/pipe/provider-image.pipe.ts
rename to UI/Web/src/app/_pipes/provider-image.pipe.ts
index 0697e49e5..75e656651 100644
--- a/UI/Web/src/app/pipe/provider-image.pipe.ts
+++ b/UI/Web/src/app/_pipes/provider-image.pipe.ts
@@ -18,8 +18,6 @@ export class ProviderImagePipe implements PipeTransform {
case ScrobbleProvider.Kavita:
return 'assets/images/logo-32.png';
}
-
- return '';
}
}
diff --git a/UI/Web/src/app/pipe/provider-name.pipe.ts b/UI/Web/src/app/_pipes/provider-name.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/provider-name.pipe.ts
rename to UI/Web/src/app/_pipes/provider-name.pipe.ts
diff --git a/UI/Web/src/app/pipe/publication-status.pipe.ts b/UI/Web/src/app/_pipes/publication-status.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/publication-status.pipe.ts
rename to UI/Web/src/app/_pipes/publication-status.pipe.ts
diff --git a/UI/Web/src/app/manga-reader/_pipes/reader-mode-icon.pipe.ts b/UI/Web/src/app/_pipes/reader-mode-icon.pipe.ts
similarity index 100%
rename from UI/Web/src/app/manga-reader/_pipes/reader-mode-icon.pipe.ts
rename to UI/Web/src/app/_pipes/reader-mode-icon.pipe.ts
diff --git a/UI/Web/src/app/pipe/relationship.pipe.ts b/UI/Web/src/app/_pipes/relationship.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/relationship.pipe.ts
rename to UI/Web/src/app/_pipes/relationship.pipe.ts
diff --git a/UI/Web/src/app/pipe/safe-html.pipe.ts b/UI/Web/src/app/_pipes/safe-html.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/safe-html.pipe.ts
rename to UI/Web/src/app/_pipes/safe-html.pipe.ts
diff --git a/UI/Web/src/app/pipe/safe-style.pipe.ts b/UI/Web/src/app/_pipes/safe-style.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/safe-style.pipe.ts
rename to UI/Web/src/app/_pipes/safe-style.pipe.ts
diff --git a/UI/Web/src/app/pipe/sentence-case.pipe.ts b/UI/Web/src/app/_pipes/sentence-case.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/sentence-case.pipe.ts
rename to UI/Web/src/app/_pipes/sentence-case.pipe.ts
diff --git a/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.ts b/UI/Web/src/app/_pipes/site-theme-provider.pipe.ts
similarity index 100%
rename from UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.ts
rename to UI/Web/src/app/_pipes/site-theme-provider.pipe.ts
diff --git a/UI/Web/src/app/pipe/sort-field.pipe.ts b/UI/Web/src/app/_pipes/sort-field.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/sort-field.pipe.ts
rename to UI/Web/src/app/_pipes/sort-field.pipe.ts
diff --git a/UI/Web/src/app/pipe/stream-name.pipe.ts b/UI/Web/src/app/_pipes/stream-name.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/stream-name.pipe.ts
rename to UI/Web/src/app/_pipes/stream-name.pipe.ts
diff --git a/UI/Web/src/app/pipe/time-ago.pipe.ts b/UI/Web/src/app/_pipes/time-ago.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/time-ago.pipe.ts
rename to UI/Web/src/app/_pipes/time-ago.pipe.ts
diff --git a/UI/Web/src/app/pipe/time-duration.pipe.ts b/UI/Web/src/app/_pipes/time-duration.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/time-duration.pipe.ts
rename to UI/Web/src/app/_pipes/time-duration.pipe.ts
diff --git a/UI/Web/src/app/pipe/utc-to-local-time.pipe.ts b/UI/Web/src/app/_pipes/utc-to-local-time.pipe.ts
similarity index 100%
rename from UI/Web/src/app/pipe/utc-to-local-time.pipe.ts
rename to UI/Web/src/app/_pipes/utc-to-local-time.pipe.ts
diff --git a/UI/Web/src/app/admin/admin-routing.module.ts b/UI/Web/src/app/_routes/admin-routing.module.ts
similarity index 50%
rename from UI/Web/src/app/admin/admin-routing.module.ts
rename to UI/Web/src/app/_routes/admin-routing.module.ts
index 11a2b6c7b..83918ccf2 100644
--- a/UI/Web/src/app/admin/admin-routing.module.ts
+++ b/UI/Web/src/app/_routes/admin-routing.module.ts
@@ -1,9 +1,8 @@
-import { NgModule } from '@angular/core';
-import { Routes, RouterModule } from '@angular/router';
+import { Routes } from '@angular/router';
import { AdminGuard } from '../_guards/admin.guard';
-import { DashboardComponent } from './dashboard/dashboard.component';
+import { DashboardComponent } from '../admin/dashboard/dashboard.component';
-const routes: Routes = [
+export const routes: Routes = [
{path: '**', component: DashboardComponent, pathMatch: 'full', canActivate: [AdminGuard]},
{
path: '',
@@ -15,9 +14,3 @@ const routes: Routes = [
}
];
-
-@NgModule({
- imports: [RouterModule.forChild(routes)],
- exports: [RouterModule]
-})
-export class AdminRoutingModule { }
diff --git a/UI/Web/src/app/_routes/all-series-routing.module.ts b/UI/Web/src/app/_routes/all-series-routing.module.ts
new file mode 100644
index 000000000..eafdb03f5
--- /dev/null
+++ b/UI/Web/src/app/_routes/all-series-routing.module.ts
@@ -0,0 +1,14 @@
+import { Routes } from "@angular/router";
+import { AuthGuard } from "../_guards/auth.guard";
+import { AllSeriesComponent } from "../all-series/_components/all-series/all-series.component";
+
+
+export const routes: Routes = [
+ {path: '**', component: AllSeriesComponent, pathMatch: 'full', canActivate: [AuthGuard]},
+ {
+ path: '',
+ component: AllSeriesComponent,
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ }
+];
diff --git a/UI/Web/src/app/_routes/announcements-routing.module.ts b/UI/Web/src/app/_routes/announcements-routing.module.ts
new file mode 100644
index 000000000..c5715ed74
--- /dev/null
+++ b/UI/Web/src/app/_routes/announcements-routing.module.ts
@@ -0,0 +1,16 @@
+import { Routes } from "@angular/router";
+import { AdminGuard } from "../_guards/admin.guard";
+import { AuthGuard } from "../_guards/auth.guard";
+import { AnnouncementsComponent } from "../announcements/_components/announcements/announcements.component";
+
+export const routes: Routes = [
+ {path: '**', component: AnnouncementsComponent, pathMatch: 'full', canActivate: [AuthGuard, AdminGuard]},
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard, AdminGuard],
+ children: [
+ {path: 'announcements', component: AnnouncementsComponent},
+ ]
+ }
+];
diff --git a/UI/Web/src/app/_routes/book-reader.router.module.ts b/UI/Web/src/app/_routes/book-reader.router.module.ts
new file mode 100644
index 000000000..5083c2d4a
--- /dev/null
+++ b/UI/Web/src/app/_routes/book-reader.router.module.ts
@@ -0,0 +1,10 @@
+import { Routes } from '@angular/router';
+import { BookReaderComponent } from '../book-reader/_components/book-reader/book-reader.component';
+
+export const routes: Routes = [
+ {
+ path: ':chapterId',
+ component: BookReaderComponent,
+ }
+];
+
diff --git a/UI/Web/src/app/_routes/bookmark-routing.module.ts b/UI/Web/src/app/_routes/bookmark-routing.module.ts
new file mode 100644
index 000000000..d303173d8
--- /dev/null
+++ b/UI/Web/src/app/_routes/bookmark-routing.module.ts
@@ -0,0 +1,15 @@
+import { Routes } from "@angular/router";
+import { AuthGuard } from "../_guards/auth.guard";
+import { BookmarksComponent } from "../bookmark/_components/bookmarks/bookmarks.component";
+
+export const routes: Routes = [
+ {path: '**', component: BookmarksComponent, pathMatch: 'full', canActivate: [AuthGuard]},
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ children: [
+ {path: 'bookmarks', component: BookmarksComponent},
+ ]
+ }
+];
diff --git a/UI/Web/src/app/_routes/collections-routing.module.ts b/UI/Web/src/app/_routes/collections-routing.module.ts
new file mode 100644
index 000000000..0227fda89
--- /dev/null
+++ b/UI/Web/src/app/_routes/collections-routing.module.ts
@@ -0,0 +1,17 @@
+import { Routes } from '@angular/router';
+import { AuthGuard } from '../_guards/auth.guard';
+import { AllCollectionsComponent } from '../collections/_components/all-collections/all-collections.component';
+import { CollectionDetailComponent } from '../collections/_components/collection-detail/collection-detail.component';
+
+export const routes: Routes = [
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ children: [
+ {path: '', component: AllCollectionsComponent, pathMatch: 'full'},
+ {path: ':id', component: CollectionDetailComponent},
+ ]
+ }
+];
+
diff --git a/UI/Web/src/app/_routes/dashboard-routing.module.ts b/UI/Web/src/app/_routes/dashboard-routing.module.ts
new file mode 100644
index 000000000..b08722fe0
--- /dev/null
+++ b/UI/Web/src/app/_routes/dashboard-routing.module.ts
@@ -0,0 +1,13 @@
+import { Routes } from '@angular/router';
+import { AuthGuard } from '../_guards/auth.guard';
+import { DashboardComponent } from '../dashboard/_components/dashboard.component';
+
+
+export const routes: Routes = [
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ component: DashboardComponent,
+ }
+];
diff --git a/UI/Web/src/app/_routes/library-detail-routing.module.ts b/UI/Web/src/app/_routes/library-detail-routing.module.ts
new file mode 100644
index 000000000..04cb3c9dd
--- /dev/null
+++ b/UI/Web/src/app/_routes/library-detail-routing.module.ts
@@ -0,0 +1,20 @@
+import { Routes } from '@angular/router';
+import { AuthGuard } from '../_guards/auth.guard';
+import { LibraryAccessGuard } from '../_guards/library-access.guard';
+import { LibraryDetailComponent } from '../library-detail/library-detail.component';
+
+
+export const routes: Routes = [
+ {
+ path: ':libraryId',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard, LibraryAccessGuard],
+ component: LibraryDetailComponent
+ },
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard, LibraryAccessGuard],
+ component: LibraryDetailComponent
+ }
+];
diff --git a/UI/Web/src/app/_routes/manga-reader.router.module.ts b/UI/Web/src/app/_routes/manga-reader.router.module.ts
new file mode 100644
index 000000000..04ff77b3c
--- /dev/null
+++ b/UI/Web/src/app/_routes/manga-reader.router.module.ts
@@ -0,0 +1,15 @@
+import { Routes } from '@angular/router';
+import { MangaReaderComponent } from '../manga-reader/_components/manga-reader/manga-reader.component';
+
+export const routes: Routes = [
+ {
+ path: ':chapterId',
+ component: MangaReaderComponent
+ },
+ {
+ // This will allow the MangaReader to have a list to use for next/prev chapters rather than natural sort order
+ path: ':chapterId/list/:listId',
+ component: MangaReaderComponent
+ }
+];
+
diff --git a/UI/Web/src/app/_routes/pdf-reader.router.module.ts b/UI/Web/src/app/_routes/pdf-reader.router.module.ts
new file mode 100644
index 000000000..a55699280
--- /dev/null
+++ b/UI/Web/src/app/_routes/pdf-reader.router.module.ts
@@ -0,0 +1,9 @@
+import { Routes } from '@angular/router';
+import { PdfReaderComponent } from '../pdf-reader/_components/pdf-reader/pdf-reader.component';
+
+export const routes: Routes = [
+ {
+ path: ':chapterId',
+ component: PdfReaderComponent,
+ }
+];
diff --git a/UI/Web/src/app/_routes/reading-list-routing.module.ts b/UI/Web/src/app/_routes/reading-list-routing.module.ts
new file mode 100644
index 000000000..e53e056c9
--- /dev/null
+++ b/UI/Web/src/app/_routes/reading-list-routing.module.ts
@@ -0,0 +1,18 @@
+import { Routes } from "@angular/router";
+import { AuthGuard } from "../_guards/auth.guard";
+import { ReadingListDetailComponent } from "../reading-list/_components/reading-list-detail/reading-list-detail.component";
+import { ReadingListsComponent } from "../reading-list/_components/reading-lists/reading-lists.component";
+
+
+export const routes: Routes = [
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ children: [
+ {path: '', component: ReadingListsComponent, pathMatch: 'full'},
+ {path: ':id', component: ReadingListDetailComponent, pathMatch: 'full'},
+ ]
+ },
+ {path: '**', component: ReadingListsComponent, pathMatch: 'full', canActivate: [AuthGuard]},
+];
diff --git a/UI/Web/src/app/_routes/registration.router.module.ts b/UI/Web/src/app/_routes/registration.router.module.ts
new file mode 100644
index 000000000..266c43187
--- /dev/null
+++ b/UI/Web/src/app/_routes/registration.router.module.ts
@@ -0,0 +1,43 @@
+import { Routes } from '@angular/router';
+import { UserLoginComponent } from '../registration/user-login/user-login.component';
+import { ConfirmEmailChangeComponent } from '../registration/_components/confirm-email-change/confirm-email-change.component';
+import { ConfirmEmailComponent } from '../registration/_components/confirm-email/confirm-email.component';
+import { ConfirmMigrationEmailComponent } from '../registration/_components/confirm-migration-email/confirm-migration-email.component';
+import { ConfirmResetPasswordComponent } from '../registration/_components/confirm-reset-password/confirm-reset-password.component';
+import { RegisterComponent } from '../registration/_components/register/register.component';
+import { ResetPasswordComponent } from '../registration/_components/reset-password/reset-password.component';
+
+export const routes: Routes = [
+ {
+ path: '',
+ component: UserLoginComponent
+ },
+ {
+ path: 'login',
+ component: UserLoginComponent
+ },
+ {
+ path: 'confirm-email',
+ component: ConfirmEmailComponent,
+ },
+ {
+ path: 'confirm-migration-email',
+ component: ConfirmMigrationEmailComponent,
+ },
+ {
+ path: 'confirm-email-update',
+ component: ConfirmEmailChangeComponent,
+ },
+ {
+ path: 'register',
+ component: RegisterComponent,
+ },
+ {
+ path: 'reset-password',
+ component: ResetPasswordComponent
+ },
+ {
+ path: 'confirm-reset-password',
+ component: ConfirmResetPasswordComponent
+ }
+];
diff --git a/UI/Web/src/app/_routes/user-settings-routing.module.ts b/UI/Web/src/app/_routes/user-settings-routing.module.ts
new file mode 100644
index 000000000..4e02386ac
--- /dev/null
+++ b/UI/Web/src/app/_routes/user-settings-routing.module.ts
@@ -0,0 +1,15 @@
+import { Routes } from '@angular/router';
+import { AuthGuard } from '../_guards/auth.guard';
+import { UserPreferencesComponent } from '../user-settings/user-preferences/user-preferences.component';
+
+export const routes: Routes = [
+ {path: '**', component: UserPreferencesComponent, pathMatch: 'full'},
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ children: [
+ {path: '', component: UserPreferencesComponent, pathMatch: 'full'},
+ ]
+ }
+];
diff --git a/UI/Web/src/app/_routes/want-to-read-routing.module.ts b/UI/Web/src/app/_routes/want-to-read-routing.module.ts
new file mode 100644
index 000000000..ad0d58b05
--- /dev/null
+++ b/UI/Web/src/app/_routes/want-to-read-routing.module.ts
@@ -0,0 +1,15 @@
+import { Routes } from '@angular/router';
+import { AuthGuard } from '../_guards/auth.guard';
+import { WantToReadComponent } from '../want-to-read/_components/want-to-read/want-to-read.component';
+
+export const routes: Routes = [
+ {path: '**', component: WantToReadComponent, pathMatch: 'full'},
+ {
+ path: '',
+ runGuardsAndResolvers: 'always',
+ canActivate: [AuthGuard],
+ children: [
+ {path: '', component: WantToReadComponent, pathMatch: 'full'},
+ ]
+ }
+];
diff --git a/UI/Web/src/app/_services/image.service.ts b/UI/Web/src/app/_services/image.service.ts
index 4aea05982..2c85f2605 100644
--- a/UI/Web/src/app/_services/image.service.ts
+++ b/UI/Web/src/app/_services/image.service.ts
@@ -95,10 +95,6 @@ export class ImageService {
return `${this.baseUrl}image/cover-upload?filename=${encodeURIComponent(filename)}&apiKey=${this.encodedKey}`;
}
- updateErroredImage(event: any) {
- event.target.src = this.placeholderImage;
- }
-
updateErroredWebLinkImage(event: any) {
event.target.src = this.errorWebLinkImage;
}
diff --git a/UI/Web/src/app/_services/statistics.service.ts b/UI/Web/src/app/_services/statistics.service.ts
index ff87fa2c4..f30eb26aa 100644
--- a/UI/Web/src/app/_services/statistics.service.ts
+++ b/UI/Web/src/app/_services/statistics.service.ts
@@ -2,9 +2,9 @@ import { HttpClient } from '@angular/common/http';
import {inject, Injectable} from '@angular/core';
import { environment } from 'src/environments/environment';
import { UserReadStatistics } from '../statistics/_models/user-read-statistics';
-import { PublicationStatusPipe } from '../pipe/publication-status.pipe';
+import { PublicationStatusPipe } from '../_pipes/publication-status.pipe';
import { map } from 'rxjs';
-import { MangaFormatPipe } from '../pipe/manga-format.pipe';
+import { MangaFormatPipe } from '../_pipes/manga-format.pipe';
import { FileExtensionBreakdown } from '../statistics/_models/file-breakdown';
import { TopUserRead } from '../statistics/_models/top-reads';
import { ReadHistoryEvent } from '../statistics/_models/read-history-event';
diff --git a/UI/Web/src/app/_single-module/review-card-modal/review-card-modal.component.ts b/UI/Web/src/app/_single-module/review-card-modal/review-card-modal.component.ts
index 1f0d521fb..24eb32d3f 100644
--- a/UI/Web/src/app/_single-module/review-card-modal/review-card-modal.component.ts
+++ b/UI/Web/src/app/_single-module/review-card-modal/review-card-modal.component.ts
@@ -12,7 +12,7 @@ import {NgbActiveModal} from "@ng-bootstrap/ng-bootstrap";
import {ReactiveFormsModule} from "@angular/forms";
import {UserReview} from "../review-card/user-review";
import {SpoilerComponent} from "../spoiler/spoiler.component";
-import {SafeHtmlPipe} from "../../pipe/safe-html.pipe";
+import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
import {TranslocoDirective} from "@ngneat/transloco";
@Component({
diff --git a/UI/Web/src/app/_single-module/review-card/review-card.component.ts b/UI/Web/src/app/_single-module/review-card/review-card.component.ts
index ff9b03848..2f0d419a9 100644
--- a/UI/Web/src/app/_single-module/review-card/review-card.component.ts
+++ b/UI/Web/src/app/_single-module/review-card/review-card.component.ts
@@ -6,9 +6,9 @@ import {ReviewCardModalComponent} from "../review-card-modal/review-card-modal.c
import {AccountService} from "../../_services/account.service";
import {ReviewSeriesModalComponent} from "../review-series-modal/review-series-modal.component";
import {ReadMoreComponent} from "../../shared/read-more/read-more.component";
-import {DefaultValuePipe} from "../../pipe/default-value.pipe";
+import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {ImageComponent} from "../../shared/image/image.component";
-import {ProviderImagePipe} from "../../pipe/provider-image.pipe";
+import {ProviderImagePipe} from "../../_pipes/provider-image.pipe";
import {TranslocoDirective} from "@ngneat/transloco";
@Component({
diff --git a/UI/Web/src/app/_single-module/series-preview-drawer/series-preview-drawer.component.ts b/UI/Web/src/app/_single-module/series-preview-drawer/series-preview-drawer.component.ts
index 1e6a420b0..b28fdf320 100644
--- a/UI/Web/src/app/_single-module/series-preview-drawer/series-preview-drawer.component.ts
+++ b/UI/Web/src/app/_single-module/series-preview-drawer/series-preview-drawer.component.ts
@@ -6,13 +6,13 @@ import {ExternalSeriesDetail, SeriesStaff} from "../../_models/series-detail/ext
import {SeriesService} from "../../_services/series.service";
import {ImageComponent} from "../../shared/image/image.component";
import {LoadingComponent} from "../../shared/loading/loading.component";
-import {SafeHtmlPipe} from "../../pipe/safe-html.pipe";
+import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
import {A11yClickDirective} from "../../shared/a11y-click.directive";
import {MetadataDetailComponent} from "../../series-detail/_components/metadata-detail/metadata-detail.component";
import {PersonBadgeComponent} from "../../shared/person-badge/person-badge.component";
import {TagBadgeComponent} from "../../shared/tag-badge/tag-badge.component";
import {ImageService} from "../../_services/image.service";
-import {PublicationStatusPipe} from "../../pipe/publication-status.pipe";
+import {PublicationStatusPipe} from "../../_pipes/publication-status.pipe";
import {SeriesMetadata} from "../../_models/metadata/series-metadata";
import {ReadMoreComponent} from "../../shared/read-more/read-more.component";
import {ActionService} from "../../_services/action.service";
diff --git a/UI/Web/src/app/_single-module/spoiler/spoiler.component.ts b/UI/Web/src/app/_single-module/spoiler/spoiler.component.ts
index 4dcbfc82d..6eefdcb70 100644
--- a/UI/Web/src/app/_single-module/spoiler/spoiler.component.ts
+++ b/UI/Web/src/app/_single-module/spoiler/spoiler.component.ts
@@ -8,7 +8,7 @@ import {
ViewEncapsulation
} from '@angular/core';
import {CommonModule} from '@angular/common';
-import {SafeHtmlPipe} from "../../pipe/safe-html.pipe";
+import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
import {TranslocoDirective} from "@ngneat/transloco";
@Component({
diff --git a/UI/Web/src/app/_single-module/user-scrobble-history/user-scrobble-history.component.ts b/UI/Web/src/app/_single-module/user-scrobble-history/user-scrobble-history.component.ts
index 166e00254..0c52dabd9 100644
--- a/UI/Web/src/app/_single-module/user-scrobble-history/user-scrobble-history.component.ts
+++ b/UI/Web/src/app/_single-module/user-scrobble-history/user-scrobble-history.component.ts
@@ -12,9 +12,9 @@ import {PaginatedResult, Pagination} from "../../_models/pagination";
import {SortableHeader, SortEvent} from "../table/_directives/sortable-header.directive";
import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
import {TranslocoModule} from "@ngneat/transloco";
-import {DefaultValuePipe} from "../../pipe/default-value.pipe";
+import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {TranslocoLocaleModule} from "@ngneat/transloco-locale";
-import {UtcToLocalTimePipe} from "../../pipe/utc-to-local-time.pipe";
+import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
@Component({
selector: 'app-user-scrobble-history',
diff --git a/UI/Web/src/app/admin/_modals/reset-password-modal/reset-password-modal.component.ts b/UI/Web/src/app/admin/_modals/reset-password-modal/reset-password-modal.component.ts
index 1df444819..b96619e4f 100644
--- a/UI/Web/src/app/admin/_modals/reset-password-modal/reset-password-modal.component.ts
+++ b/UI/Web/src/app/admin/_modals/reset-password-modal/reset-password-modal.component.ts
@@ -3,7 +3,7 @@ import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angula
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { Member } from 'src/app/_models/auth/member';
import { AccountService } from 'src/app/_services/account.service';
-import { SentenceCasePipe } from '../../../pipe/sentence-case.pipe';
+import { SentenceCasePipe } from '../../../_pipes/sentence-case.pipe';
import { NgIf } from '@angular/common';
import {TranslocoDirective} from "@ngneat/transloco";
diff --git a/UI/Web/src/app/admin/admin.module.ts b/UI/Web/src/app/admin/admin.module.ts
deleted file mode 100644
index 92c2debfe..000000000
--- a/UI/Web/src/app/admin/admin.module.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { AdminRoutingModule } from './admin-routing.module';
-import { DashboardComponent } from './dashboard/dashboard.component';
-import {
- NgbAccordionModule,
- NgbCollapse,
- NgbDropdownModule,
- NgbNavModule,
- NgbTooltipModule,
- NgbTypeaheadModule
-} from '@ng-bootstrap/ng-bootstrap';
-import { ManageLibraryComponent } from './manage-library/manage-library.component';
-import { ManageUsersComponent } from './manage-users/manage-users.component';
-import { LibraryAccessModalComponent } from './_modals/library-access-modal/library-access-modal.component';
-import { DirectoryPickerComponent } from './_modals/directory-picker/directory-picker.component';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { ResetPasswordModalComponent } from './_modals/reset-password-modal/reset-password-modal.component';
-import { ManageSettingsComponent } from './manage-settings/manage-settings.component';
-import { ManageSystemComponent } from './manage-system/manage-system.component';
-import { InviteUserComponent } from './invite-user/invite-user.component';
-import { RoleSelectorComponent } from './role-selector/role-selector.component';
-import { LibrarySelectorComponent } from './library-selector/library-selector.component';
-import { EditUserComponent } from './edit-user/edit-user.component';
-import { UserSettingsModule } from '../user-settings/user-settings.module';
-import { ManageMediaSettingsComponent } from './manage-media-settings/manage-media-settings.component';
-import { ManageEmailSettingsComponent } from './manage-email-settings/manage-email-settings.component';
-import { ManageTasksSettingsComponent } from './manage-tasks-settings/manage-tasks-settings.component';
-import { ManageLogsComponent } from './manage-logs/manage-logs.component';
-import { VirtualScrollerModule } from '@iharbeck/ngx-virtual-scroller';
-
-import { ManageAlertsComponent } from './manage-alerts/manage-alerts.component';
-import {ManageScrobbleErrorsComponent} from "./manage-scrobble-errors/manage-scrobble-errors.component";
-import {DefaultValuePipe} from "../pipe/default-value.pipe";
-import {LibraryTypePipe} from "../pipe/library-type.pipe";
-import {TimeAgoPipe} from "../pipe/time-ago.pipe";
-import {SentenceCasePipe} from "../pipe/sentence-case.pipe";
-import {FilterPipe} from "../pipe/filter.pipe";
-import {TagBadgeComponent} from "../shared/tag-badge/tag-badge.component";
-import {LoadingComponent} from "../shared/loading/loading.component";
-import {
- SideNavCompanionBarComponent
-} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
-import {RouterModule} from "@angular/router";
-import {LicenseComponent} from "./license/license.component";
-
-
-
-
-@NgModule({
- imports: [
- CommonModule,
- AdminRoutingModule,
- ReactiveFormsModule,
- RouterModule,
- FormsModule,
- NgbNavModule,
- NgbTooltipModule,
- NgbTypeaheadModule,
- NgbDropdownModule,
- NgbAccordionModule,
- UserSettingsModule,
- VirtualScrollerModule,
- ManageScrobbleErrorsComponent,
- DefaultValuePipe,
- LibraryTypePipe,
- TimeAgoPipe,
- SentenceCasePipe,
- FilterPipe,
- TagBadgeComponent,
- LoadingComponent,
- SideNavCompanionBarComponent,
- NgbCollapse,
- ManageUsersComponent,
- DashboardComponent,
- ManageLibraryComponent,
- LibraryAccessModalComponent,
- DirectoryPickerComponent,
- ResetPasswordModalComponent,
- ManageSettingsComponent,
- ManageSystemComponent,
- InviteUserComponent,
- RoleSelectorComponent,
- LibrarySelectorComponent,
- EditUserComponent,
- ManageMediaSettingsComponent,
- ManageEmailSettingsComponent,
- ManageTasksSettingsComponent,
- ManageLogsComponent,
- ManageAlertsComponent,
- LicenseComponent
-],
- providers: []
-})
-export class AdminModule { }
diff --git a/UI/Web/src/app/admin/dashboard/dashboard.component.ts b/UI/Web/src/app/admin/dashboard/dashboard.component.ts
index 5dfd2c449..350d3d184 100644
--- a/UI/Web/src/app/admin/dashboard/dashboard.component.ts
+++ b/UI/Web/src/app/admin/dashboard/dashboard.component.ts
@@ -2,7 +2,7 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit} f
import {ActivatedRoute, RouterLink} from '@angular/router';
import {Title} from '@angular/platform-browser';
import {NavService} from '../../_services/nav.service';
-import {SentenceCasePipe} from '../../pipe/sentence-case.pipe';
+import {SentenceCasePipe} from '../../_pipes/sentence-case.pipe';
import {LicenseComponent} from '../license/license.component';
import {ManageTasksSettingsComponent} from '../manage-tasks-settings/manage-tasks-settings.component';
import {ServerStatsComponent} from '../../statistics/_components/server-stats/server-stats.component';
diff --git a/UI/Web/src/app/admin/edit-user/edit-user.component.ts b/UI/Web/src/app/admin/edit-user/edit-user.component.ts
index a9eba589e..a0ed23cc1 100644
--- a/UI/Web/src/app/admin/edit-user/edit-user.component.ts
+++ b/UI/Web/src/app/admin/edit-user/edit-user.component.ts
@@ -5,7 +5,7 @@ import { AgeRestriction } from 'src/app/_models/metadata/age-restriction';
import { Library } from 'src/app/_models/library';
import { Member } from 'src/app/_models/auth/member';
import { AccountService } from 'src/app/_services/account.service';
-import { SentenceCasePipe } from '../../pipe/sentence-case.pipe';
+import { SentenceCasePipe } from '../../_pipes/sentence-case.pipe';
import { RestrictionSelectorComponent } from '../../user-settings/restriction-selector/restriction-selector.component';
import { LibrarySelectorComponent } from '../library-selector/library-selector.component';
import { RoleSelectorComponent } from '../role-selector/role-selector.component';
diff --git a/UI/Web/src/app/admin/invite-user/invite-user.component.html b/UI/Web/src/app/admin/invite-user/invite-user.component.html
index e9b3d6af0..6d4a27607 100644
--- a/UI/Web/src/app/admin/invite-user/invite-user.component.html
+++ b/UI/Web/src/app/admin/invite-user/invite-user.component.html
@@ -47,10 +47,10 @@