Co-authored-by: Zeoic <zeorgaming@gmail.com>
Co-authored-by: Fesaa <77553571+Fesaa@users.noreply.github.com>
This commit is contained in:
Joe Milazzo 2025-03-01 17:17:57 -06:00 committed by GitHub
parent b38400c092
commit 0ffe0228e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 339 additions and 115 deletions

View file

@ -0,0 +1,13 @@
import { Directive, HostListener } from '@angular/core';
@Directive({
selector: '[appEnterBlur]',
standalone: true,
})
export class EnterBlurDirective {
@HostListener('keydown.enter', ['$event'])
onEnter(event: KeyboardEvent): void {
event.preventDefault();
document.body.click();
}
}

View file

@ -242,7 +242,7 @@ export class SeriesService {
}
updateMatch(seriesId: number, series: ExternalSeriesDetail) {
return this.httpClient.post<string>(this.baseUrl + 'series/update-match?seriesId=' + seriesId + '&aniListId=' + series.aniListId, {}, TextResonse);
return this.httpClient.post<string>(this.baseUrl + `series/update-match?seriesId=${seriesId}&aniListId=${series.aniListId}${series.malId ? '&malId=' + series.malId : ''}`, {}, TextResonse);
}
updateDontMatch(seriesId: number, dontMatch: boolean) {

View file

@ -15,7 +15,7 @@
<li [ngbNavItem]="TabID.General">
<a ngbNavLink>{{t(TabID.General)}}</a>
<ng-template ngbNavContent>
<div class="row g-0">
<div class="row">
<div class="col-md-9 col-sm-12 mb-3">
<app-setting-item [title]="t('title-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@ -23,7 +23,7 @@
<div class="input-group" [ngClass]="{'lock-active': chapter.titleNameLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'titleNameLocked' }"></ng-container>
<input class="form-control" formControlName="titleName" type="text"
[class.is-invalid]="formControl.invalid && formControl.touched">
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors; as errors) {
<div class="invalid-feedback">
@if (errors.required) {
@ -44,7 +44,7 @@
<div class="input-group" [ngClass]="{'lock-active': chapter.sortOrderLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'sortOrderLocked' }"></ng-container>
<input class="form-control" formControlName="sortOrder" type="number" min="0" step="0.1" inputmode="numeric"
[class.is-invalid]="formControl.invalid && formControl.touched">
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors; as errors) {
<div class="invalid-feedback">
@if (errors.required) {
@ -59,7 +59,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-md-9 col-sm-12 mb-3">
<app-setting-item [title]="t('isbn-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@ -67,7 +67,7 @@
<div class="input-group" [ngClass]="{'lock-active': chapter.isbnLocked}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: chapter, field: 'isbnLocked' }"></ng-container>
<input class="form-control" formControlName="isbn" type="text"
[class.is-invalid]="formControl.invalid && formControl.touched">
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors; as errors) {
<div class="invalid-feedback">
@if (errors.required) {
@ -99,7 +99,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-9 col-md-12">
<div class="mb-3">
<app-setting-item [title]="t('language-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -137,7 +137,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3" style="width: 100%">
<app-setting-item [title]="t('summary-label')" [showEdit]="false" [toggleOnViewClick]="false">
<ng-template #view>
@ -163,7 +163,7 @@
<a ngbNavLink>{{t(TabID.Tags)}}</a>
<ng-template ngbNavContent>
<!-- genre & tag -->
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('genres-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -204,7 +204,7 @@
</div>
<!-- imprint & publisher -->
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('imprint-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -245,7 +245,7 @@
</div>
<!-- team & location -->
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('team-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -286,7 +286,7 @@
</div>
<!-- character -->
<div class="row g-0">
<div class="row">
<div class="col-lg-12 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('character-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -319,7 +319,7 @@
<a ngbNavLink>{{t(TabID.People)}}</a>
<ng-template ngbNavContent>
<!-- writer & cover artist -->
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('writer-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -360,7 +360,7 @@
</div>
<!-- penciller & colorist -->
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('penciller-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -401,7 +401,7 @@
</div>
<!-- inker & letterer -->
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('inker-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -442,7 +442,7 @@
</div>
<!-- translator -->
<div class="row g-0">
<div class="row">
<div class="col-lg-12 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('translator-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -487,7 +487,7 @@
<li [ngbNavItem]="TabID.Info">
<a ngbNavLink>{{t(TabID.Info)}}</a>
<ng-template ngbNavContent>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('pages-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -508,7 +508,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('read-time-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -530,7 +530,7 @@
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('date-added-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -556,7 +556,7 @@
<div class="setting-section-break"></div>
<div class="container-fluid mb-3">
<div class="row g-0">
<div class="row">
<h6 class="section-title">{{t('links-label')}}</h6>
<div class="col-auto">
@for(link of WebLinks; track link) {
@ -571,7 +571,7 @@
}
@if (accountService.isAdmin$ | async) {
<div class="row g-0">
<div class="row">
<app-setting-item [title]="t('files-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@for (file of chapter.files; track file.id) {

View file

@ -12,7 +12,7 @@
<li [ngbNavItem]="TabID.Info">
<a ngbNavLink>{{t(TabID.Info)}}</a>
<ng-template ngbNavContent>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('pages-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -33,7 +33,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('read-time-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -55,7 +55,7 @@
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('date-added-label')" [toggleOnViewClick]="false" [showEdit]="false">

View file

@ -7,17 +7,15 @@ import {ScrobbleEventTypePipe} from "../../_pipes/scrobble-event-type.pipe";
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
import {ScrobbleEventSortField} from "../../_models/scrobbling/scrobble-event-filter";
import {debounceTime, take} from "rxjs/operators";
import {PaginatedResult, Pagination} from "../../_models/pagination";
import {PaginatedResult} from "../../_models/pagination";
import {SortEvent} from "../table/_directives/sortable-header.directive";
import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
import {translate, TranslocoModule} from "@jsverse/transloco";
import {TranslocoModule} from "@jsverse/transloco";
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {TranslocoLocaleModule} from "@jsverse/transloco-locale";
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
import {ToastrService} from "ngx-toastr";
import {LooseLeafOrDefaultNumber, SpecialVolumeNumber} from "../../_models/chapter";
import {ColumnMode, NgxDatatableModule} from "@siemens/ngx-datatable";
import {CardActionablesComponent} from "../card-actionables/card-actionables.component";
import {AsyncPipe} from "@angular/common";
import {AccountService} from "../../_services/account.service";
@ -32,7 +30,7 @@ export interface DataTablePage {
selector: 'app-user-scrobble-history',
standalone: true,
imports: [ScrobbleEventTypePipe, ReactiveFormsModule, TranslocoModule,
DefaultValuePipe, TranslocoLocaleModule, UtcToLocalTimePipe, NgbTooltip, NgxDatatableModule, CardActionablesComponent, AsyncPipe],
DefaultValuePipe, TranslocoLocaleModule, UtcToLocalTimePipe, NgbTooltip, NgxDatatableModule, AsyncPipe],
templateUrl: './user-scrobble-history.component.html',
styleUrls: ['./user-scrobble-history.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
@ -47,7 +45,6 @@ export class UserScrobbleHistoryComponent implements OnInit {
private readonly scrobblingService = inject(ScrobblingService);
private readonly cdRef = inject(ChangeDetectorRef);
private readonly destroyRef = inject(DestroyRef);
private readonly toastr = inject(ToastrService);
protected readonly accountService = inject(AccountService);
@ -67,7 +64,8 @@ export class UserScrobbleHistoryComponent implements OnInit {
ngOnInit() {
this.onPageChange({offset: 0});
this.pageInfo.pageNumber = 0;
this.cdRef.markForCheck();
this.scrobblingService.hasTokenExpired(ScrobbleProvider.AniList).subscribe(hasExpired => {
this.tokenExpired = hasExpired;

View file

@ -19,7 +19,7 @@
<ng-template #edit>
<div class="input-group">
<input id="settings-hostname" aria-describedby="hostname-validations" class="form-control" formControlName="hostName" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
<button type="button" class="btn btn-outline-secondary" (click)="autofillGmail()">{{t('gmail-label')}}</button>
<button type="button" class="btn btn-outline-secondary" (click)="autofillOutlook()">{{t('outlook-label')}}</button>
</div>
@ -43,7 +43,7 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="text" class="form-control" formControlName="senderAddress" id="settings-sender-address" />
<input type="text" class="form-control" formControlName="senderAddress" id="settings-sender-address" appEnterBlur/>
</ng-template>
</app-setting-item>
}
@ -56,7 +56,7 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="text" class="form-control" formControlName="senderDisplayName" id="settings-sender-displayname" />
<input type="text" class="form-control" formControlName="senderDisplayName" id="settings-sender-displayname" appEnterBlur />
</ng-template>
</app-setting-item>
}
@ -69,7 +69,7 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="text" class="form-control" formControlName="host" id="settings-host" />
<input type="text" class="form-control" formControlName="host" id="settings-host" appEnterBlur />
</ng-template>
</app-setting-item>
}
@ -82,7 +82,7 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="number" inputmode="numeric" min="1" class="form-control" formControlName="port" id="settings-port" />
<input type="number" inputmode="numeric" min="1" class="form-control" formControlName="port" id="settings-port" appEnterBlur />
</ng-template>
</app-setting-item>
}
@ -107,7 +107,7 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="text" class="form-control" formControlName="userName" id="settings-username" />
<input type="text" class="form-control" formControlName="userName" id="settings-username" appEnterBlur />
</ng-template>
</app-setting-item>
}
@ -120,7 +120,7 @@
{{formControl.value ? '********' : null | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="text" class="form-control" formControlName="password" id="settings-password" />
<input type="text" class="form-control" formControlName="password" id="settings-password" appEnterBlur />
</ng-template>
</app-setting-item>
}
@ -133,7 +133,7 @@
{{formControl.value | bytes}}
</ng-template>
<ng-template #edit>
<input type="number" inputmode="numeric" min="1" class="form-control" formControlName="sizeLimit" id="settings-size-limit" />
<input type="number" inputmode="numeric" min="1" class="form-control" formControlName="sizeLimit" id="settings-size-limit" appEnterBlur />
</ng-template>
</app-setting-item>
}

View file

@ -10,6 +10,7 @@ import {SettingSwitchComponent} from "../../settings/_components/setting-switch/
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {BytesPipe} from "../../_pipes/bytes.pipe";
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {EnterBlurDirective} from "../../_directives/enter-blur.directive";
@Component({
selector: 'app-manage-email-settings',
@ -17,7 +18,7 @@ import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
styleUrls: ['./manage-email-settings.component.scss'],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ReactiveFormsModule, TranslocoModule, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, BytesPipe]
imports: [ReactiveFormsModule, TranslocoModule, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, BytesPipe, EnterBlurDirective]
})
export class ManageEmailSettingsComponent implements OnInit {

View file

@ -18,6 +18,7 @@ import {PersonRole} from "../../_models/metadata/person";
import {PersonRolePipe} from "../../_pipes/person-role.pipe";
import {allMetadataSettingField, MetadataSettingField} from "../_models/metadata-setting-field";
import {MetadataSettingFiledPipe} from "../../_pipes/metadata-setting-filed.pipe";
import {EnterBlurDirective} from "../../_directives/enter-blur.directive";
@Component({
@ -33,6 +34,7 @@ import {MetadataSettingFiledPipe} from "../../_pipes/metadata-setting-filed.pipe
AgeRatingPipe,
PersonRolePipe,
MetadataSettingFiledPipe,
EnterBlurDirective,
],
templateUrl: './manage-metadata-settings.component.html',
styleUrl: './manage-metadata-settings.component.scss',

View file

@ -21,7 +21,7 @@
</ng-template>
<ng-template #edit>
<input id="settings-hostname" aria-describedby="settings-hostname-help" class="form-control" formControlName="hostName" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if(settingsForm.dirty || !settingsForm.untouched) {
<div id="hostname-validations" class="invalid-feedback">
@ -44,7 +44,7 @@
<ng-template #edit>
<div class="input-group">
<input id="settings-baseurl" aria-describedby="settings-baseurl-help" class="form-control" formControlName="baseUrl" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
<button type="button" class="btn btn-outline-secondary" (click)="resetBaseUrl()">{{t('reset')}}</button>
</div>
@ -69,7 +69,7 @@
<ng-template #edit>
<div class="input-group">
<input id="settings-ipaddresses" aria-describedby="settings-ipaddresses-help" class="form-control" formControlName="ipAddresses" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
<button type="button" class="btn btn-outline-secondary" (click)="resetIPAddresses()">{{t('reset')}}</button>
</div>
@ -94,7 +94,7 @@
<ng-template #edit>
<input id="settings-port" aria-describedby="settings-port-help" class="form-control"
formControlName="port" type="number" step="1" min="1"
onkeypress="return event.charCode >= 48 && event.charCode <= 57">
onkeypress="return event.charCode >= 48 && event.charCode <= 57" appEnterBlur>
</ng-template>
</app-setting-item>
}
@ -116,7 +116,7 @@
<input id="settings-backup" aria-describedby="total-backups-validations" class="form-control"
formControlName="totalBackups" type="number" inputmode="numeric" step="1" min="1" max="30"
onkeypress="return event.charCode >= 48 && event.charCode <= 57"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if(settingsForm.dirty || !settingsForm.untouched) {
<div id="total-backups-validations" class="invalid-feedback">
@ -146,7 +146,7 @@
<input id="settings-logs" aria-describedby="total-logs-validations" class="form-control"
formControlName="totalLogs" type="number" inputmode="numeric" step="1" min="1" max="30"
onkeypress="return event.charCode >= 48 && event.charCode <= 57"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if(settingsForm.dirty || !settingsForm.untouched) {
<div id="total-logs-validations" class="invalid-feedback">
@ -202,7 +202,7 @@
<ng-template #edit>
<input id="setting-cache-size" aria-describedby="cache-size-help" class="form-control" formControlName="cacheSize"
type="number" inputmode="numeric" step="5" min="50" onkeypress="return event.charCode >= 48 && event.charCode <= 57"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if(settingsForm.dirty || !settingsForm.untouched) {
<div id="cache-size-validations" class="invalid-feedback">
@ -271,7 +271,7 @@
<input id="setting-on-deck-progress-days" aria-describedby="on-deck-progress-days-validations" class="form-control" formControlName="onDeckProgressDays"
type="number" inputmode="numeric" step="1" min="1"
onkeypress="return event.charCode >= 48 && event.charCode <= 57"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if(settingsForm.dirty || !settingsForm.untouched) {
<div id="on-deck-last-progress-validations" class="invalid-feedback">
@ -298,7 +298,7 @@
<input id="on-deck-last-chapter-add" aria-describedby="on-deck-last-chapter-add-validations" class="form-control" formControlName="onDeckUpdateDays"
type="number" inputmode="numeric" step="1" min="1"
onkeypress="return event.charCode >= 48 && event.charCode <= 57"
[class.is-invalid]="formControl.invalid && !formControl.untouched">
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if(settingsForm.dirty || !settingsForm.untouched) {
<div id="on-deck-last-chapter-add-validations" class="invalid-feedback">

View file

@ -14,6 +14,7 @@ import {ConfirmService} from "../../shared/confirm.service";
import {debounceTime, distinctUntilChanged, filter, of, switchMap, tap} from "rxjs";
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {EnterBlurDirective} from "../../_directives/enter-blur.directive";
const ValidIpAddress = /^(\s*((([12]?\d{1,2}\.){3}[12]?\d{1,2})|(([\da-f]{0,4}\:){0,7}([\da-f]{0,4})))\s*\,)*\s*((([12]?\d{1,2}\.){3}[12]?\d{1,2})|(([\da-f]{0,4}\:){0,7}([\da-f]{0,4})))\s*$/i;
@ -23,7 +24,7 @@ const ValidIpAddress = /^(\s*((([12]?\d{1,2}\.){3}[12]?\d{1,2})|(([\da-f]{0,4}\:
styleUrls: ['./manage-settings.component.scss'],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ReactiveFormsModule, TitleCasePipe, TranslocoModule, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe]
imports: [ReactiveFormsModule, TitleCasePipe, TranslocoModule, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, EnterBlurDirective]
})
export class ManageSettingsComponent implements OnInit {

View file

@ -13,14 +13,14 @@
<li [ngbNavItem]="tabs[TabID.General]">
<a ngbNavLink>{{t(tabs[TabID.General])}}</a>
<ng-template ngbNavContent>
<div class="row g-0">
<div class="row">
<div class="mb-3" style="width: 100%">
<app-setting-item [title]="t('name-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<div class="input-group">
@if (editSeriesForm.get('name'); as formControl) {
<input id="name" class="form-control" formControlName="name" type="text" readonly
[class.is-invalid]="formControl.invalid && formControl.touched">
[class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors) {
@if (formControl.errors.required) {
<div class="invalid-feedback">{{t('required-field')}}</div>
@ -33,14 +33,14 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3" style="width: 100%">
@if (editSeriesForm.get('sortName'); as formControl) {
<app-setting-item [title]="t('sort-name-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
<div class="input-group {{series.sortNameLocked ? 'lock-active' : ''}}">
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: series, field: 'sortNameLocked' }"></ng-container>
<input id="sort-name" class="form-control" formControlName="sortName" type="text" [class.is-invalid]="formControl.invalid && formControl.touched">
<input id="sort-name" class="form-control" formControlName="sortName" type="text" [class.is-invalid]="formControl.invalid && !formControl.untouched">
@if (formControl.errors) {
@if (formControl.errors.required) {
<div class="invalid-feedback">{{t('required-field')}}</div>
@ -53,7 +53,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3" style="width: 100%">
<app-setting-item [title]="t('localized-name-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -69,7 +69,7 @@
</div>
@if (metadata) {
<div class="row g-0">
<div class="row">
<div class="mb-3" style="width: 100%">
<app-setting-item [title]="t('summary-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -91,7 +91,7 @@
<a ngbNavLink>{{t(tabs[TabID.Metadata])}}</a>
<ng-template ngbNavContent>
<div class="row g-0">
<div class="row">
<div class="col-lg-8 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('language-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -131,7 +131,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-md-12">
<div class="mb-3">
<app-setting-item [title]="t('genres-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -152,7 +152,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-md-12">
<div class="mb-3">
<app-setting-item [title]="t('tags-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -173,7 +173,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('age-rating-label')" [toggleOnViewClick]="false" [showEdit]="false">
@ -215,7 +215,7 @@
<li [ngbNavItem]="tabs[TabID.People]">
<a ngbNavLink>{{t(tabs[TabID.People])}}</a>
<ng-template ngbNavContent>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('writer-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -233,7 +233,7 @@
</app-setting-item>
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('cover-artist-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -253,7 +253,7 @@
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('publisher-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -272,7 +272,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('imprint-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -291,7 +291,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('penciller-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -311,7 +311,7 @@
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('letterer-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -329,7 +329,7 @@
</app-setting-item>
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('inker-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -350,7 +350,7 @@
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('editor-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -368,7 +368,7 @@
</app-setting-item>
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('colorist-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -387,7 +387,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('translator-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -406,7 +406,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('character-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -425,7 +425,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('team-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -444,7 +444,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="mb-3">
<app-setting-item [title]="t('location-label')" [toggleOnViewClick]="false" [showEdit]="false">
<ng-template #view>
@ -498,7 +498,7 @@
<ng-template ngbNavContent>
<h5>{{t('info-title')}}</h5>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('library-title')" [toggleOnViewClick]="false" [showEdit]="false">
@ -519,7 +519,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('folder-path-title')" [subtitle]="t('folder-path-tooltip')" [toggleOnViewClick]="false" [showEdit]="false">
@ -541,7 +541,7 @@
</div>
@if (metadata) {
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('max-items-title')" [subtitle]="t('highest-count-tooltip')" [toggleOnViewClick]="false" [showEdit]="false">
@ -562,7 +562,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('publication-status-title')" [toggleOnViewClick]="false" [showEdit]="false">
@ -584,7 +584,7 @@
</div>
}
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('created-title')" [toggleOnViewClick]="false" [showEdit]="false">
@ -605,7 +605,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('last-scanned-title')" [toggleOnViewClick]="false" [showEdit]="false">
@ -626,7 +626,7 @@
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col-lg-6 col-md-12 pe-2">
<div class="mb-3">
<app-setting-item [title]="t('total-pages-title')" [toggleOnViewClick]="false" [showEdit]="false">
@ -660,7 +660,7 @@
<div class="flex-grow-1">
<h5 class="mt-0 mb-1">{{formatVolumeName(volume)}}</h5>
<div>
<div class="row g-0">
<div class="row">
<div class="col">
{{t('added-title')}} {{volume.createdUtc | utcToLocalTime | defaultDate}}
</div>
@ -668,7 +668,7 @@
{{t('last-modified-title')}} {{volume.lastModifiedUtc | utcToLocalTime | translocoDate: {dateStyle: 'short' } | defaultDate}}
</div>
</div>
<div class="row g-0">
<div class="row">
<div class="col">
<button type="button" class="btn btn-outline-primary" (click)="collapse.toggle()"
[attr.aria-expanded]="!volumeCollapsed[volume.name]" [disabled]="!isAdmin">
@ -685,7 +685,7 @@
@for(file of volume.volumeFiles; track file.id) {
<li class="list-group-item">
<span>{{file.filePath}}</span>
<div class="row g-0">
<div class="row">
<div class="col">
{{t('chapter-title')}} {{file.chapter}}
</div>

View file

@ -61,6 +61,7 @@
@if (works$ | async; as works) {
<div class="row mt-2">
<!-- TODO: If the person is JUST a character, then switch this title to: 'A character in` -->
<app-carousel-reel [items]="works" [title]="t('known-for-title')" (sectionClick)="loadFilterByPerson()">
<ng-template #carouselItem let-item>
<app-card-item [entity]="item"

View file

@ -829,10 +829,37 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
if (!this.router.url.includes('#')) {
this.updateSelectedTab();
} else if (this.activeTabId != TabID.Storyline) {
// Validate that the tab we are selected is still there (in case this comes from a messageHub)
switch (this.activeTabId) {
case TabID.Related:
if (!this.hasRelations) this.updateSelectedTab();
break;
case TabID.Specials:
if (!this.hasSpecials) this.updateSelectedTab();
break;
case TabID.Volumes:
if (this.volumes.length === 0) this.updateSelectedTab();
break;
case TabID.Chapters:
if (this.chapters.length === 0) this.updateSelectedTab();
break;
case TabID.Recommendations:
if (!this.hasRecommendations) this.updateSelectedTab();
break;
case TabID.Reviews:
if (this.reviews.length === 0) this.updateSelectedTab();
break;
case TabID.Details:
break;
}
this.cdRef.markForCheck();
}
this.isLoading = false;
this.cdRef.markForCheck();
});
@ -917,6 +944,8 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
}
}
// BUG: Related or other tab can be in history but no longer there, need to default
this.updateUrl(this.activeTabId);
this.cdRef.markForCheck();
}

View file

@ -83,6 +83,11 @@ export class EditListComponent implements OnInit {
.map(key => this.form.get(key)?.value)
.join(',');
// Recreate form to ensure index's match
this.form = new FormGroup({});
this.Items.forEach((item, index) => {
this.form.addControl('link' + index, new FormControl(item, []));
})
this.emit();
this.cdRef.markForCheck();

View file

@ -41,7 +41,7 @@ $image-width: 160px;
position: relative;
color: var(--card-text-color);
border: 1px var(--card-border-color);
box-sizing: border-box;
}
.card-title {