Comic Rework, New Scanner, Foundation Overahul (is this a full release?) (#2780)

This commit is contained in:
Joe Milazzo 2024-03-17 12:58:32 -05:00 committed by GitHub
parent d7e9e7c832
commit 7552c3f5fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
182 changed files with 27630 additions and 3046 deletions

View file

@ -21,40 +21,20 @@
<ng-container *ngIf="currentStepIndex === Step.Validate">
<p>{{t('validate-description')}}</p>
<div class="row g-0">
<div ngbAccordion #accordion="ngbAccordion">
@for(fileToProcess of filesToProcess; track fileToProcess.fileName) {
<div ngbAccordionItem *ngIf="fileToProcess.validateSummary as summary">
<h5 ngbAccordionHeader>
<button ngbAccordionButton>
<ng-container [ngTemplateOutlet]="heading" [ngTemplateOutletContext]="{ summary: summary, filename: fileToProcess.fileName }"></ng-container>
</button>
</h5>
<div ngbAccordionCollapse>
<div ngbAccordionBody>
@if(summary.results.length > 0) {
<h5>{{t('validate-warning')}}</h5>
<ol class="list-group list-group-numbered list-group-flush" >
<li class="list-group-item no-hover" *ngFor="let result of summary.results"
[innerHTML]="result | cblConflictReason | safeHtml">
</li>
</ol>
} @else {
<div class="justify-content-center col">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="fa-solid fa-circle-check" style="font-size: 24px" aria-hidden="true"></i>
</div>
<div class="flex-grow-1 ms-3">
{{t('validate-no-issue')}}
</div>
</div>
{{t('validate-no-issue-description')}}
</div>
}
<div ngbAccordionItem *ngIf="fileToProcess.validateSummary as summary">
<h5 ngbAccordionHeader>
<button ngbAccordionButton>
<ng-container [ngTemplateOutlet]="heading" [ngTemplateOutletContext]="{ summary: summary, filename: fileToProcess.fileName }"></ng-container>
</button>
</h5>
<div ngbAccordionCollapse>
<div ngbAccordionBody>
<ng-container [ngTemplateOutlet]="validationList" [ngTemplateOutletContext]="{ summary: summary }"></ng-container>
</div>
</div>
</div>
</div>
}
</div>
</div>
@ -105,6 +85,38 @@
</ng-container>
</div>
<ng-template #validationList let-summary="summary">
@if (summary.results.length > 0) {
<div class="justify-content-center col">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="fa-solid fa-triangle-exclamation" style="font-size: 24px" aria-hidden="true"></i>
</div>
<div class="flex-grow-1 ms-3">
{{t('validate-warning')}}
</div>
</div>
</div>
<ol class="list-group list-group-numbered list-group-flush" >
<li class="list-group-item no-hover" *ngFor="let result of summary.results"
[innerHTML]="result | cblConflictReason | safeHtml">
</li>
</ol>
}
@else {
<div class="justify-content-center col">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="fa-solid fa-circle-check" style="font-size: 24px" aria-hidden="true"></i>
</div>
<div class="flex-grow-1 ms-3">
{{t('validate-no-issue-description')}}
</div>
</div>
</div>
}
</ng-template>
<ng-template #resultsList let-summary="summary">
<ul class="list-group list-group-flush">
@for(result of summary.results; track result.order) {
@ -115,23 +127,46 @@
</ng-template>
<ng-template #heading let-filename="filename" let-summary="summary">
<ng-container *ngIf="summary.success | cblImportResult as success">
<ng-container [ngSwitch]="summary.success">
<span *ngSwitchCase="CblImportResult.Success" class="badge bg-primary me-1">{{success}}</span>
<span *ngSwitchCase="CblImportResult.Fail" class="badge bg-danger me-1">{{success}}</span>
<span *ngSwitchCase="CblImportResult.Partial" class="badge bg-warning me-1">{{success}}</span>
</ng-container>
</ng-container>
<span>{{filename}}<span *ngIf="summary.cblName">: ({{summary.cblName}})</span></span>
@switch (summary.success) {
@case (CblImportResult.Success) {
<span class="badge heading-badge bg-primary me-1">{{summary.success | cblImportResult}}</span>
}
@case (CblImportResult.Fail) {
<span class="badge heading-badge bg-danger me-1">{{summary.success | cblImportResult}}</span>
}
@case (CblImportResult.Partial) {
<span class="badge heading-badge bg-warning me-1">{{summary.success | cblImportResult}}</span>
}
}
<span>{{filename}}<span *ngIf="summary.cblName">: ({{summary.cblName}})</span></span>
</ng-template>
</div>
<div class="modal-footer">
<a class="btn btn-icon" href="https://wiki.kavitareader.com/en/guides/get-started-using-your-library/reading-lists#creating-a-reading-list-via-cbl" target="_blank" rel="noopener noreferrer">Help</a>
<button type="button" class="btn btn-secondary" (click)="close()">{{t('close')}}</button>
<button type="button" class="btn btn-primary" (click)="prevStep()" [disabled]="!canMoveToPrevStep()">{{t('prev')}}</button>
<button type="button" class="btn btn-primary" (click)="nextStep()" [disabled]="!canMoveToNextStep()">{{t(NextButtonLabel)}}</button>
<form [formGroup]="cblSettingsForm" class="row align-items-center">
<div class="col-auto">
<div class="form-check form-switch">
<input type="checkbox" id="settings-comicvine-mode" role="switch" formControlName="comicVineMatching" class="form-check-input"
aria-labelledby="auto-close-label">
<label class="form-check-label" for="settings-comicvine-mode">{{t('comicvine-parsing-label')}}</label>
</div>
</div>
</form>
<!-- Spacer -->
<div class="col" aria-hidden="true"></div>
<div class="col-auto">
<a class="btn btn-icon" href="https://wiki.kavitareader.com/en/guides/get-started-using-your-library/reading-lists#creating-a-reading-list-via-cbl" target="_blank" rel="noopener noreferrer">Help</a>
</div>
<div class="col-auto">
<button type="button" class="btn btn-secondary" (click)="close()">{{t('close')}}</button>
</div>
<div class="col-auto">
<button type="button" class="btn btn-primary" (click)="prevStep()" [disabled]="!canMoveToPrevStep()">{{t('prev')}}</button>
</div>
<div class="col-auto">
<button type="button" class="btn btn-primary" (click)="nextStep()" [disabled]="!canMoveToNextStep()">{{t(NextButtonLabel)}}</button>
</div>
</div>

View file

@ -2,6 +2,10 @@
display: none;
}
.heading-badge {
color: var(--bs-badge-color);
}
::ng-deep .file-info {
width: 83%;
float: left;
@ -38,4 +42,4 @@ file-upload {
::ng-deep .reading-list-fail--item {
color: var(--error-color);
}
}

View file

@ -46,8 +46,12 @@ enum Step {
})
export class ImportCblModalComponent {
protected readonly CblImportResult = CblImportResult;
protected readonly Step = Step;
@ViewChild('fileUpload') fileUpload!: ElementRef<HTMLInputElement>;
fileUploadControl = new FormControl<undefined | Array<File>>(undefined, [
FileUploadValidators.accept(['.cbl']),
]);
@ -55,6 +59,9 @@ export class ImportCblModalComponent {
uploadForm = new FormGroup({
files: this.fileUploadControl
});
cblSettingsForm = new FormGroup({
comicVineMatching: new FormControl(true, [])
});
isLoading: boolean = false;
@ -70,10 +77,6 @@ export class ImportCblModalComponent {
failedFiles: Array<FileStep> = [];
get Breakpoint() { return Breakpoint; }
get Step() { return Step; }
get CblImportResult() { return CblImportResult; }
get NextButtonLabel() {
switch(this.currentStepIndex) {
case Step.DryRun:
@ -105,11 +108,12 @@ export class ImportCblModalComponent {
return;
}
// Load each file into filesToProcess and group their data
let pages = [];
const pages = [];
for (let i = 0; i < files.length; i++) {
const formData = new FormData();
formData.append('cbl', files[i]);
formData.append('dryRun', true + '');
formData.append('dryRun', 'true');
formData.append('comicVineMatching', this.cblSettingsForm.get('comicVineMatching')?.value + '');
pages.push(this.readingListService.validateCbl(formData));
}
forkJoin(pages).subscribe(results => {
@ -195,12 +199,13 @@ export class ImportCblModalComponent {
const filenamesAllowedToProcess = this.filesToProcess.map(p => p.fileName);
const files = (this.uploadForm.get('files')?.value || []).filter(f => filenamesAllowedToProcess.includes(f.name));
let pages = [];
const pages = [];
for (let i = 0; i < files.length; i++) {
const formData = new FormData();
formData.append('cbl', files[i]);
formData.append('dryRun', 'true');
pages.push(this.readingListService.importCbl(formData));
formData.append('cbl', files[i]);
formData.append('dryRun', 'true');
formData.append('comicVineMatching', this.cblSettingsForm.get('comicVineMatching')?.value + '');
pages.push(this.readingListService.importCbl(formData));
}
forkJoin(pages).subscribe(results => {
results.forEach(cblImport => {
@ -224,6 +229,7 @@ export class ImportCblModalComponent {
const formData = new FormData();
formData.append('cbl', files[i]);
formData.append('dryRun', 'false');
formData.append('comicVineMatching', this.cblSettingsForm.get('comicVineMatching')?.value + '');
pages.push(this.readingListService.importCbl(formData));
}
forkJoin(pages).subscribe(results => {