mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
Polish Round 1 (#2396)
This commit is contained in:
parent
cf2c43d390
commit
02b002d81a
@ -76,6 +76,17 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.13" />
|
||||
<PackageReference Include="EasyCaching.InMemory" Version="1.9.2" />
|
||||
<PackageReference Include="ExCSS" Version="4.2.4" />
|
||||
<PackageReference Include="Hangfire" Version="1.8.6" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.6" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="0.6.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.13" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.13" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.13" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.13" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.13" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="MimeTypeMapOfficial" Version="1.0.17" />
|
||||
|
@ -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<ActionResult<string>> 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)
|
||||
|
@ -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<LibraryDto>? Libraries { get; init; }
|
||||
public IEnumerable<string>? Roles { get; init; }
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -120,6 +120,7 @@ public static class Seed
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
public static async Task SeedRoles(RoleManager<AppRole> roleManager)
|
||||
{
|
||||
var roles = typeof(PolicyConstants)
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
433
UI/Web/package-lock.json
generated
433
UI/Web/package-lock.json
generated
@ -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": {
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
})
|
||||
);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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',
|
@ -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',
|
@ -18,8 +18,6 @@ export class ProviderImagePipe implements PipeTransform {
|
||||
case ScrobbleProvider.Kavita:
|
||||
return 'assets/images/logo-32.png';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
@ -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 { }
|
14
UI/Web/src/app/_routes/all-series-routing.module.ts
Normal file
14
UI/Web/src/app/_routes/all-series-routing.module.ts
Normal file
@ -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],
|
||||
}
|
||||
];
|
16
UI/Web/src/app/_routes/announcements-routing.module.ts
Normal file
16
UI/Web/src/app/_routes/announcements-routing.module.ts
Normal file
@ -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},
|
||||
]
|
||||
}
|
||||
];
|
10
UI/Web/src/app/_routes/book-reader.router.module.ts
Normal file
10
UI/Web/src/app/_routes/book-reader.router.module.ts
Normal file
@ -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,
|
||||
}
|
||||
];
|
||||
|
15
UI/Web/src/app/_routes/bookmark-routing.module.ts
Normal file
15
UI/Web/src/app/_routes/bookmark-routing.module.ts
Normal file
@ -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},
|
||||
]
|
||||
}
|
||||
];
|
17
UI/Web/src/app/_routes/collections-routing.module.ts
Normal file
17
UI/Web/src/app/_routes/collections-routing.module.ts
Normal file
@ -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},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
13
UI/Web/src/app/_routes/dashboard-routing.module.ts
Normal file
13
UI/Web/src/app/_routes/dashboard-routing.module.ts
Normal file
@ -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,
|
||||
}
|
||||
];
|
20
UI/Web/src/app/_routes/library-detail-routing.module.ts
Normal file
20
UI/Web/src/app/_routes/library-detail-routing.module.ts
Normal file
@ -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
|
||||
}
|
||||
];
|
15
UI/Web/src/app/_routes/manga-reader.router.module.ts
Normal file
15
UI/Web/src/app/_routes/manga-reader.router.module.ts
Normal file
@ -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
|
||||
}
|
||||
];
|
||||
|
9
UI/Web/src/app/_routes/pdf-reader.router.module.ts
Normal file
9
UI/Web/src/app/_routes/pdf-reader.router.module.ts
Normal file
@ -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,
|
||||
}
|
||||
];
|
18
UI/Web/src/app/_routes/reading-list-routing.module.ts
Normal file
18
UI/Web/src/app/_routes/reading-list-routing.module.ts
Normal file
@ -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]},
|
||||
];
|
43
UI/Web/src/app/_routes/registration.router.module.ts
Normal file
43
UI/Web/src/app/_routes/registration.router.module.ts
Normal file
@ -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
|
||||
}
|
||||
];
|
15
UI/Web/src/app/_routes/user-settings-routing.module.ts
Normal file
15
UI/Web/src/app/_routes/user-settings-routing.module.ts
Normal file
@ -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'},
|
||||
]
|
||||
}
|
||||
];
|
15
UI/Web/src/app/_routes/want-to-read-routing.module.ts
Normal file
15
UI/Web/src/app/_routes/want-to-read-routing.module.ts
Normal file
@ -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'},
|
||||
]
|
||||
}
|
||||
];
|
@ -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;
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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";
|
||||
|
@ -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({
|
||||
|
@ -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',
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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 { }
|
@ -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';
|
||||
|
@ -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';
|
||||
|
@ -47,10 +47,10 @@
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" (click)="close()">
|
||||
{{t('cancel')}}
|
||||
<button type="button" class="btn btn-{{invited ? 'primary' : 'secondary'}}" (click)="close()">
|
||||
{{invited ? t('cancel') : t('close')}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" (click)="invite()" [disabled]="isSending || !inviteForm.valid || emailLink !== ''">
|
||||
<button *ngIf="!invited" type="button" class="btn btn-primary" (click)="invite()" [disabled]="isSending || !inviteForm.valid || emailLink !== ''">
|
||||
<span *ngIf="isSending" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
<span>{{isSending ? t('inviting') : t('invite')}}</span>
|
||||
</button>
|
||||
|
@ -13,7 +13,7 @@ import { LibrarySelectorComponent } from '../library-selector/library-selector.c
|
||||
import { RoleSelectorComponent } from '../role-selector/role-selector.component';
|
||||
import { NgIf } from '@angular/common';
|
||||
import {translate, TranslocoDirective} from "@ngneat/transloco";
|
||||
import {SafeHtmlPipe} from "../../pipe/safe-html.pipe";
|
||||
import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
|
||||
|
||||
@Component({
|
||||
selector: 'app-invite-user',
|
||||
|
@ -17,7 +17,7 @@ import { ServerService } from 'src/app/_services/server.service';
|
||||
import { EVENTS, MessageHubService } from 'src/app/_services/message-hub.service';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import { FilterPipe } from '../../pipe/filter.pipe';
|
||||
import { FilterPipe } from '../../_pipes/filter.pipe';
|
||||
import { LoadingComponent } from '../../shared/loading/loading.component';
|
||||
import { NgIf, NgFor } from '@angular/common';
|
||||
import {TranslocoDirective} from "@ngneat/transloco";
|
||||
|
@ -7,7 +7,7 @@ import {ServerSettings} from '../_models/server-settings';
|
||||
import {NgbTooltip} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {NgIf, NgTemplateOutlet} from '@angular/common';
|
||||
import {translate, TranslocoModule, TranslocoService} from "@ngneat/transloco";
|
||||
import {SafeHtmlPipe} from "../../pipe/safe-html.pipe";
|
||||
import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
|
||||
import {ServerService} from "../../_services/server.service";
|
||||
|
||||
@Component({
|
||||
|
@ -17,13 +17,13 @@ import { Library } from 'src/app/_models/library';
|
||||
import { LibraryService } from 'src/app/_services/library.service';
|
||||
import { EVENTS, Message, MessageHubService } from 'src/app/_services/message-hub.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import { SentenceCasePipe } from '../../pipe/sentence-case.pipe';
|
||||
import { TimeAgoPipe } from '../../pipe/time-ago.pipe';
|
||||
import { LibraryTypePipe } from '../../pipe/library-type.pipe';
|
||||
import { SentenceCasePipe } from '../../_pipes/sentence-case.pipe';
|
||||
import { TimeAgoPipe } from '../../_pipes/time-ago.pipe';
|
||||
import { LibraryTypePipe } from '../../_pipes/library-type.pipe';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { NgFor, NgIf } from '@angular/common';
|
||||
import {translate, TranslocoModule} from "@ngneat/transloco";
|
||||
import {DefaultDatePipe} from "../../pipe/default-date.pipe";
|
||||
import {DefaultDatePipe} from "../../_pipes/default-date.pipe";
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-library',
|
||||
|
@ -23,13 +23,13 @@ import {ScrobbleError} from "../../_models/scrobbling/scrobble-error";
|
||||
import {SeriesService} from "../../_services/series.service";
|
||||
import {EditSeriesModalComponent} from "../../cards/_modals/edit-series-modal/edit-series-modal.component";
|
||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {FilterPipe} from "../../pipe/filter.pipe";
|
||||
import {FilterPipe} from "../../_pipes/filter.pipe";
|
||||
import {LoadingComponent} from "../../shared/loading/loading.component";
|
||||
import {TranslocoModule} from "@ngneat/transloco";
|
||||
import {DefaultDatePipe} from "../../pipe/default-date.pipe";
|
||||
import {DefaultValuePipe} from "../../pipe/default-value.pipe";
|
||||
import {DefaultDatePipe} from "../../_pipes/default-date.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-manage-scrobble-errors',
|
||||
|
@ -10,11 +10,11 @@ import {Job} from 'src/app/_models/job/job';
|
||||
import {UpdateNotificationModalComponent} from 'src/app/shared/update-notification/update-notification-modal.component';
|
||||
import {NgbModal, NgbTooltip} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {DownloadService} from 'src/app/shared/_services/download.service';
|
||||
import {DefaultValuePipe} from '../../pipe/default-value.pipe';
|
||||
import {DefaultValuePipe} from '../../_pipes/default-value.pipe';
|
||||
import {AsyncPipe, DatePipe, NgFor, NgIf, NgTemplateOutlet, TitleCasePipe} from '@angular/common';
|
||||
import {TranslocoModule, TranslocoService} from "@ngneat/transloco";
|
||||
import {TranslocoLocaleModule} from "@ngneat/transloco-locale";
|
||||
import {UtcToLocalTimePipe} from "../../pipe/utc-to-local-time.pipe";
|
||||
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
||||
|
||||
interface AdhocTask {
|
||||
name: string;
|
||||
|
@ -11,12 +11,7 @@
|
||||
<li *ngFor="let member of members; let idx = index;" class="list-group-item no-hover">
|
||||
<div>
|
||||
<h4>
|
||||
<span id="member-name--{{idx}}">{{member.username | titlecase}} </span>
|
||||
<span *ngIf="member.username === loggedInUsername">
|
||||
<i class="fas fa-star" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">{{t('you-alt')}}</span>
|
||||
</span>
|
||||
<span class="badge bg-secondary text-dark" *ngIf="member.isPending">{{t('pending-title')}}</span>
|
||||
<span id="member-name--{{idx}}" [ngClass]="{'highlight': member.username === loggedInUsername}">{{member.username | titlecase}}</span>
|
||||
<div class="float-end" *ngIf="canEditMember(member)">
|
||||
<button class="btn btn-danger btn-sm me-2" (click)="deleteUser(member)"
|
||||
placement="top" [ngbTooltip]="t('delete-user-tooltip')" [attr.aria-label]="t('delete-user-alt', {user: member.username | titlecase})">
|
||||
@ -27,24 +22,37 @@
|
||||
<i class="fa fa-pen" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
<button *ngIf="member.isPending" class="btn btn-secondary btn-sm me-2" (click)="resendEmail(member)"
|
||||
placement="top" [ngbTooltip]="t('resend-invite-tooltip')" [attr.aria-label]="t('resend-invite-alt', {user: member.username | titlecase})">{{t('resend')}}</button>
|
||||
<button *ngIf="member.isPending" class="btn btn-secondary btn-sm me-2" (click)="setup(member)"
|
||||
placement="top" [ngbTooltip]="t('setup-user-tooltip')" [attr.aria-label]="t('setup-user-alt', {user: member.username | titlecase})">Setup</button>
|
||||
<ng-container *ngIf="member.isPending">
|
||||
<button class="btn btn-secondary btn-sm me-2" (click)="resendEmail(member)"
|
||||
placement="top" [ngbTooltip]="t('resend-invite-tooltip')" [attr.aria-label]="t('resend-invite-alt', {user: member.username | titlecase})"><i class="fa-solid fa-share-from-square" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-secondary btn-sm" (click)="setup(member)"
|
||||
placement="top" [ngbTooltip]="t('setup-user-tooltip')" [attr.aria-label]="t('setup-user-alt', {user: member.username | titlecase})"><i class="fa-solid fa-sliders" aria-hidden="true"></i></button>
|
||||
</ng-container>
|
||||
<button *ngIf="!member.isPending" class="btn btn-secondary btn-sm" (click)="updatePassword(member)"
|
||||
placement="top" [ngbTooltip]="t('change-password-tooltip')" [attr.aria-label]="t('change-password-alt', {user: member.username | titlecase})"><i class="fa fa-key" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
</h4>
|
||||
<div class="user-info">
|
||||
<div>{{t('last-active-title')}}
|
||||
<span>{{member.lastActive | date: 'short' | defaultDate}} <i class="presence fa fa-circle ms-1" [title]="t('online-now-tooltip')" aria-hidden="true" *ngIf="(messageHub.onlineUsers$ | async)?.includes(member.username)"></i></span>
|
||||
<span class="badge bg-secondary text-dark ms-1 pending-badge" *ngIf="member.isPending; else activeTime">{{t('pending-title')}}</span>
|
||||
<ng-template #activeTime>
|
||||
<span>{{member.lastActiveUtc | utcToLocalTime | defaultDate}} <i class="presence fa fa-circle ms-1" [title]="t('online-now-tooltip')" aria-hidden="true" *ngIf="(messageHub.onlineUsers$ | async)?.includes(member.username)"></i></span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div *ngIf="!hasAdminRole(member) && member.libraries.length > 0">
|
||||
{{t('sharing-title')}}
|
||||
<app-tag-badge *ngFor="let lib of member.libraries" class="col-auto">{{lib.name}}</app-tag-badge>
|
||||
</div>
|
||||
<div *ngIf="!hasAdminRole(member)">{{t('sharing-title')}} {{formatLibraries(member)}}</div>
|
||||
<div class="row g-0">
|
||||
<div>
|
||||
{{t('roles-title')}} <span *ngIf="getRoles(member).length === 0; else showRoles">{{t('none')}}</span>
|
||||
<div *ngIf="getRoles(member) as roles">
|
||||
{{t('roles-title')}} <span *ngIf="roles.length === 0; else showRoles">{{null | defaultValue}}</span>
|
||||
<ng-template #showRoles>
|
||||
<app-tag-badge *ngFor="let role of getRoles(member)" class="col-auto">{{role}}</app-tag-badge>
|
||||
<ng-container *ngIf="hasAdminRole(member); else allRoles">
|
||||
<app-tag-badge class="col-auto">Admin</app-tag-badge>
|
||||
</ng-container>
|
||||
<ng-template #allRoles>
|
||||
<app-tag-badge *ngFor="let role of roles" class="col-auto">{{role}}</app-tag-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,3 +6,11 @@
|
||||
.user-info > div {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.pending-badge {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
@ -13,9 +13,12 @@ import {EditUserComponent} from '../edit-user/edit-user.component';
|
||||
import {ServerService} from 'src/app/_services/server.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {TagBadgeComponent} from '../../shared/tag-badge/tag-badge.component';
|
||||
import {AsyncPipe, DatePipe, NgFor, NgIf, TitleCasePipe} from '@angular/common';
|
||||
import {TranslocoModule, TranslocoService} from "@ngneat/transloco";
|
||||
import {DefaultDatePipe} from "../../pipe/default-date.pipe";
|
||||
import {AsyncPipe, DatePipe, NgClass, NgFor, NgIf, TitleCasePipe} from '@angular/common';
|
||||
import {translate, TranslocoModule, TranslocoService} from "@ngneat/transloco";
|
||||
import {DefaultDatePipe} from "../../_pipes/default-date.pipe";
|
||||
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
||||
import {ReadMoreComponent} from "../../shared/read-more/read-more.component";
|
||||
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-users',
|
||||
@ -23,7 +26,7 @@ import {DefaultDatePipe} from "../../pipe/default-date.pipe";
|
||||
styleUrls: ['./manage-users.component.scss'],
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [NgFor, NgIf, NgbTooltip, TagBadgeComponent, AsyncPipe, TitleCasePipe, DatePipe, TranslocoModule, DefaultDatePipe]
|
||||
imports: [NgFor, NgIf, NgbTooltip, TagBadgeComponent, AsyncPipe, TitleCasePipe, DatePipe, TranslocoModule, DefaultDatePipe, NgClass, DefaultValuePipe, ReadMoreComponent, UtcToLocalTimePipe]
|
||||
})
|
||||
export class ManageUsersComponent implements OnInit {
|
||||
|
||||
@ -31,24 +34,24 @@ export class ManageUsersComponent implements OnInit {
|
||||
loggedInUsername = '';
|
||||
loadingMembers = false;
|
||||
|
||||
translocoService = inject(TranslocoService);
|
||||
cdRef = inject(ChangeDetectorRef);
|
||||
private readonly translocoService = inject(TranslocoService);
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
private readonly memberService = inject(MemberService);
|
||||
private readonly accountService = inject(AccountService);
|
||||
private readonly modalService = inject(NgbModal);
|
||||
private readonly toastr = inject(ToastrService);
|
||||
private readonly confirmService = inject(ConfirmService);
|
||||
public readonly messageHub = inject(MessageHubService);
|
||||
private readonly serverService = inject(ServerService);
|
||||
private readonly router = inject(Router);
|
||||
|
||||
constructor(private memberService: MemberService,
|
||||
private accountService: AccountService,
|
||||
private modalService: NgbModal,
|
||||
private toastr: ToastrService,
|
||||
private confirmService: ConfirmService,
|
||||
public messageHub: MessageHubService,
|
||||
private serverService: ServerService,
|
||||
private router: Router) {
|
||||
constructor() {
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe((user) => {
|
||||
if (user) {
|
||||
this.loggedInUsername = user.username;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -136,7 +139,7 @@ export class ManageUsersComponent implements OnInit {
|
||||
|
||||
formatLibraries(member: Member) {
|
||||
if (member.libraries.length === 0) {
|
||||
return this.translocoService.translate('manage-users.none');
|
||||
return translate('manage-users.none');
|
||||
}
|
||||
|
||||
return member.libraries.map(item => item.name).join(', ');
|
||||
|
@ -35,11 +35,11 @@ import {SeriesFilterV2} from "../../../_models/metadata/v2/series-filter-v2";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-all-series',
|
||||
templateUrl: './all-series.component.html',
|
||||
styleUrls: ['./all-series.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
selector: 'app-all-series',
|
||||
templateUrl: './all-series.component.html',
|
||||
styleUrls: ['./all-series.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [SideNavCompanionBarComponent, NgIf, BulkOperationsComponent, CardDetailLayoutComponent, SeriesCardComponent, DecimalPipe, TranslocoDirective]
|
||||
})
|
||||
export class AllSeriesComponent implements OnInit {
|
||||
|
@ -1,22 +0,0 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { Routes, RouterModule } from "@angular/router";
|
||||
import { AuthGuard } from "../_guards/auth.guard";
|
||||
import { AllSeriesComponent } from "./_components/all-series/all-series.component";
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '**', component: AllSeriesComponent, pathMatch: 'full', canActivate: [AuthGuard]},
|
||||
{
|
||||
path: '',
|
||||
component: AllSeriesComponent,
|
||||
runGuardsAndResolvers: 'always',
|
||||
canActivate: [AuthGuard],
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AllSeriesRoutingModule { }
|
@ -1,25 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AllSeriesRoutingModule } from './all-series-routing.module';
|
||||
import { AllSeriesComponent } from './_components/all-series/all-series.component';
|
||||
import {SeriesCardComponent} from "../cards/series-card/series-card.component";
|
||||
import {BulkOperationsComponent} from "../cards/bulk-operations/bulk-operations.component";
|
||||
import {CardDetailLayoutComponent} from "../cards/card-detail-layout/card-detail-layout.component";
|
||||
import {
|
||||
SideNavCompanionBarComponent
|
||||
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
AllSeriesRoutingModule,
|
||||
SeriesCardComponent,
|
||||
BulkOperationsComponent,
|
||||
CardDetailLayoutComponent,
|
||||
SideNavCompanionBarComponent,
|
||||
AllSeriesComponent,
|
||||
]
|
||||
})
|
||||
export class AllSeriesModule { }
|
@ -1,24 +0,0 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { Routes, RouterModule } from "@angular/router";
|
||||
import { AdminGuard } from "../_guards/admin.guard";
|
||||
import { AuthGuard } from "../_guards/auth.guard";
|
||||
import { AnnouncementsComponent } from "./_components/announcements/announcements.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '**', component: AnnouncementsComponent, pathMatch: 'full', canActivate: [AuthGuard, AdminGuard]},
|
||||
{
|
||||
path: '',
|
||||
runGuardsAndResolvers: 'always',
|
||||
canActivate: [AuthGuard, AdminGuard],
|
||||
children: [
|
||||
{path: 'announcments', component: AnnouncementsComponent},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AnnouncementsRoutingModule { }
|
@ -1,25 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AnnouncementsComponent } from './_components/announcements/announcements.component';
|
||||
import { ChangelogComponent } from './_components/changelog/changelog.component';
|
||||
import { AnnouncementsRoutingModule } from './announcements-routing.module';
|
||||
import {ReadMoreComponent} from "../shared/read-more/read-more.component";
|
||||
import {LoadingComponent} from "../shared/loading/loading.component";
|
||||
import {
|
||||
SideNavCompanionBarComponent
|
||||
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
AnnouncementsRoutingModule,
|
||||
ReadMoreComponent,
|
||||
LoadingComponent,
|
||||
SideNavCompanionBarComponent,
|
||||
AnnouncementsComponent,
|
||||
ChangelogComponent
|
||||
]
|
||||
})
|
||||
export class AnnouncementsModule { }
|
@ -8,50 +8,48 @@ const routes: Routes = [
|
||||
{
|
||||
path: 'admin',
|
||||
canActivate: [AdminGuard],
|
||||
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
|
||||
},
|
||||
{
|
||||
path: 'collections',
|
||||
canActivate: [AuthGuard],
|
||||
loadChildren: () => import('./collections/collections.module').then(m => m.CollectionsModule)
|
||||
loadChildren: () => import('./_routes/admin-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'preferences',
|
||||
canActivate: [AuthGuard],
|
||||
loadChildren: () => import('./user-settings/user-settings.module').then(m => m.UserSettingsModule)
|
||||
loadChildren: () => import('./_routes/user-settings-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'collections',
|
||||
loadChildren: () => import('./_routes/collections-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'lists',
|
||||
canActivate: [AuthGuard],
|
||||
loadChildren: () => import('./reading-list/reading-list.module').then(m => m.ReadingListModule)
|
||||
loadChildren: () => import('./_routes/reading-list-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'registration',
|
||||
loadChildren: () => import('../app/registration/registration.module').then(m => m.RegistrationModule)
|
||||
loadChildren: () => import('./_routes/registration.router.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
loadChildren: () => import('./_routes/registration.router.module').then(m => m.routes) // TODO: Refactor so we just use /registration/login going forward
|
||||
},
|
||||
{
|
||||
path: 'announcements',
|
||||
loadChildren: () => import('../app/announcements/announcements.module').then(m => m.AnnouncementsModule)
|
||||
loadChildren: () => import('./_routes/announcements-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'bookmarks',
|
||||
loadChildren: () => import('../app/bookmark/bookmark.module').then(m => m.BookmarkModule)
|
||||
loadChildren: () => import('./_routes/bookmark-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'all-series',
|
||||
loadChildren: () => import('../app/all-series/all-series.module').then(m => m.AllSeriesModule)
|
||||
},
|
||||
{
|
||||
path: 'libraries',
|
||||
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
|
||||
},
|
||||
{
|
||||
path: 'libraries',
|
||||
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
|
||||
loadChildren: () => import('./_routes/all-series-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'want-to-read',
|
||||
loadChildren: () => import('../app/want-to-read/want-to-read.module').then(m => m.WantToReadModule)
|
||||
loadChildren: () => import('./_routes/want-to-read-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
loadChildren: () => import('./_routes/dashboard-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'library',
|
||||
@ -61,30 +59,30 @@ const routes: Routes = [
|
||||
{
|
||||
path: ':libraryId',
|
||||
pathMatch: 'full',
|
||||
loadChildren: () => import('../app/library-detail/library-detail.module').then(m => m.LibraryDetailModule)
|
||||
loadChildren: () => import('./_routes/library-detail-routing.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: ':libraryId/series/:seriesId',
|
||||
pathMatch: 'full',
|
||||
loadChildren: () => import('../app/series-detail/series-detail.module').then(m => m.SeriesDetailModule)
|
||||
loadComponent: () => import('../app/series-detail/_components/series-detail/series-detail.component').then(c => c.SeriesDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':libraryId/series/:seriesId/manga',
|
||||
loadChildren: () => import('../app/manga-reader/manga-reader.module').then(m => m.MangaReaderModule)
|
||||
loadChildren: () => import('./_routes/manga-reader.router.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: ':libraryId/series/:seriesId/book',
|
||||
loadChildren: () => import('../app/book-reader/book-reader.module').then(m => m.BookReaderModule)
|
||||
loadChildren: () => import('./_routes/book-reader.router.module').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: ':libraryId/series/:seriesId/pdf',
|
||||
loadChildren: () => import('../app/pdf-reader/pdf-reader.module').then(m => m.PdfReaderModule)
|
||||
loadChildren: () => import('./_routes/pdf-reader.router.module').then(m => m.routes)
|
||||
},
|
||||
]
|
||||
},
|
||||
{path: 'login', loadChildren: () => import('../app/registration/registration.module').then(m => m.RegistrationModule)},
|
||||
{path: '**', pathMatch: 'full', redirectTo: 'libraries'},
|
||||
{path: '**', pathMatch: 'prefix', redirectTo: 'libraries'},
|
||||
{path: '**', pathMatch: 'full', redirectTo: 'home'},
|
||||
{path: 'libraries', pathMatch: 'full', redirectTo: 'home'},
|
||||
{path: '**', pathMatch: 'prefix', redirectTo: 'home'},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -2,7 +2,7 @@ import {
|
||||
ChangeDetectionStrategy, ChangeDetectorRef,
|
||||
Component,
|
||||
DestroyRef,
|
||||
ElementRef, EventEmitter,
|
||||
ElementRef, EventEmitter, HostListener,
|
||||
inject,
|
||||
Input,
|
||||
OnInit, Output,
|
||||
@ -15,6 +15,7 @@ import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/
|
||||
import {ReaderService} from "../../../_services/reader.service";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
import {translate, TranslocoDirective} from "@ngneat/transloco";
|
||||
import {KEY_CODES} from "../../../shared/_services/utility.service";
|
||||
|
||||
enum BookLineOverlayMode {
|
||||
None = 0,
|
||||
@ -52,6 +53,17 @@ export class BookLineOverlayComponent implements OnInit {
|
||||
get BookLineOverlayMode() { return BookLineOverlayMode; }
|
||||
constructor(private elementRef: ElementRef, private toastr: ToastrService) {}
|
||||
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
handleKeyPress(event: KeyboardEvent) {
|
||||
if (event.key === KEY_CODES.ESC_KEY) {
|
||||
this.reset();
|
||||
this.cdRef.markForCheck();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
if (this.parent) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
<div class="container-flex {{darkMode ? 'dark-mode' : ''}} reader-container {{ColumnLayout}} {{WritingStyleClass}}" tabindex="0" #reader>
|
||||
<div class="container-flex {{darkMode ? 'dark-mode' : ''}} reader-container {{ColumnLayout}} {{WritingStyleClass}}"
|
||||
tabindex="0" #reader (click)="handleContainerClick($event)" [ngClass]="{'pointer' : cursorIsPointer}">
|
||||
<ng-container *transloco="let t; read: 'book-reader'">
|
||||
<div class="fixed-top" #stickyTop>
|
||||
<a class="visually-hidden-focusable focus-visible" href="javascript:void(0);" (click)="moveFocus()">{{t('skip-header')}}</a>
|
||||
@ -98,7 +99,8 @@
|
||||
</app-drawer>
|
||||
</div>
|
||||
|
||||
<div #readingSection class="reading-section {{ColumnLayout}} {{WritingStyleClass}}" [ngStyle]="{'width': PageWidthForPagination}" [ngClass]="{'immersive' : immersiveMode || !actionBarVisible}" [@isLoading]="isLoading">
|
||||
<div #readingSection class="reading-section {{ColumnLayout}} {{WritingStyleClass}}" [ngStyle]="{'width': PageWidthForPagination}"
|
||||
[ngClass]="{'immersive' : immersiveMode || !actionBarVisible}" [@isLoading]="isLoading" (click)="handleReaderClick($event)">
|
||||
|
||||
<ng-container *ngIf="clickToPaginate">
|
||||
<div class="left {{clickOverlayClass('left')}} no-pointer-events no-observe"
|
||||
@ -111,9 +113,8 @@
|
||||
[ngStyle]="{height: PageHeightForPagination}"></div>
|
||||
</ng-container>
|
||||
<div #bookContainer class="book-container {{WritingStyleClass}}"
|
||||
[ngClass]="{'immersive' : immersiveMode, 'pointer' : cursorIsPointer}"
|
||||
(click)="handleReaderClick($event)"
|
||||
(mousedown)="mouseDown($event)">
|
||||
[ngClass]="{'immersive' : immersiveMode}"
|
||||
(mousedown)="mouseDown($event)" >
|
||||
|
||||
<div #readingHtml class="book-content {{ColumnLayout}} {{WritingStyleClass}}"
|
||||
[ngStyle]="{'max-height': ColumnHeight, 'max-width': VerticalBookContentWidth, 'width': VerticalBookContentWidth, 'column-width': ColumnWidth}"
|
||||
|
@ -184,7 +184,7 @@ $action-bar-height: 38px;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
// background-color: purple !important;
|
||||
//background-color: purple !important;
|
||||
|
||||
&.column-layout-1 {
|
||||
height: calc((var(--vh, 1vh) * 100) - $action-bar-height);
|
||||
@ -198,10 +198,10 @@ $action-bar-height: 38px;
|
||||
// Fixes an issue where chrome will cut of margins, doesn't seem to affect other browsers
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.book-content {
|
||||
@ -325,6 +325,10 @@ $action-bar-height: 38px;
|
||||
}
|
||||
|
||||
$pagination-color: transparent;
|
||||
$pagination-opacity: 0;
|
||||
|
||||
//$pagination-color: red;
|
||||
//$pagination-opacity: 0.7;
|
||||
|
||||
|
||||
.right {
|
||||
@ -356,9 +360,9 @@ $pagination-color: transparent;
|
||||
width: 18%;
|
||||
z-index: 3;
|
||||
background: $pagination-color;
|
||||
opacity: $pagination-opacity;
|
||||
border-color: transparent;
|
||||
border: none !important;
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
|
||||
&.immersive {
|
||||
@ -376,11 +380,12 @@ $pagination-color: transparent;
|
||||
top: $action-bar-height;
|
||||
width: 20vw;
|
||||
background: $pagination-color;
|
||||
opacity: $pagination-opacity;
|
||||
border-color: transparent;
|
||||
border: none !important;
|
||||
z-index: 3;
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
height: 100vw;
|
||||
|
||||
&.immersive {
|
||||
top: 0px;
|
||||
|
@ -523,7 +523,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
handleScrollEvent() {
|
||||
// Highlight the current chapter we are on
|
||||
if (Object.keys(this.pageAnchors).length !== 0) {
|
||||
// get the height of the document so we can capture markers that are halfway on the document viewport
|
||||
// get the height of the document, so we can capture markers that are halfway on the document viewport
|
||||
const verticalOffset = this.reader.nativeElement?.scrollTop || (this.scrollService.scrollPosition + (this.document.body.offsetHeight / 2));
|
||||
|
||||
const alreadyReached = Object.values(this.pageAnchors).filter((i: number) => i <= verticalOffset);
|
||||
@ -576,7 +576,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const chapterId = this.route.snapshot.paramMap.get('chapterId');
|
||||
|
||||
if (libraryId === null || seriesId === null || chapterId === null) {
|
||||
this.router.navigateByUrl('/libraries');
|
||||
this.router.navigateByUrl('/home');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -618,7 +618,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
|
||||
|
||||
this.bookService.getBookInfo(this.chapterId).subscribe(info => {
|
||||
if (this.readingListMode && info.seriesFormat !== MangaFormat.EPUB) {
|
||||
// Redirect to the manga reader.
|
||||
@ -711,6 +710,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
} else if (event.key === KEY_CODES.LEFT_ARROW) {
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD);
|
||||
} else if (event.key === KEY_CODES.ESC_KEY) {
|
||||
const isHighlighting = window.getSelection()?.toString() != '';
|
||||
if (isHighlighting) return;
|
||||
this.closeReader();
|
||||
} else if (event.key === KEY_CODES.SPACE) {
|
||||
this.toggleDrawer();
|
||||
@ -1590,12 +1591,14 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
private isCursorOverLeftPaginationArea(event: MouseEvent): boolean {
|
||||
const leftPaginationAreaEnd = window.innerWidth * 0.2;
|
||||
//console.log('user clicked on ', event.clientX, ' and left pagination ends on ', leftPaginationAreaEnd);
|
||||
return event.clientX <= leftPaginationAreaEnd;
|
||||
}
|
||||
|
||||
private isCursorOverRightPaginationArea(event: MouseEvent): boolean {
|
||||
const rightPaginationAreaStart = event.clientX >= window.innerWidth * 0.8;
|
||||
return rightPaginationAreaStart;
|
||||
const rightPaginationAreaStart = window.innerWidth * 0.8;
|
||||
//console.log('user clicked on ', event.clientX, ' and right pagination starts at ', rightPaginationAreaStart);
|
||||
return event.clientX >= rightPaginationAreaStart;
|
||||
}
|
||||
|
||||
private isCursorOverPaginationArea(event: MouseEvent): boolean {
|
||||
@ -1611,25 +1614,39 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
// Responsibile for handling pagination only
|
||||
handleContainerClick(event: MouseEvent) {
|
||||
|
||||
//if (event.target)
|
||||
console.log('target: ', event.target);
|
||||
if (['action-bar'].some(className => (event.target as Element).classList.contains(className))) {
|
||||
console.log('exiting early')
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isCursorOverLeftPaginationArea(event)) {
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD);
|
||||
} else if (this.isCursorOverRightPaginationArea(event)) {
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS)
|
||||
} else {
|
||||
this.toggleMenu(event);
|
||||
}
|
||||
}
|
||||
|
||||
handleReaderClick(event: MouseEvent) {
|
||||
if (!this.clickToPaginate) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.toggleMenu(event);
|
||||
return;
|
||||
}
|
||||
|
||||
const isHighlighting = window.getSelection()?.toString() != '';
|
||||
|
||||
if (isHighlighting) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isCursorOverLeftPaginationArea(event)) {
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.BACKWARDS : PAGING_DIRECTION.FORWARD);
|
||||
} else if (this.isCursorOverRightPaginationArea(event)) {
|
||||
this.movePage(this.readingDirection === ReadingDirection.LeftToRight ? PAGING_DIRECTION.FORWARD : PAGING_DIRECTION.BACKWARDS)
|
||||
} else {
|
||||
this.toggleMenu(event);
|
||||
}
|
||||
}
|
||||
|
||||
toggleMenu(event: MouseEvent) {
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
@Pipe({
|
||||
name: 'safeStyle',
|
||||
standalone: true
|
||||
})
|
||||
export class SafeStylePipe implements PipeTransform {
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) {}
|
||||
|
||||
transform(value: string): unknown {
|
||||
return this.sanitizer.bypassSecurityTrustStyle(value);
|
||||
}
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BookReaderComponent } from './_components/book-reader/book-reader.component';
|
||||
import { BookReaderRoutingModule } from './book-reader.router.module';
|
||||
import { SafeStylePipe } from './_pipes/safe-style.pipe';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { NgbAccordionModule, NgbNavModule, NgbProgressbarModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ReaderSettingsComponent } from './_components/reader-settings/reader-settings.component';
|
||||
import { TableOfContentsComponent } from './_components/table-of-contents/table-of-contents.component';
|
||||
import {DrawerComponent} from "../shared/drawer/drawer.component";
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
BookReaderRoutingModule,
|
||||
ReactiveFormsModule,
|
||||
NgbProgressbarModule,
|
||||
NgbTooltipModule,
|
||||
NgbTooltipModule,
|
||||
NgbAccordionModule,
|
||||
NgbNavModule,
|
||||
DrawerComponent,
|
||||
BookReaderComponent, SafeStylePipe, TableOfContentsComponent, ReaderSettingsComponent,
|
||||
], exports: [
|
||||
BookReaderComponent,
|
||||
SafeStylePipe
|
||||
]
|
||||
})
|
||||
export class BookReaderModule { }
|
@ -1,17 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { BookReaderComponent } from './_components/book-reader/book-reader.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: ':chapterId',
|
||||
component: BookReaderComponent,
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes), ],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class BookReaderRoutingModule { }
|
@ -66,7 +66,7 @@ export class BookmarksComponent implements OnInit {
|
||||
|
||||
private readonly translocoService = inject(TranslocoService);
|
||||
|
||||
constructor(private readerService: ReaderService, private seriesService: SeriesService,
|
||||
constructor(private readerService: ReaderService,
|
||||
private downloadService: DownloadService, private toastr: ToastrService,
|
||||
private confirmService: ConfirmService, public bulkSelectionService: BulkSelectionService,
|
||||
public imageService: ImageService, private actionFactoryService: ActionFactoryService,
|
||||
|
@ -1,23 +0,0 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { Routes, RouterModule } from "@angular/router";
|
||||
import { AuthGuard } from "../_guards/auth.guard";
|
||||
import { BookmarksComponent } from "./_components/bookmarks/bookmarks.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '**', component: BookmarksComponent, pathMatch: 'full', canActivate: [AuthGuard]},
|
||||
{
|
||||
path: '',
|
||||
runGuardsAndResolvers: 'always',
|
||||
canActivate: [AuthGuard],
|
||||
children: [
|
||||
{path: 'bookmarks', component: BookmarksComponent},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class BookmarkRoutingModule { }
|
@ -1,25 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BookmarkRoutingModule } from './bookmark-routing.module';
|
||||
import { BookmarksComponent } from './_components/bookmarks/bookmarks.component';
|
||||
import {BulkOperationsComponent} from "../cards/bulk-operations/bulk-operations.component";
|
||||
import {CardDetailLayoutComponent} from "../cards/card-detail-layout/card-detail-layout.component";
|
||||
import {
|
||||
SideNavCompanionBarComponent
|
||||
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
|
||||
import {CardItemComponent} from "../cards/card-item/card-item.component";
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
BookmarkRoutingModule,
|
||||
BulkOperationsComponent,
|
||||
CardDetailLayoutComponent,
|
||||
SideNavCompanionBarComponent,
|
||||
CardItemComponent,
|
||||
BookmarksComponent
|
||||
]
|
||||
})
|
||||
export class BookmarkModule { }
|
@ -17,7 +17,7 @@ import { CollectionTag } from 'src/app/_models/collection-tag';
|
||||
import { ReadingList } from 'src/app/_models/reading-list';
|
||||
import { CollectionTagService } from 'src/app/_services/collection-tag.service';
|
||||
import {CommonModule} from "@angular/common";
|
||||
import {FilterPipe} from "../../../pipe/filter.pipe";
|
||||
import {FilterPipe} from "../../../_pipes/filter.pipe";
|
||||
import {translate, TranslocoDirective, TranslocoService} from "@ngneat/transloco";
|
||||
|
||||
@Component({
|
||||
|
@ -42,18 +42,18 @@ import {CommonModule} from "@angular/common";
|
||||
import {TypeaheadComponent} from "../../../typeahead/_components/typeahead.component";
|
||||
import {CoverImageChooserComponent} from "../../cover-image-chooser/cover-image-chooser.component";
|
||||
import {EditSeriesRelationComponent} from "../../edit-series-relation/edit-series-relation.component";
|
||||
import {SentenceCasePipe} from "../../../pipe/sentence-case.pipe";
|
||||
import {MangaFormatPipe} from "../../../pipe/manga-format.pipe";
|
||||
import {DefaultDatePipe} from "../../../pipe/default-date.pipe";
|
||||
import {TimeAgoPipe} from "../../../pipe/time-ago.pipe";
|
||||
import {SentenceCasePipe} from "../../../_pipes/sentence-case.pipe";
|
||||
import {MangaFormatPipe} from "../../../_pipes/manga-format.pipe";
|
||||
import {DefaultDatePipe} from "../../../_pipes/default-date.pipe";
|
||||
import {TimeAgoPipe} from "../../../_pipes/time-ago.pipe";
|
||||
import {TagBadgeComponent} from "../../../shared/tag-badge/tag-badge.component";
|
||||
import {PublicationStatusPipe} from "../../../pipe/publication-status.pipe";
|
||||
import {BytesPipe} from "../../../pipe/bytes.pipe";
|
||||
import {PublicationStatusPipe} from "../../../_pipes/publication-status.pipe";
|
||||
import {BytesPipe} from "../../../_pipes/bytes.pipe";
|
||||
import {ImageComponent} from "../../../shared/image/image.component";
|
||||
import {DefaultValuePipe} from "../../../pipe/default-value.pipe";
|
||||
import {DefaultValuePipe} from "../../../_pipes/default-value.pipe";
|
||||
import {TranslocoModule} from "@ngneat/transloco";
|
||||
import {TranslocoDatePipe} from "@ngneat/transloco-locale";
|
||||
import {UtcToLocalTimePipe} from "../../../pipe/utc-to-local-time.pipe";
|
||||
import {UtcToLocalTimePipe} from "../../../_pipes/utc-to-local-time.pipe";
|
||||
|
||||
enum TabID {
|
||||
General = 0,
|
||||
|
@ -43,8 +43,8 @@ import {ReadMoreComponent} from "../../shared/read-more/read-more.component";
|
||||
import {EntityInfoCardsComponent} from "../entity-info-cards/entity-info-cards.component";
|
||||
import {CoverImageChooserComponent} from "../cover-image-chooser/cover-image-chooser.component";
|
||||
import {ChapterMetadataDetailComponent} from "../chapter-metadata-detail/chapter-metadata-detail.component";
|
||||
import {DefaultDatePipe} from "../../pipe/default-date.pipe";
|
||||
import {BytesPipe} from "../../pipe/bytes.pipe";
|
||||
import {DefaultDatePipe} from "../../_pipes/default-date.pipe";
|
||||
import {BytesPipe} from "../../_pipes/bytes.pipe";
|
||||
import {BadgeExpanderComponent} from "../../shared/badge-expander/badge-expander.component";
|
||||
import {TagBadgeComponent} from "../../shared/tag-badge/tag-badge.component";
|
||||
import {PersonBadgeComponent} from "../../shared/person-badge/person-badge.component";
|
||||
|
@ -8,11 +8,14 @@
|
||||
</span>
|
||||
<span *ngIf="header !== undefined && header.length > 0">
|
||||
{{header}}
|
||||
<span class="badge bg-primary rounded-pill" [attr.aria-label]="t('total-items', {count: pagination.totalItems})" *ngIf="pagination !== undefined">{{pagination.totalItems}}</span>
|
||||
<span class="badge bg-primary rounded-pill"
|
||||
[attr.aria-label]="t('total-items', {count: pagination.totalItems})"
|
||||
*ngIf="pagination !== undefined">{{pagination.totalItems}}</span>
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-metadata-filter [filterSettings]="filterSettings" [filterOpen]="filterOpen" (applyFilter)="applyMetadataFilter($event)"></app-metadata-filter>
|
||||
<div class="viewport-container" [ngClass]="{'empty': items.length === 0 && !isLoading}">
|
||||
<div class="content-container">
|
||||
@ -20,9 +23,13 @@
|
||||
<p *ngIf="items.length === 0 && !isLoading">
|
||||
<ng-container [ngTemplateOutlet]="noDataTemplate"></ng-container>
|
||||
</p>
|
||||
<virtual-scroller [ngClass]="{'empty': items.length === 0 && !isLoading}" #scroll [items]="items" [bufferAmount]="1" [parentScroll]="parentScroll">
|
||||
|
||||
<virtual-scroller [ngClass]="{'empty': items.length === 0 && !isLoading}" #scroll [items]="items" [bufferAmount]="bufferAmount" [parentScroll]="parentScroll" >
|
||||
<div class="grid row g-0" #container>
|
||||
<div class="card col-auto mt-2 mb-2" (click)="tryToSaveJumpKey(item)" *ngFor="let item of scroll.viewPortItems; trackBy:trackByIdentity; index as i" id="jumpbar-index--{{i}}" [attr.jumpbar-index]="i">
|
||||
<div class="card col-auto mt-2 mb-2"
|
||||
(click)="tryToSaveJumpKey(item)"
|
||||
*ngFor="let item of scroll.viewPortItems; trackBy:trackByIdentity; index as i" id="jumpbar-index--{{i}}"
|
||||
[attr.jumpbar-index]="i">
|
||||
<ng-container [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item, idx: scroll.viewPortInfo.startIndexWithBuffer + i }"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
@ -32,8 +39,9 @@
|
||||
|
||||
<ng-container *ngIf="jumpBarKeysToRender.length >= 4 && items.length > 0 && scroll.viewPortInfo.maxScrollPosition > 0" [ngTemplateOutlet]="jumpBar" [ngTemplateOutletContext]="{ id: 'jumpbar' }"></ng-container>
|
||||
</div>
|
||||
|
||||
<ng-template #cardTemplate>
|
||||
<virtual-scroller #scroll [items]="items" [bufferAmount]="1">
|
||||
<virtual-scroller #scroll [items]="items" [bufferAmount]="bufferAmount">
|
||||
<div class="grid row g-0" #container>
|
||||
<div class="card col-auto mt-2 mb-2" (click)="tryToSaveJumpKey(item)" *ngFor="let item of scroll.viewPortItems; trackBy:trackByIdentity; index as i" id="jumpbar-index--{{i}}" [attr.jumpbar-index]="i">
|
||||
<ng-container [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item, idx: i }"></ng-container>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user