mirror of
https://github.com/adityachandelgit/BookLore.git
synced 2026-02-12 10:19:57 -06:00
Upgrade primeng to 20.0.1 (#903)
* build(npm): add missed packages * build(npm): upgrade primeng to 20.0.1 * feat(ui): upgrade ui to support 20 primeng https://primeng.org/migration/v19#compatible * fix(ui): p-input value max requires value * refactor(ui): remove unused component imports * build(npm): allow common js dependencies * style(ui): fix some warnings * fix(ui): replace chips with autoComplete --------- Co-authored-by: Aditya Chandel <8075870+adityachandelgit@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
77e02ac7f9
commit
60f8442514
@@ -47,7 +47,18 @@
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
"scripts": [],
|
||||
"allowedCommonJsDependencies": [
|
||||
"lodash",
|
||||
"quill-delta",
|
||||
"event-emitter",
|
||||
"showdown",
|
||||
"@xmldom/xmldom",
|
||||
"path-webpack",
|
||||
"jszip/dist/jszip",
|
||||
"localforage",
|
||||
"marks-pane"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
||||
2698
booklore-ui/package-lock.json
generated
2698
booklore-ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -21,10 +21,11 @@
|
||||
"@angular/platform-browser-dynamic": "^20.1.6",
|
||||
"@angular/router": "^20.1.6",
|
||||
"@iharbeck/ngx-virtual-scroller": "^19.0.1",
|
||||
"@primeng/themes": "^19.1.4",
|
||||
"@primeng/themes": "^20.0.1",
|
||||
"@stomp/rx-stomp": "^2.0.1",
|
||||
"@stomp/stompjs": "^7.1.1",
|
||||
"@tailwindcss/postcss": "^4.1.8",
|
||||
"@tweenjs/tween.js": "^25.0.0",
|
||||
"angular-oauth2-oidc": "^20.0.0",
|
||||
"epubjs": "^0.3.93",
|
||||
"jwt-decode": "^4.0.0",
|
||||
@@ -32,7 +33,7 @@
|
||||
"ngx-extended-pdf-viewer": "^23.3.1",
|
||||
"ngx-infinite-scroll": "^20.0.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"primeng": "19.1.4",
|
||||
"primeng": "^20.0.1",
|
||||
"quill": "^2.0.3",
|
||||
"rxjs": "^7.8.2",
|
||||
"showdown": "^2.1.0",
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
<i class="pi pi-search"></i>
|
||||
</button>
|
||||
|
||||
<p-overlayPanel #searchDropdown [dismissable]="true" appendTo="body" [style]="{ width: '18rem' }">
|
||||
<p-popover #searchDropdown [dismissable]="true" appendTo="body" [style]="{ width: '18rem' }">
|
||||
<div class="relative w-full">
|
||||
<input
|
||||
type="text"
|
||||
@@ -192,7 +192,7 @@
|
||||
(click)="clearSearch(); searchDropdown.hide()"
|
||||
></p-button>
|
||||
</div>
|
||||
</p-overlayPanel>
|
||||
</p-popover>
|
||||
</div>
|
||||
|
||||
<div class="hidden md:block relative">
|
||||
|
||||
@@ -27,14 +27,12 @@ import {FormsModule} from '@angular/forms';
|
||||
import {BookFilterComponent} from './book-filter/book-filter.component';
|
||||
import {Tooltip} from 'primeng/tooltip';
|
||||
import {EntityViewPreferences, UserService} from '../../../settings/user-management/user.service';
|
||||
import {OverlayPanelModule} from 'primeng/overlaypanel';
|
||||
import {SeriesCollapseFilter} from './filters/SeriesCollapseFilter';
|
||||
import {SideBarFilter} from './filters/SidebarFilter';
|
||||
import {HeaderFilter} from './filters/HeaderFilter';
|
||||
import {CoverScalePreferenceService} from './cover-scale-preference.service';
|
||||
import {BookSorter} from './sorting/BookSorter';
|
||||
import {BookDialogHelperService} from './BookDialogHelperService';
|
||||
import {DropdownModule} from 'primeng/dropdown';
|
||||
import {Checkbox} from 'primeng/checkbox';
|
||||
import {Popover} from 'primeng/popover';
|
||||
import {Slider} from 'primeng/slider';
|
||||
@@ -83,8 +81,8 @@ const SORT_DIRECTION = {
|
||||
styleUrls: ['./book-browser.component.scss'],
|
||||
imports: [
|
||||
Button, VirtualScrollerModule, BookCardComponent, AsyncPipe, ProgressSpinner, Menu, InputText, FormsModule,
|
||||
BookTableComponent, BookFilterComponent, Tooltip, NgClass, PrimeTemplate, NgStyle, OverlayPanelModule,
|
||||
DropdownModule, Checkbox, Popover, Slider, Select, Divider, MultiSelect, TieredMenu
|
||||
BookTableComponent, BookFilterComponent, Tooltip, NgClass, PrimeTemplate, NgStyle, Popover,
|
||||
Checkbox, Slider, Select, Divider, MultiSelect, TieredMenu
|
||||
],
|
||||
providers: [SeriesCollapseFilter],
|
||||
animations: [
|
||||
|
||||
@@ -10,7 +10,6 @@ import {SlicePipe} from '@angular/common';
|
||||
import {Divider} from 'primeng/divider';
|
||||
import {UrlHelperService} from '../../../utilities/service/url-helper.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {OverlayPanelModule} from 'primeng/overlaypanel';
|
||||
import {IconField} from 'primeng/iconfield';
|
||||
import {InputIcon} from 'primeng/inputicon';
|
||||
|
||||
@@ -23,7 +22,6 @@ import {InputIcon} from 'primeng/inputicon';
|
||||
Button,
|
||||
SlicePipe,
|
||||
Divider,
|
||||
OverlayPanelModule,
|
||||
IconField,
|
||||
InputIcon
|
||||
],
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
[ngClass]="{
|
||||
'outlined-input-green': isValueCopied(field.controlName) && !hoveredFields[field.controlName],
|
||||
}">
|
||||
<p-chips formControlName="{{field.controlName}}" addOnBlur="true"></p-chips>
|
||||
<p-autoComplete formControlName="{{field.controlName}}" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" styleClass="w-full" (onBlur)="onAutoCompleteBlur(field.controlName, $event)"></p-autoComplete>
|
||||
</div>
|
||||
<p-button
|
||||
[icon]="isValueSaved(field.controlName) ? 'pi pi-check' : (hoveredFields[field.controlName] && isValueCopied(field.controlName) ? 'pi pi-times' : 'pi pi-arrow-left')"
|
||||
@@ -115,11 +115,12 @@
|
||||
(mouseleave)="onMouseLeave(field.controlName)"/>
|
||||
|
||||
<div class="w-full">
|
||||
<p-chips
|
||||
<p-autoComplete
|
||||
[ngModel]="fetchedMetadata[field.fetchedKey] ?? []"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
[disabled]="true">
|
||||
</p-chips>
|
||||
[disabled]="true"
|
||||
[multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" styleClass="w-full">
|
||||
</p-autoComplete>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -201,7 +202,7 @@
|
||||
<div class="flex items-center py-1">
|
||||
<label for="{{field.controlName}}" class="w-[15%]">{{ field.label }}</label>
|
||||
<div class="flex w-full">
|
||||
<p-chips class="w-full" formControlName="{{field.controlName}}" addOnBlur="true"></p-chips>
|
||||
<p-autoComplete formControlName="{{field.controlName}}" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" styleClass="w-full" (onBlur)="onAutoCompleteBlur(field.controlName, $event)"></p-autoComplete>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import {Tooltip} from 'primeng/tooltip';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {BookMetadata} from '../../book/model/book.model';
|
||||
import {UrlHelperService} from '../../utilities/service/url-helper.service';
|
||||
import {Chips} from 'primeng/chips';
|
||||
import {Textarea} from 'primeng/textarea';
|
||||
import {AutoComplete} from 'primeng/autocomplete';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bookdrop-file-metadata-picker-component',
|
||||
@@ -17,9 +17,9 @@ import {Textarea} from 'primeng/textarea';
|
||||
Tooltip,
|
||||
InputText,
|
||||
NgClass,
|
||||
Chips,
|
||||
FormsModule,
|
||||
Textarea
|
||||
Textarea,
|
||||
AutoComplete
|
||||
],
|
||||
templateUrl: './bookdrop-file-metadata-picker.component.html',
|
||||
styleUrl: './bookdrop-file-metadata-picker.component.scss'
|
||||
@@ -132,6 +132,24 @@ export class BookdropFileMetadataPickerComponent {
|
||||
this.hoveredFields[field] = false;
|
||||
}
|
||||
|
||||
// Handle blur event for AutoComplete to add custom values
|
||||
onAutoCompleteBlur(fieldName: string, event: any) {
|
||||
const inputValue = event.target.value?.trim();
|
||||
if (inputValue) {
|
||||
const currentValue = this.metadataForm.get(fieldName)?.value || [];
|
||||
const values = Array.isArray(currentValue) ? currentValue :
|
||||
typeof currentValue === 'string' && currentValue ? currentValue.split(',').map((v: string) => v.trim()) : [];
|
||||
|
||||
// Add the new value if it's not already in the array
|
||||
if (!values.includes(inputValue)) {
|
||||
values.push(inputValue);
|
||||
this.metadataForm.get(fieldName)?.setValue(values);
|
||||
}
|
||||
// Clear the input
|
||||
event.target.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
resetAll() {
|
||||
if (this.originalMetadata) {
|
||||
this.metadataForm.patchValue({
|
||||
|
||||
@@ -7,7 +7,6 @@ import {LibraryService} from '../../book/service/library.service';
|
||||
import {Library} from '../../book/model/library.model';
|
||||
|
||||
import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
import {DropdownModule} from 'primeng/dropdown';
|
||||
import {FormControl, FormGroup, FormsModule} from '@angular/forms';
|
||||
import {Button} from 'primeng/button';
|
||||
import {Select} from 'primeng/select';
|
||||
@@ -47,7 +46,6 @@ export interface BookdropFileUI {
|
||||
styleUrl: './bookdrop-file-review.component.scss',
|
||||
imports: [
|
||||
ProgressSpinner,
|
||||
DropdownModule,
|
||||
FormsModule,
|
||||
Button,
|
||||
Select,
|
||||
|
||||
@@ -2,7 +2,6 @@ import {Component, inject, OnInit} from '@angular/core';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {Button} from 'primeng/button';
|
||||
import {DropdownModule} from 'primeng/dropdown';
|
||||
|
||||
import {Checkbox} from 'primeng/checkbox';
|
||||
import {ToggleSwitch} from 'primeng/toggleswitch';
|
||||
@@ -23,7 +22,6 @@ import {LibraryService} from '../../../book/service/library.service';
|
||||
imports: [
|
||||
FormsModule,
|
||||
InputText,
|
||||
DropdownModule,
|
||||
Checkbox,
|
||||
ToggleSwitch,
|
||||
Divider,
|
||||
|
||||
@@ -4,7 +4,6 @@ import {FormsModule} from '@angular/forms';
|
||||
import {$t} from '@primeng/themes';
|
||||
import Aura from '@primeng/themes/aura';
|
||||
import {ButtonModule} from 'primeng/button';
|
||||
import {InputSwitchModule} from 'primeng/inputswitch';
|
||||
import {RadioButtonModule} from 'primeng/radiobutton';
|
||||
import {ToggleSwitchModule} from 'primeng/toggleswitch';
|
||||
import {AppConfigService} from '../../../core/service/app-config.service';
|
||||
@@ -27,7 +26,6 @@ interface Palette {
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
InputSwitchModule,
|
||||
ButtonModule,
|
||||
RadioButtonModule,
|
||||
ToggleSwitchModule
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
<p-inputNumber [formControl]="ruleCtrl.get('valueStart')" [min]="0" class="w-full" placeholder="Start Value" [showButtons]="true"></p-inputNumber>
|
||||
<p-inputNumber [formControl]="ruleCtrl.get('valueEnd')" [min]="0" class="w-full" placeholder="End Value" [showButtons]="true"></p-inputNumber>
|
||||
} @else if (numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.type === 'decimal') {
|
||||
<p-inputNumber [formControl]="ruleCtrl.get('valueStart')" mode="decimal" [minFractionDigits]="1" [maxFractionDigits]="1" [min]="0" [max]="numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.max" class="w-full" placeholder="Start Value" [showButtons]="true"></p-inputNumber>
|
||||
<p-inputNumber [formControl]="ruleCtrl.get('valueEnd')" mode="decimal" [minFractionDigits]="1" [maxFractionDigits]="1" [min]="0" [max]="numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.max" class="w-full" placeholder="End Value" [showButtons]="true"></p-inputNumber>
|
||||
<p-inputNumber [formControl]="ruleCtrl.get('valueStart')" mode="decimal" [minFractionDigits]="1" [maxFractionDigits]="1" [min]="0" [max]="numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.max || 10" class="w-full" placeholder="Start Value" [showButtons]="true"></p-inputNumber>
|
||||
<p-inputNumber [formControl]="ruleCtrl.get('valueEnd')" mode="decimal" [minFractionDigits]="1" [maxFractionDigits]="1" [min]="0" [max]="numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.max || 10" class="w-full" placeholder="End Value" [showButtons]="true"></p-inputNumber>
|
||||
} @else {
|
||||
<input pInputText [formControl]="ruleCtrl.get('valueStart')" class="w-full" placeholder="Start Value"/>
|
||||
<input pInputText [formControl]="ruleCtrl.get('valueEnd')" class="w-full" placeholder="End Value"/>
|
||||
@@ -83,7 +83,7 @@
|
||||
} @else if (numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.type === 'number') {
|
||||
<p-inputNumber formControlName="value" class="w-full" mode="decimal" placeholder="Value" [showButtons]="true"></p-inputNumber>
|
||||
} @else if (numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.type === 'decimal') {
|
||||
<p-inputNumber formControlName="value" mode="decimal" [minFractionDigits]="1" [maxFractionDigits]="1" [min]="0" [max]="numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.max" class="w-full" placeholder="Value" [showButtons]="true"></p-inputNumber>
|
||||
<p-inputNumber formControlName="value" mode="decimal" [minFractionDigits]="1" [maxFractionDigits]="1" [min]="0" [max]="numericFieldConfigMap.get(ruleCtrl.get('field')?.value)?.max || 10" class="w-full" placeholder="Value" [showButtons]="true"></p-inputNumber>
|
||||
} @else if (['includes_any', 'includes_all', 'excludes_all'].includes(ruleCtrl.get('operator')?.value)) {
|
||||
@if (ruleCtrl.get('field')?.value === 'readStatus') {
|
||||
<p-multiSelect [options]="readStatusOptions" formControlName="value" display="chip" class="w-full" appendTo="body" placeholder="Select Statuses"></p-multiSelect>
|
||||
@@ -93,7 +93,7 @@
|
||||
<p-multiSelect [options]="libraryOptions" formControlName="value" display="chip" class="w-full" appendTo="body" placeholder="Select Libraries"></p-multiSelect>
|
||||
} @else {
|
||||
<div class="w-full">
|
||||
<p-chips [formControl]="ruleCtrl.get('value')" separator="," placeholder="Enter values (press Enter or comma)" class="w-full"></p-chips>
|
||||
<p-autoComplete [formControl]="ruleCtrl.get('value')" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" styleClass="w-full" placeholder="Enter values (press Enter or comma)" (onBlur)="onAutoCompleteBlur(ruleCtrl.get('value'), $event)"></p-autoComplete>
|
||||
</div>
|
||||
}
|
||||
} @else if (ruleCtrl.get('field')?.value === 'readStatus') {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {AbstractControl, FormArray, FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
|
||||
import {DropdownModule} from 'primeng/dropdown';
|
||||
import {Button} from 'primeng/button';
|
||||
import {NgTemplateOutlet} from '@angular/common';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
@@ -13,8 +12,8 @@ import {Library} from '../book/model/library.model';
|
||||
import {MagicShelfService} from '../magic-shelf.service';
|
||||
import {MessageService} from 'primeng/api';
|
||||
import {DynamicDialogConfig} from 'primeng/dynamicdialog';
|
||||
import {Chips} from 'primeng/chips';
|
||||
import {MultiSelect} from 'primeng/multiselect';
|
||||
import {AutoComplete} from 'primeng/autocomplete';
|
||||
import {EMPTY_CHECK_OPERATORS, MULTI_VALUE_OPERATORS, parseValue, removeNulls, serializeDateRules} from '../magic-shelf-utils';
|
||||
import { IconPickerService } from '../utilities/services/icon-picker.service';
|
||||
|
||||
@@ -88,7 +87,7 @@ export interface GroupRule {
|
||||
name: string;
|
||||
type: 'group';
|
||||
join: 'and' | 'or';
|
||||
rules: Array<Rule | GroupRule>;
|
||||
rules: (Rule | GroupRule)[];
|
||||
}
|
||||
|
||||
export type RuleFormGroup = FormGroup<{
|
||||
@@ -138,15 +137,14 @@ const FIELD_CONFIGS: Record<RuleField, FullFieldConfig> = {
|
||||
standalone: true,
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
DropdownModule,
|
||||
NgTemplateOutlet,
|
||||
InputText,
|
||||
Select,
|
||||
Button,
|
||||
DatePicker,
|
||||
InputNumber,
|
||||
Chips,
|
||||
MultiSelect
|
||||
MultiSelect,
|
||||
AutoComplete
|
||||
]
|
||||
})
|
||||
export class MagicShelfComponent implements OnInit {
|
||||
@@ -327,7 +325,7 @@ export class MagicShelfComponent implements OnInit {
|
||||
return new FormGroup({
|
||||
type: new FormControl<'group'>('group' as 'group'),
|
||||
join: new FormControl<'and' | 'or'>('and' as 'and' | 'or'),
|
||||
rules: new FormArray([] as Array<GroupFormGroup | RuleFormGroup>),
|
||||
rules: new FormArray([] as (GroupFormGroup | RuleFormGroup)[]),
|
||||
}) as GroupFormGroup;
|
||||
}
|
||||
|
||||
@@ -413,6 +411,24 @@ export class MagicShelfComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
// Handle blur event for AutoComplete to add custom values
|
||||
onAutoCompleteBlur(formControl: any, event: any) {
|
||||
const inputValue = event.target.value?.trim();
|
||||
if (inputValue) {
|
||||
const currentValue = formControl.value || [];
|
||||
const values = Array.isArray(currentValue) ? currentValue :
|
||||
typeof currentValue === 'string' && currentValue ? currentValue.split(',').map((v: string) => v.trim()) : [];
|
||||
|
||||
// Add the new value if it's not already in the array
|
||||
if (!values.includes(inputValue)) {
|
||||
values.push(inputValue);
|
||||
formControl.setValue(values);
|
||||
}
|
||||
// Clear the input
|
||||
event.target.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (!this.hasAtLeastOneValidRule(this.group)) {
|
||||
this.messageService.add({severity: 'warn', summary: 'Validation Error', detail: 'You must add at least one valid rule before saving.'});
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<label for="authors">Authors</label>
|
||||
<div class="flex justify-between items-center gap-2">
|
||||
<div class="w-full">
|
||||
<p-chips formControlName="authors" addOnBlur="true"></p-chips>
|
||||
<p-autoComplete formControlName="authors" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" [showClear]="true" (onBlur)="onAutoCompleteBlur('authors', $event)" styleClass="w-full"></p-autoComplete>
|
||||
</div>
|
||||
@if (!book.metadata!['authorsLocked']) {
|
||||
<p-button icon="pi pi-lock-open" [outlined]="true" (onClick)="toggleLock('authors')" severity="success"></p-button>
|
||||
@@ -128,7 +128,7 @@
|
||||
<label for="categories">Categories</label>
|
||||
<div class="flex justify-between items-center gap-2">
|
||||
<div class="w-full">
|
||||
<p-chips formControlName="categories" addOnBlur="true"></p-chips>
|
||||
<p-autoComplete formControlName="categories" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" [showClear]="true" (onBlur)="onAutoCompleteBlur('categories', $event)" styleClass="w-full"></p-autoComplete>
|
||||
</div>
|
||||
@if (!book.metadata!['categoriesLocked']) {
|
||||
<p-button icon="pi pi-lock-open" [outlined]="true" (onClick)="toggleLock('categories')" severity="success"></p-button>
|
||||
|
||||
@@ -21,7 +21,7 @@ import {DialogService} from 'primeng/dynamicdialog';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {MetadataRefreshRequest} from '../../model/request/metadata-refresh-request.model';
|
||||
import {MetadataRefreshType} from '../../model/request/metadata-refresh-type.enum';
|
||||
import {Chips} from 'primeng/chips';
|
||||
import {AutoComplete} from 'primeng/autocomplete';
|
||||
|
||||
@Component({
|
||||
selector: 'app-metadata-editor',
|
||||
@@ -45,7 +45,7 @@ import {Chips} from 'primeng/chips';
|
||||
Tab,
|
||||
TabPanels,
|
||||
TabPanel,
|
||||
Chips
|
||||
AutoComplete
|
||||
]
|
||||
})
|
||||
export class MetadataEditorComponent implements OnInit {
|
||||
@@ -79,6 +79,24 @@ export class MetadataEditorComponent implements OnInit {
|
||||
|
||||
originalMetadata!: BookMetadata;
|
||||
|
||||
// Handle blur event for AutoComplete to add custom values
|
||||
onAutoCompleteBlur(fieldName: string, event: any) {
|
||||
const inputValue = event.target.value?.trim();
|
||||
if (inputValue) {
|
||||
const currentValue = this.metadataForm.get(fieldName)?.value || [];
|
||||
const values = Array.isArray(currentValue) ? currentValue :
|
||||
typeof currentValue === 'string' && currentValue ? currentValue.split(',').map((v: string) => v.trim()) : [];
|
||||
|
||||
// Add the new value if it's not already in the array
|
||||
if (!values.includes(inputValue)) {
|
||||
values.push(inputValue);
|
||||
this.metadataForm.get(fieldName)?.setValue(values);
|
||||
}
|
||||
// Clear the input
|
||||
event.target.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.metadataForm = new FormGroup({
|
||||
title: new FormControl(''),
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<p-button icon="pi pi-lock" [outlined]="true" (onClick)="toggleLock(field.controlName)" severity="warn"></p-button>
|
||||
}
|
||||
<div class="w-full px-4">
|
||||
<p-chips formControlName="{{field.controlName}}" addOnBlur="true"></p-chips>
|
||||
<p-autoComplete formControlName="{{field.controlName}}" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" (onBlur)="onAutoCompleteBlur(field.controlName, $event)" styleClass="w-full"></p-autoComplete>
|
||||
</div>
|
||||
<p-button
|
||||
[icon]="isValueSaved(field.controlName) ? 'pi pi-check' : (hoveredFields[field.controlName] && isValueCopied(field.controlName) ? 'pi pi-times' : 'pi pi-arrow-left')"
|
||||
@@ -103,11 +103,12 @@
|
||||
(mouseleave)="onMouseLeave(field.controlName)"/>
|
||||
|
||||
<div class="w-full px-4">
|
||||
<p-chips
|
||||
<p-autoComplete
|
||||
[ngModel]="fetchedMetadata[field.fetchedKey] ?? []"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
[disabled]="true">
|
||||
</p-chips>
|
||||
[disabled]="true"
|
||||
[multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" styleClass="w-full">
|
||||
</p-autoComplete>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ import {BookService} from '../../../book/service/book.service';
|
||||
import {Textarea} from 'primeng/textarea';
|
||||
import {filter, map} from 'rxjs/operators';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {Chips} from 'primeng/chips';
|
||||
import {AutoComplete} from 'primeng/autocomplete';
|
||||
|
||||
@Component({
|
||||
selector: 'app-metadata-picker',
|
||||
@@ -31,7 +31,7 @@ import {Chips} from 'primeng/chips';
|
||||
Tooltip,
|
||||
AsyncPipe,
|
||||
Textarea,
|
||||
Chips
|
||||
AutoComplete
|
||||
]
|
||||
})
|
||||
export class MetadataPickerComponent implements OnInit {
|
||||
@@ -77,6 +77,24 @@ export class MetadataPickerComponent implements OnInit {
|
||||
@Input() book$!: Observable<Book | null>;
|
||||
@Output() goBack = new EventEmitter<boolean>();
|
||||
|
||||
// Handle blur event for AutoComplete to add custom values
|
||||
onAutoCompleteBlur(fieldName: string, event: any) {
|
||||
const inputValue = event.target.value?.trim();
|
||||
if (inputValue) {
|
||||
const currentValue = this.metadataForm.get(fieldName)?.value || [];
|
||||
const values = Array.isArray(currentValue) ? currentValue :
|
||||
typeof currentValue === 'string' && currentValue ? currentValue.split(',').map((v: string) => v.trim()) : [];
|
||||
|
||||
// Add the new value if it's not already in the array
|
||||
if (!values.includes(inputValue)) {
|
||||
values.push(inputValue);
|
||||
this.metadataForm.get(fieldName)?.setValue(values);
|
||||
}
|
||||
// Clear the input
|
||||
event.target.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
metadataForm: FormGroup;
|
||||
currentBookId!: number;
|
||||
copiedFields: Record<string, boolean> = {};
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<label for="clearAuthors" class="text-sm text-gray-300 cursor-pointer">Clear</label>
|
||||
</div>
|
||||
</label>
|
||||
<p-chips formControlName="authors" [disabled]="clearFields.authors" addOnBlur="true"></p-chips>
|
||||
<p-autoComplete formControlName="authors" [disabled]="clearFields.authors" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" (onBlur)="onAutoCompleteBlur('authors', $event)" styleClass="w-full"></p-autoComplete>
|
||||
</div>
|
||||
|
||||
<!-- Publisher -->
|
||||
@@ -139,7 +139,7 @@
|
||||
<label for="clearGenres" class="text-sm text-gray-300 cursor-pointer">Clear</label>
|
||||
</div>
|
||||
</label>
|
||||
<p-chips formControlName="genres" addOnBlur="true" [disabled]="clearFields.genres"></p-chips>
|
||||
<p-autoComplete formControlName="genres" [disabled]="clearFields.genres" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" (onBlur)="onAutoCompleteBlur('genres', $event)" styleClass="w-full"></p-autoComplete>
|
||||
|
||||
<div class="flex items-center gap-2 mt-2">
|
||||
<p-checkbox
|
||||
|
||||
@@ -4,13 +4,13 @@ import {CommonModule} from '@angular/common';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {Button} from 'primeng/button';
|
||||
import {Tooltip} from 'primeng/tooltip';
|
||||
import {Chips} from 'primeng/chips';
|
||||
import {DatePicker} from 'primeng/datepicker';
|
||||
import {DynamicDialogConfig, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import {MessageService} from 'primeng/api';
|
||||
import {BookService} from '../../book/service/book.service';
|
||||
import {Book, BulkMetadataUpdateRequest} from '../../book/model/book.model';
|
||||
import {Checkbox} from 'primeng/checkbox';
|
||||
import {AutoComplete} from 'primeng/autocomplete';
|
||||
import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
|
||||
@Component({
|
||||
@@ -23,10 +23,10 @@ import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
InputText,
|
||||
Button,
|
||||
Tooltip,
|
||||
Chips,
|
||||
DatePicker,
|
||||
Checkbox,
|
||||
ProgressSpinner
|
||||
ProgressSpinner,
|
||||
AutoComplete
|
||||
],
|
||||
providers: [MessageService],
|
||||
templateUrl: './bulk-metadata-update-component.html',
|
||||
@@ -83,6 +83,24 @@ export class BulkMetadataUpdateComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle blur event for AutoComplete to add custom values
|
||||
onAutoCompleteBlur(fieldName: string, event: any) {
|
||||
const inputValue = event.target.value?.trim();
|
||||
if (inputValue) {
|
||||
const currentValue = this.metadataForm.get(fieldName)?.value || [];
|
||||
const values = Array.isArray(currentValue) ? currentValue :
|
||||
typeof currentValue === 'string' && currentValue ? currentValue.split(',').map((v: string) => v.trim()) : [];
|
||||
|
||||
// Add the new value if it's not already in the array
|
||||
if (!values.includes(inputValue)) {
|
||||
values.push(inputValue);
|
||||
this.metadataForm.get(fieldName)?.setValue(values);
|
||||
}
|
||||
// Clear the input
|
||||
event.target.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (!this.metadataForm.valid) return;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import {FormsModule} from '@angular/forms';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
import {Divider} from 'primeng/divider';
|
||||
import {DropdownModule} from 'primeng/dropdown';
|
||||
import {Select} from 'primeng/select';
|
||||
import {Button} from 'primeng/button';
|
||||
import {Tooltip} from 'primeng/tooltip';
|
||||
@@ -21,7 +20,6 @@ import {InputText} from 'primeng/inputtext';
|
||||
standalone: true,
|
||||
imports: [
|
||||
Divider,
|
||||
DropdownModule,
|
||||
Select,
|
||||
Button,
|
||||
Tooltip,
|
||||
|
||||
Reference in New Issue
Block a user