Stability (I hope) (#2688)
This commit is contained in:
parent
92ad7db918
commit
7e61cca92d
30 changed files with 3336 additions and 177 deletions
|
@ -33,6 +33,10 @@ export class MetadataService {
|
|||
return this.httpClient.get<SeriesDetailPlus | null>(this.baseUrl + 'metadata/series-detail-plus?seriesId=' + seriesId + '&libraryType=' + libraryType);
|
||||
}
|
||||
|
||||
forceRefreshFromPlus(seriesId: number) {
|
||||
return this.httpClient.post(this.baseUrl + 'metadata/force-refresh?seriesId=' + seriesId, {});
|
||||
}
|
||||
|
||||
getAllAgeRatings(libraries?: Array<number>) {
|
||||
let method = 'metadata/age-ratings'
|
||||
if (libraries != undefined && libraries.length > 0) {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
</ng-container>
|
||||
<ng-container *ngIf="tab.fragment === TabID.KavitaPlus">
|
||||
<p>{{t('kavita+-desc-part-1')}} <a href="https://wiki.kavitareader.com/en/kavita-plus" target="_blank" rel="noreferrer nofollow">{{t('kavita+-desc-part-2')}}</a> {{t('kavita+-desc-part-3')}} <a href="https://wiki.kavitareader.com/en/kavita-plus#faq" target="_blank" rel="noreferrer nofollow">FAQ</a></p>
|
||||
<p>{{t('kavita+-requirement')}} <a [routerLink]="'/announcements'">{{t('kavita+-releases')}}</a></p>
|
||||
<app-license></app-license>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<ng-container *transloco="let t; read: 'manage-system'">
|
||||
<div class="container-fluid">
|
||||
<h3>{{t('title')}}</h3>
|
||||
<hr/>
|
||||
|
||||
<div class="mb-3" *ngIf="serverInfo">
|
||||
<h3>{{t('title')}}</h3>
|
||||
<dl>
|
||||
<dt>{{t('version-title')}}</dt>
|
||||
<dd>{{serverInfo.kavitaVersion}}</dd>
|
||||
|
@ -12,36 +12,43 @@
|
|||
</dl>
|
||||
</div>
|
||||
|
||||
<h3>{{t('more-info-title')}}</h3>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('home-page-title')}}</div>
|
||||
<div class="col"><a href="https://www.kavitareader.com" target="_blank" rel="noopener noreferrer">kavitareader.com</a></div>
|
||||
<div class="mb-3">
|
||||
<h3>{{t('more-info-title')}}</h3>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('home-page-title')}}</div>
|
||||
<div class="col"><a href="https://www.kavitareader.com" target="_blank" rel="noopener noreferrer">kavitareader.com</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('wiki-title')}}</div>
|
||||
<div class="col"><a href="https://wiki.kavitareader.com" target="_blank" rel="noopener noreferrer">wiki.kavitareader.com</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('discord-title')}}</div>
|
||||
<div class="col"><a href="https://discord.gg/b52wT37kt7" target="_blank" rel="noopener noreferrer">discord.gg/b52wT37kt7</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('donations-title')}}</div>
|
||||
<div class="col"><a href="https://opencollective.com/kavita" target="_blank" rel="noopener noreferrer">opencollective.com/kavita</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('source-title')}}</div>
|
||||
<div class="col"><a href="https://github.com/Kareadita/Kavita" target="_blank" rel="noopener noreferrer">github.com/Kareadita/Kavita</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('localization-title')}}</div>
|
||||
<div class="col"><a href="https://hosted.weblate.org/engage/kavita/" target="_blank" rel="noopener noreferrer">Weblate</a><br/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('feature-request-title')}}</div>
|
||||
<div class="col"><a href="https://github.com/Kareadita/Kavita/discussions/2529" target="_blank" rel="noopener noreferrer">https://github.com/Kareadita/Kavita/discussions/</a><br/></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('wiki-title')}}</div>
|
||||
<div class="col"><a href="https://wiki.kavitareader.com" target="_blank" rel="noopener noreferrer">wiki.kavitareader.com</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('discord-title')}}</div>
|
||||
<div class="col"><a href="https://discord.gg/b52wT37kt7" target="_blank" rel="noopener noreferrer">discord.gg/b52wT37kt7</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('donations-title')}}</div>
|
||||
<div class="col"><a href="https://opencollective.com/kavita" target="_blank" rel="noopener noreferrer">opencollective.com/kavita</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('source-title')}}</div>
|
||||
<div class="col"><a href="https://github.com/Kareadita/Kavita" target="_blank" rel="noopener noreferrer">github.com/Kareadita/Kavita</a></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('localization-title')}}</div>
|
||||
<div class="col"><a href="https://hosted.weblate.org/engage/kavita/" target="_blank" rel="noopener noreferrer">Weblate</a><br/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">{{t('feature-request-title')}}</div>
|
||||
<div class="col"><a href="https://github.com/Kareadita/Kavita/discussions/2529" target="_blank" rel="noopener noreferrer">https://github.com/Kareadita/Kavita/discussions/</a><br/></div>
|
||||
|
||||
<div class="mb-3">
|
||||
<h3>{{t('updates-title')}}</h3>
|
||||
<app-changelog></app-changelog>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
|
|
@ -3,6 +3,7 @@ import {ServerService} from 'src/app/_services/server.service';
|
|||
import {ServerInfoSlim} from '../_models/server-info';
|
||||
import {NgIf} from '@angular/common';
|
||||
import {TranslocoDirective} from "@ngneat/transloco";
|
||||
import {ChangelogComponent} from "../../announcements/_components/changelog/changelog.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-manage-system',
|
||||
|
@ -10,7 +11,7 @@ import {TranslocoDirective} from "@ngneat/transloco";
|
|||
styleUrls: ['./manage-system.component.scss'],
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [NgIf, TranslocoDirective]
|
||||
imports: [NgIf, TranslocoDirective, ChangelogComponent]
|
||||
})
|
||||
export class ManageSystemComponent implements OnInit {
|
||||
|
||||
|
|
|
@ -55,12 +55,13 @@ export class ManageTasksSettingsComponent implements OnInit {
|
|||
api: this.serverService.convertMedia(),
|
||||
successMessage: 'convert-media-task-success'
|
||||
},
|
||||
{
|
||||
name: 'bust-cache-task',
|
||||
description: 'bust-cache-task-desc',
|
||||
api: this.serverService.bustCache(),
|
||||
successMessage: 'bust-cache-task-success'
|
||||
},
|
||||
// I removed this as it's not really needed, given that External Recs are the only thing that fill this cache now
|
||||
// {
|
||||
// name: 'bust-cache-task',
|
||||
// description: 'bust-cache-task-desc',
|
||||
// api: this.serverService.bustCache(),
|
||||
// successMessage: 'bust-cache-task-success'
|
||||
// },
|
||||
{
|
||||
name: 'bust-locale-task',
|
||||
description: 'bust-locale-task-desc',
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<div class="card w-100 mb-2" style="width: 18rem;">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">{{update.updateTitle}}
|
||||
<span class="badge bg-secondary" *ngIf="isNightly(update)">{{t('nightly', {version: update.currentVersion})}}</span>
|
||||
<span class="badge bg-secondary" *ngIf="update.updateVersion === update.currentVersion">{{t('installed')}}</span>
|
||||
<span class="badge bg-secondary" *ngIf="update.updateVersion > update.currentVersion">{{t('available')}}</span>
|
||||
</h4>
|
||||
|
|
|
@ -1,29 +1,55 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { UpdateVersionEvent } from 'src/app/_models/events/update-version-event';
|
||||
import { ServerService } from 'src/app/_services/server.service';
|
||||
import { LoadingComponent } from '../../../shared/loading/loading.component';
|
||||
import { ReadMoreComponent } from '../../../shared/read-more/read-more.component';
|
||||
import { NgFor, NgIf, DatePipe } from '@angular/common';
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit} from '@angular/core';
|
||||
import {UpdateVersionEvent} from 'src/app/_models/events/update-version-event';
|
||||
import {ServerService} from 'src/app/_services/server.service';
|
||||
import {LoadingComponent} from '../../../shared/loading/loading.component';
|
||||
import {ReadMoreComponent} from '../../../shared/read-more/read-more.component';
|
||||
import {DatePipe, NgFor, NgIf} from '@angular/common';
|
||||
import {TranslocoDirective} from "@ngneat/transloco";
|
||||
|
||||
@Component({
|
||||
selector: 'app-changelog',
|
||||
templateUrl: './changelog.component.html',
|
||||
styleUrls: ['./changelog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [NgFor, NgIf, ReadMoreComponent, LoadingComponent, DatePipe, TranslocoDirective]
|
||||
selector: 'app-changelog',
|
||||
templateUrl: './changelog.component.html',
|
||||
styleUrls: ['./changelog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [NgFor, NgIf, ReadMoreComponent, LoadingComponent, DatePipe, TranslocoDirective],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ChangelogComponent implements OnInit {
|
||||
|
||||
private readonly serverService = inject(ServerService);
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
updates: Array<UpdateVersionEvent> = [];
|
||||
isLoading: boolean = true;
|
||||
|
||||
constructor(private serverService: ServerService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.serverService.getChangelog().subscribe(updates => {
|
||||
this.updates = updates;
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
isNightly(update: UpdateVersionEvent) {
|
||||
// Split the version numbers into arrays
|
||||
const updateVersionArr = update.updateVersion.split('.');
|
||||
const currentVersionArr = update.currentVersion.split('.');
|
||||
|
||||
// Compare the first three parts of the version numbers
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const updatePart = parseInt(updateVersionArr[i]);
|
||||
const currentPart = parseInt(currentVersionArr[i]);
|
||||
|
||||
// If any part of the update version is less than the corresponding part of the current version, return true
|
||||
if (updatePart < currentPart) {
|
||||
return true;
|
||||
}
|
||||
// If any part of the update version is greater than the corresponding part of the current version, return false
|
||||
else if (updatePart > currentPart) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If all parts are equal, compare the length of the version numbers
|
||||
return updateVersionArr.length < currentVersionArr.length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -460,6 +460,18 @@
|
|||
<div [ngbNavOutlet]="nav" class="tab-content {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'mt-3' : 'ms-4 flex-fill'}}"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@if (accountService.hasValidLicense$ | async) {
|
||||
<button type="button" class="btn btn-light" (click)="forceScan()" position="above"
|
||||
[ngbTooltip]="t('force-refresh-tooltip')">
|
||||
@if (forceIsLoading) {
|
||||
<div class="spinner-border spinner-border-sm text-primary" role="status">
|
||||
<span class="visually-hidden">loading...</span>
|
||||
</div>
|
||||
} @else {
|
||||
{{t('force-refresh')}}
|
||||
}
|
||||
</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" (click)="close()">{{t('close')}}</button>
|
||||
<button type="submit" class="btn btn-primary" [disabled]="!editSeriesForm.valid" (click)="save()">{{t('save')}}</button>
|
||||
</div>
|
||||
|
|
|
@ -51,10 +51,13 @@ import {PublicationStatusPipe} from "../../../_pipes/publication-status.pipe";
|
|||
import {BytesPipe} from "../../../_pipes/bytes.pipe";
|
||||
import {ImageComponent} from "../../../shared/image/image.component";
|
||||
import {DefaultValuePipe} from "../../../_pipes/default-value.pipe";
|
||||
import {TranslocoModule} from "@ngneat/transloco";
|
||||
import {translate, TranslocoModule} from "@ngneat/transloco";
|
||||
import {TranslocoDatePipe} from "@ngneat/transloco-locale";
|
||||
import {UtcToLocalTimePipe} from "../../../_pipes/utc-to-local-time.pipe";
|
||||
import {EditListComponent} from "../../../shared/edit-list/edit-list.component";
|
||||
import {AccountService} from "../../../_services/account.service";
|
||||
import {LibraryType} from "../../../_models/library/library";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
|
||||
enum TabID {
|
||||
General = 0,
|
||||
|
@ -66,6 +69,13 @@ enum TabID {
|
|||
Info = 6,
|
||||
}
|
||||
|
||||
export interface EditSeriesModalCloseResult {
|
||||
success: boolean;
|
||||
series: Series;
|
||||
coverImageUpdate: boolean;
|
||||
updateExternal: boolean
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-series-modal',
|
||||
standalone: true,
|
||||
|
@ -112,6 +122,9 @@ export class EditSeriesModalComponent implements OnInit {
|
|||
private readonly uploadService = inject(UploadService);
|
||||
private readonly metadataService = inject(MetadataService);
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
public readonly accountService = inject(AccountService);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly toastr = inject(ToastrService);
|
||||
|
||||
protected readonly TabID = TabID;
|
||||
protected readonly PersonRole = PersonRole;
|
||||
|
@ -133,7 +146,9 @@ export class EditSeriesModalComponent implements OnInit {
|
|||
editSeriesForm!: FormGroup;
|
||||
libraryName: string | undefined = undefined;
|
||||
size: number = 0;
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
hasForcedKPlus = false;
|
||||
forceIsLoading = false;
|
||||
|
||||
|
||||
// Typeaheads
|
||||
tagsSettings: TypeaheadSettings<Tag> = new TypeaheadSettings();
|
||||
|
@ -502,7 +517,17 @@ export class EditSeriesModalComponent implements OnInit {
|
|||
}
|
||||
|
||||
close() {
|
||||
this.modal.close({success: false, series: undefined, coverImageUpdate: this.coverImageReset});
|
||||
this.modal.close({success: false, series: undefined, coverImageUpdate: this.coverImageReset, updateExternal: this.hasForcedKPlus});
|
||||
}
|
||||
|
||||
forceScan() {
|
||||
this.forceIsLoading = true;
|
||||
this.metadataService.forceRefreshFromPlus(this.series.id).subscribe(() => {
|
||||
this.hasForcedKPlus = true;
|
||||
this.forceIsLoading = false;
|
||||
this.toastr.info(translate('toasts.force-kavita+-refresh-success'));
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
fetchCollectionTags(filter: string = '') {
|
||||
|
@ -541,7 +566,7 @@ export class EditSeriesModalComponent implements OnInit {
|
|||
this.saveNestedComponents.emit();
|
||||
|
||||
forkJoin(apis).subscribe(results => {
|
||||
this.modal.close({success: true, series: model, coverImageUpdate: selectedIndex > 0 || this.coverImageReset});
|
||||
this.modal.close({success: true, series: model, coverImageUpdate: selectedIndex > 0 || this.coverImageReset, updateExternal: this.hasForcedKPlus});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,10 @@ import {catchError, forkJoin, Observable, of} from 'rxjs';
|
|||
import {map, take} from 'rxjs/operators';
|
||||
import {BulkSelectionService} from 'src/app/cards/bulk-selection.service';
|
||||
import {CardDetailDrawerComponent} from 'src/app/cards/card-detail-drawer/card-detail-drawer.component';
|
||||
import {EditSeriesModalComponent} from 'src/app/cards/_modals/edit-series-modal/edit-series-modal.component';
|
||||
import {
|
||||
EditSeriesModalCloseResult,
|
||||
EditSeriesModalComponent
|
||||
} from 'src/app/cards/_modals/edit-series-modal/edit-series-modal.component';
|
||||
import {TagBadgeCursor} from 'src/app/shared/tag-badge/tag-badge.component';
|
||||
import {DownloadEvent, DownloadService} from 'src/app/shared/_services/download.service';
|
||||
import {KEY_CODES, UtilityService} from 'src/app/shared/_services/utility.service';
|
||||
|
@ -839,10 +842,10 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||
openEditSeriesModal() {
|
||||
const modalRef = this.modalService.open(EditSeriesModalComponent, { size: 'xl' });
|
||||
modalRef.componentInstance.series = this.series;
|
||||
modalRef.closed.subscribe((closeResult: {success: boolean, series: Series, coverImageUpdate: boolean}) => {
|
||||
modalRef.closed.subscribe((closeResult: EditSeriesModalCloseResult) => {
|
||||
if (closeResult.success) {
|
||||
window.scrollTo(0, 0);
|
||||
this.loadSeries(this.seriesId);
|
||||
this.loadSeries(this.seriesId, closeResult.updateExternal);
|
||||
}
|
||||
|
||||
if (closeResult.coverImageUpdate) {
|
||||
|
|
|
@ -559,6 +559,7 @@
|
|||
"changelog": {
|
||||
"installed": "Installed",
|
||||
"download": "Download",
|
||||
"nightly": "Nightly: {{version}}",
|
||||
"published-label": "Published: ",
|
||||
"available": "Available",
|
||||
"description": "If you do not see an {{installed}}",
|
||||
|
@ -1231,7 +1232,8 @@
|
|||
"donations-title": "Donations:",
|
||||
"source-title": "Source:",
|
||||
"feature-request-title": "Feature Requests:",
|
||||
"localization-title": "Localizations:"
|
||||
"localization-title": "Localizations:",
|
||||
"updates-title": "Update History"
|
||||
},
|
||||
|
||||
"manage-tasks-settings": {
|
||||
|
@ -1377,7 +1379,9 @@
|
|||
"kavita+-tab": "Kavita+",
|
||||
"kavita+-desc-part-1": "Kavita+ is a premium subscription service which unlocks features for all users on this Kavita instance. Buy a subscription to unlock ",
|
||||
"kavita+-desc-part-2": "premium benefits",
|
||||
"kavita+-desc-part-3": "today!"
|
||||
"kavita+-desc-part-3": "today!",
|
||||
"kavita+-requirement": "Kavita+ is designed to work only with the latest release - 2 versions. Anything outside of that is subject to not working.",
|
||||
"kavita+-releases": "See releases"
|
||||
},
|
||||
|
||||
"collection-detail": {
|
||||
|
@ -1718,9 +1722,9 @@
|
|||
"chapter-title": "Chapter:",
|
||||
"volume-num": "{{common.volume-num}}",
|
||||
"highest-count-tooltip": "Highest Count found across all ComicInfo in the Series",
|
||||
"max-issue-tooltip": "Max Issue or Volume field from all ComicInfo in the series"
|
||||
|
||||
|
||||
"max-issue-tooltip": "Max Issue or Volume field from all ComicInfo in the series",
|
||||
"force-refresh": "Force Refresh",
|
||||
"force-refresh-tooltip": "Force refresh external metadata from Kavita+"
|
||||
},
|
||||
|
||||
"day-breakdown": {
|
||||
|
@ -2060,7 +2064,8 @@
|
|||
"smart-filter-updated": "Created/Updated smart filter",
|
||||
"external-source-already-exists": "An External Source already exists with the same Name/Host/API Key",
|
||||
"anilist-token-expired": "Your AniList token is expired. Scrobbling will no longer process until you re-generate it in User Settings > Account",
|
||||
"collection-tag-deleted": "Collection Tag deleted"
|
||||
"collection-tag-deleted": "Collection Tag deleted",
|
||||
"force-kavita+-refresh-success": "Kavita+ external metadata has been invalidated"
|
||||
},
|
||||
|
||||
"actionable": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue