mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-10-10 02:16:12 -05:00
Lots of cleanup, looking good. Simplify
This commit is contained in:
@@ -188,50 +188,45 @@
|
|||||||
<i-bs name="plus-circle"></i-bs> <span i18n>Add condition</span>
|
<i-bs name="plus-circle"></i-bs> <span i18n>Add condition</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2" formArrayName="conditions">
|
<div class="mt-2 conditions" formArrayName="conditions">
|
||||||
@if (getConditionsFormArray(formGroup).length === 0) {
|
@if (getConditionsFormArray(formGroup).length === 0) {
|
||||||
<p class="text-muted small" i18n>No conditions added. Add one to define document filters.</p>
|
<p class="text-muted small" i18n>No conditions added. Add one to define document filters.</p>
|
||||||
}
|
}
|
||||||
@for (condition of getConditionsFormArray(formGroup).controls; track condition; let conditionIndex = $index) {
|
@for (condition of getConditionsFormArray(formGroup).controls; track condition; let conditionIndex = $index) {
|
||||||
<div [formGroupName]="conditionIndex" class="border rounded p-3 mb-2">
|
<div [formGroupName]="conditionIndex" class="border rounded p-3 mb-2">
|
||||||
<div class="d-flex align-items-start gap-2 mb-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<div class="flex-grow-1">
|
<div class="w-25">
|
||||||
<pngx-input-select
|
<pngx-input-select
|
||||||
i18n-title
|
i18n-title
|
||||||
title="Condition type"
|
|
||||||
[items]="getConditionTypeOptions(formGroup, conditionIndex)"
|
[items]="getConditionTypeOptions(formGroup, conditionIndex)"
|
||||||
formControlName="type"
|
formControlName="type"
|
||||||
[allowNull]="false"
|
[allowNull]="false"
|
||||||
horizontal="true"
|
|
||||||
></pngx-input-select>
|
></pngx-input-select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
@if (isTagsCondition(condition.get('type').value)) {
|
||||||
|
<pngx-input-tags
|
||||||
|
[allowCreate]="false"
|
||||||
|
[title]="null"
|
||||||
|
formControlName="values"
|
||||||
|
></pngx-input-tags>
|
||||||
|
} @else {
|
||||||
|
<pngx-input-select
|
||||||
|
[items]="getConditionSelectItems(condition.get('type').value)"
|
||||||
|
[allowNull]="true"
|
||||||
|
[multiple]="isSelectMultiple(condition.get('type').value)"
|
||||||
|
formControlName="values"
|
||||||
|
></pngx-input-select>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-link text-danger p-0 ms-1"
|
class="btn btn-link text-danger p-0"
|
||||||
(click)="removeCondition(formGroup, conditionIndex)"
|
(click)="removeCondition(formGroup, conditionIndex)"
|
||||||
>
|
>
|
||||||
<i-bs name="trash"></i-bs><span class="ms-1" i18n>Delete</span>
|
<i-bs name="trash"></i-bs><span class="ms-1" i18n>Delete</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@if (isTagsCondition(condition.get('type').value)) {
|
|
||||||
<pngx-input-tags
|
|
||||||
[allowCreate]="false"
|
|
||||||
[title]="getConditionValueLabel(condition.get('type').value)"
|
|
||||||
[hint]="getConditionHint(formGroup, conditionIndex)"
|
|
||||||
formControlName="values"
|
|
||||||
horizontal="true"
|
|
||||||
></pngx-input-tags>
|
|
||||||
} @else {
|
|
||||||
<pngx-input-select
|
|
||||||
[title]="getConditionValueLabel(condition.get('type').value)"
|
|
||||||
[items]="getConditionSelectItems(condition.get('type').value)"
|
|
||||||
[hint]="getConditionHint(formGroup, conditionIndex)"
|
|
||||||
[allowNull]="true"
|
|
||||||
[multiple]="isSelectMultiple(condition.get('type').value)"
|
|
||||||
formControlName="values"
|
|
||||||
horizontal="true"
|
|
||||||
></pngx-input-select>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -7,3 +7,7 @@
|
|||||||
.accordion-button {
|
.accordion-button {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep .conditions .paperless-input-select.mb-3 {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
@@ -150,20 +150,17 @@ export enum TriggerConditionType {
|
|||||||
interface TriggerConditionDefinition {
|
interface TriggerConditionDefinition {
|
||||||
id: TriggerConditionType
|
id: TriggerConditionType
|
||||||
name: string
|
name: string
|
||||||
hint?: string
|
|
||||||
valueLabel: string
|
|
||||||
inputType: 'tags' | 'select'
|
inputType: 'tags' | 'select'
|
||||||
allowMultipleEntries: boolean
|
allowMultipleEntries: boolean
|
||||||
allowMultipleValues: boolean
|
allowMultipleValues: boolean
|
||||||
selectItems?: 'correspondents' | 'documentTypes' | 'storagePaths'
|
selectItems?: 'correspondents' | 'documentTypes' | 'storagePaths'
|
||||||
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
||||||
{
|
{
|
||||||
id: TriggerConditionType.TagsAny,
|
id: TriggerConditionType.TagsAny,
|
||||||
name: $localize`Has any of these tags`,
|
name: $localize`Has any of these tags`,
|
||||||
hint: $localize`Trigger matches when the document has at least one of the selected tags.`,
|
|
||||||
valueLabel: $localize`Tags`,
|
|
||||||
inputType: 'tags',
|
inputType: 'tags',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: true,
|
allowMultipleValues: true,
|
||||||
@@ -171,8 +168,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.TagsAll,
|
id: TriggerConditionType.TagsAll,
|
||||||
name: $localize`Has all of these tags`,
|
name: $localize`Has all of these tags`,
|
||||||
hint: $localize`Trigger matches only when every selected tag is present.`,
|
|
||||||
valueLabel: $localize`Tags`,
|
|
||||||
inputType: 'tags',
|
inputType: 'tags',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: true,
|
allowMultipleValues: true,
|
||||||
@@ -180,8 +175,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.TagsNone,
|
id: TriggerConditionType.TagsNone,
|
||||||
name: $localize`Does not have these tags`,
|
name: $localize`Does not have these tags`,
|
||||||
hint: $localize`Trigger matches only when none of the selected tags are present.`,
|
|
||||||
valueLabel: $localize`Tags`,
|
|
||||||
inputType: 'tags',
|
inputType: 'tags',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: true,
|
allowMultipleValues: true,
|
||||||
@@ -189,8 +182,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.CorrespondentIs,
|
id: TriggerConditionType.CorrespondentIs,
|
||||||
name: $localize`Has correspondent`,
|
name: $localize`Has correspondent`,
|
||||||
hint: $localize`Trigger matches when the document has the selected correspondent.`,
|
|
||||||
valueLabel: $localize`Correspondent`,
|
|
||||||
inputType: 'select',
|
inputType: 'select',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: false,
|
allowMultipleValues: false,
|
||||||
@@ -199,8 +190,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.CorrespondentNot,
|
id: TriggerConditionType.CorrespondentNot,
|
||||||
name: $localize`Does not have correspondents`,
|
name: $localize`Does not have correspondents`,
|
||||||
hint: $localize`Trigger matches when the document does not have any of the selected correspondents.`,
|
|
||||||
valueLabel: $localize`Correspondents`,
|
|
||||||
inputType: 'select',
|
inputType: 'select',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: true,
|
allowMultipleValues: true,
|
||||||
@@ -209,8 +198,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.DocumentTypeIs,
|
id: TriggerConditionType.DocumentTypeIs,
|
||||||
name: $localize`Has document type`,
|
name: $localize`Has document type`,
|
||||||
hint: $localize`Trigger matches when the document has the selected document type.`,
|
|
||||||
valueLabel: $localize`Document type`,
|
|
||||||
inputType: 'select',
|
inputType: 'select',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: false,
|
allowMultipleValues: false,
|
||||||
@@ -219,8 +206,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.DocumentTypeNot,
|
id: TriggerConditionType.DocumentTypeNot,
|
||||||
name: $localize`Does not have document types`,
|
name: $localize`Does not have document types`,
|
||||||
hint: $localize`Trigger matches when the document does not have any of the selected document types.`,
|
|
||||||
valueLabel: $localize`Document types`,
|
|
||||||
inputType: 'select',
|
inputType: 'select',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: true,
|
allowMultipleValues: true,
|
||||||
@@ -229,8 +214,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.StoragePathIs,
|
id: TriggerConditionType.StoragePathIs,
|
||||||
name: $localize`Has storage path`,
|
name: $localize`Has storage path`,
|
||||||
hint: $localize`Trigger matches when the document has the selected storage path.`,
|
|
||||||
valueLabel: $localize`Storage path`,
|
|
||||||
inputType: 'select',
|
inputType: 'select',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: false,
|
allowMultipleValues: false,
|
||||||
@@ -239,8 +222,6 @@ const TRIGGER_CONDITION_DEFINITIONS: TriggerConditionDefinition[] = [
|
|||||||
{
|
{
|
||||||
id: TriggerConditionType.StoragePathNot,
|
id: TriggerConditionType.StoragePathNot,
|
||||||
name: $localize`Does not have storage paths`,
|
name: $localize`Does not have storage paths`,
|
||||||
hint: $localize`Trigger matches when the document does not have any of the selected storage paths.`,
|
|
||||||
valueLabel: $localize`Storage paths`,
|
|
||||||
inputType: 'select',
|
inputType: 'select',
|
||||||
allowMultipleEntries: false,
|
allowMultipleEntries: false,
|
||||||
allowMultipleValues: true,
|
allowMultipleValues: true,
|
||||||
@@ -304,6 +285,11 @@ export class WorkflowEditDialogComponent
|
|||||||
|
|
||||||
private allowedActionTypes = []
|
private allowedActionTypes = []
|
||||||
|
|
||||||
|
private conditionTypeOptionCache = new WeakMap<
|
||||||
|
FormArray,
|
||||||
|
TriggerConditionDefinition[]
|
||||||
|
>()
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.service = inject(WorkflowService)
|
this.service = inject(WorkflowService)
|
||||||
@@ -723,19 +709,30 @@ export class WorkflowEditDialogComponent
|
|||||||
|
|
||||||
getConditionTypeOptions(formGroup: FormGroup, conditionIndex: number) {
|
getConditionTypeOptions(formGroup: FormGroup, conditionIndex: number) {
|
||||||
const conditions = this.getConditionsFormArray(formGroup)
|
const conditions = this.getConditionsFormArray(formGroup)
|
||||||
|
const options = this.getConditionTypeOptionsForArray(conditions)
|
||||||
|
const currentType = conditions.at(conditionIndex).get('type')
|
||||||
|
.value as TriggerConditionType
|
||||||
|
const usedTypes = conditions.controls.map(
|
||||||
|
(control) => control.get('type').value as TriggerConditionType
|
||||||
|
)
|
||||||
|
|
||||||
return this.conditionDefinitions.map((definition) => ({
|
options.forEach((option) => {
|
||||||
id: definition.id,
|
if (option.allowMultipleEntries) {
|
||||||
name: definition.name,
|
option.disabled = false
|
||||||
disabled:
|
return
|
||||||
!definition.allowMultipleEntries &&
|
}
|
||||||
conditions.controls.some((control, idx) => {
|
|
||||||
if (idx === conditionIndex) {
|
const usedElsewhere = usedTypes.some((type, idx) => {
|
||||||
return false
|
if (idx === conditionIndex) {
|
||||||
}
|
return false
|
||||||
return control.get('type').value === definition.id
|
}
|
||||||
}),
|
return type === option.id
|
||||||
}))
|
})
|
||||||
|
|
||||||
|
option.disabled = usedElsewhere && option.id !== currentType
|
||||||
|
})
|
||||||
|
|
||||||
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
canAddCondition(formGroup: FormGroup): boolean {
|
canAddCondition(formGroup: FormGroup): boolean {
|
||||||
@@ -802,17 +799,6 @@ export class WorkflowEditDialogComponent
|
|||||||
return this.getConditionDefinition(type)?.name ?? ''
|
return this.getConditionDefinition(type)?.name ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
getConditionHint(formGroup: FormGroup, conditionIndex: number): string {
|
|
||||||
const conditions = this.getConditionsFormArray(formGroup)
|
|
||||||
const type = conditions.at(conditionIndex).get('type')
|
|
||||||
.value as TriggerConditionType
|
|
||||||
return this.getConditionDefinition(type)?.hint ?? ''
|
|
||||||
}
|
|
||||||
|
|
||||||
getConditionValueLabel(type: TriggerConditionType): string {
|
|
||||||
return this.getConditionDefinition(type)?.valueLabel ?? ''
|
|
||||||
}
|
|
||||||
|
|
||||||
isTagsCondition(type: TriggerConditionType): boolean {
|
isTagsCondition(type: TriggerConditionType): boolean {
|
||||||
return this.getConditionDefinition(type)?.inputType === 'tags'
|
return this.getConditionDefinition(type)?.inputType === 'tags'
|
||||||
}
|
}
|
||||||
@@ -876,6 +862,20 @@ export class WorkflowEditDialogComponent
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getConditionTypeOptionsForArray(
|
||||||
|
conditions: FormArray
|
||||||
|
): TriggerConditionDefinition[] {
|
||||||
|
let cached = this.conditionTypeOptionCache.get(conditions)
|
||||||
|
if (!cached) {
|
||||||
|
cached = this.conditionDefinitions.map((definition) => ({
|
||||||
|
...definition,
|
||||||
|
disabled: false,
|
||||||
|
}))
|
||||||
|
this.conditionTypeOptionCache.set(conditions, cached)
|
||||||
|
}
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
private createTriggerField(
|
private createTriggerField(
|
||||||
trigger: WorkflowTrigger,
|
trigger: WorkflowTrigger,
|
||||||
emitEvent: boolean = false
|
emitEvent: boolean = false
|
||||||
|
@@ -1,66 +1,68 @@
|
|||||||
<div class="mb-3 paperless-input-select" [class.disabled]="disabled">
|
<div class="mb-3 paperless-input-select" [class.disabled]="disabled">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="d-flex align-items-center position-relative hidden-button-container" [class.col-md-3]="horizontal">
|
@if (title || removable) {
|
||||||
@if (title) {
|
<div class="d-flex align-items-center position-relative hidden-button-container" [class.col-md-3]="horizontal">
|
||||||
<label class="form-label" [class.mb-md-0]="horizontal" [for]="inputId">{{title}}</label>
|
@if (title) {
|
||||||
}
|
<label class="form-label" [class.mb-md-0]="horizontal" [for]="inputId">{{title}}</label>
|
||||||
@if (removable) {
|
}
|
||||||
<button type="button" class="btn btn-sm btn-danger position-absolute left-0" (click)="removed.emit(this)">
|
@if (removable) {
|
||||||
<i-bs name="x"></i-bs> <ng-container i18n>Remove</ng-container>
|
<button type="button" class="btn btn-sm btn-danger position-absolute left-0" (click)="removed.emit(this)">
|
||||||
|
<i-bs name="x"></i-bs> <ng-container i18n>Remove</ng-container>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div [class.col-md-9]="horizontal">
|
||||||
|
<div [class.input-group]="allowCreateNew || showFilter" [class.is-invalid]="error">
|
||||||
|
<ng-select name="inputId" [(ngModel)]="value"
|
||||||
|
[disabled]="disabled"
|
||||||
|
[style.color]="textColor"
|
||||||
|
[style.background]="backgroundColor"
|
||||||
|
[class.private]="isPrivate"
|
||||||
|
[clearable]="allowNull"
|
||||||
|
[items]="items"
|
||||||
|
[addTag]="allowCreateNew && addItemRef"
|
||||||
|
addTagText="Add item"
|
||||||
|
i18n-addTagText="Used for both types, correspondents, storage paths"
|
||||||
|
[placeholder]="placeholder"
|
||||||
|
[notFoundText]="notFoundText"
|
||||||
|
[multiple]="multiple"
|
||||||
|
[bindLabel]="bindLabel"
|
||||||
|
bindValue="id"
|
||||||
|
(change)="onChange(value)"
|
||||||
|
(search)="onSearch($event)"
|
||||||
|
(focus)="clearLastSearchTerm()"
|
||||||
|
(clear)="clearLastSearchTerm()"
|
||||||
|
(blur)="onBlur()">
|
||||||
|
<ng-template ng-option-tmp let-item="item">
|
||||||
|
<span [title]="item[bindLabel]">{{item[bindLabel]}}</span>
|
||||||
|
</ng-template>
|
||||||
|
</ng-select>
|
||||||
|
@if (allowCreateNew && !hideAddButton) {
|
||||||
|
<button class="btn btn-outline-secondary" type="button" (click)="addItem()" [disabled]="disabled">
|
||||||
|
<i-bs width="1.2em" height="1.2em" name="plus"></i-bs>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@if (showFilter) {
|
||||||
|
<button class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="isPrivate || this.value === null" title="{{ filterButtonTitle }}">
|
||||||
|
<i-bs width="1.2em" height="1.2em" name="filter"></i-bs>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div [class.col-md-9]="horizontal">
|
<div class="invalid-feedback">
|
||||||
<div [class.input-group]="allowCreateNew || showFilter" [class.is-invalid]="error">
|
{{error}}
|
||||||
<ng-select name="inputId" [(ngModel)]="value"
|
|
||||||
[disabled]="disabled"
|
|
||||||
[style.color]="textColor"
|
|
||||||
[style.background]="backgroundColor"
|
|
||||||
[class.private]="isPrivate"
|
|
||||||
[clearable]="allowNull"
|
|
||||||
[items]="items"
|
|
||||||
[addTag]="allowCreateNew && addItemRef"
|
|
||||||
addTagText="Add item"
|
|
||||||
i18n-addTagText="Used for both types, correspondents, storage paths"
|
|
||||||
[placeholder]="placeholder"
|
|
||||||
[notFoundText]="notFoundText"
|
|
||||||
[multiple]="multiple"
|
|
||||||
[bindLabel]="bindLabel"
|
|
||||||
bindValue="id"
|
|
||||||
(change)="onChange(value)"
|
|
||||||
(search)="onSearch($event)"
|
|
||||||
(focus)="clearLastSearchTerm()"
|
|
||||||
(clear)="clearLastSearchTerm()"
|
|
||||||
(blur)="onBlur()">
|
|
||||||
<ng-template ng-option-tmp let-item="item">
|
|
||||||
<span [title]="item[bindLabel]">{{item[bindLabel]}}</span>
|
|
||||||
</ng-template>
|
|
||||||
</ng-select>
|
|
||||||
@if (allowCreateNew && !hideAddButton) {
|
|
||||||
<button class="btn btn-outline-secondary" type="button" (click)="addItem()" [disabled]="disabled">
|
|
||||||
<i-bs width="1.2em" height="1.2em" name="plus"></i-bs>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
@if (showFilter) {
|
|
||||||
<button class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="isPrivate || this.value === null" title="{{ filterButtonTitle }}">
|
|
||||||
<i-bs width="1.2em" height="1.2em" name="filter"></i-bs>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{{error}}
|
|
||||||
</div>
|
|
||||||
@if (hint) {
|
|
||||||
<small class="form-text text-muted">{{hint}}</small>
|
|
||||||
}
|
|
||||||
@if (getSuggestions().length > 0) {
|
|
||||||
<small>
|
|
||||||
<span i18n>Suggestions:</span>
|
|
||||||
@for (s of getSuggestions(); track s) {
|
|
||||||
<a (click)="value = s.id; onChange(value)" [routerLink]="[]">{{s.name}}</a>
|
|
||||||
}
|
|
||||||
</small>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
@if (hint) {
|
||||||
|
<small class="form-text text-muted">{{hint}}</small>
|
||||||
|
}
|
||||||
|
@if (getSuggestions().length > 0) {
|
||||||
|
<small>
|
||||||
|
<span i18n>Suggestions:</span>
|
||||||
|
@for (s of getSuggestions(); track s) {
|
||||||
|
<a (click)="value = s.id; onChange(value)" [routerLink]="[]">{{s.name}}</a>
|
||||||
|
}
|
||||||
|
</small>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
<div class="mb-3 paperless-input-select paperless-input-tags" [class.disabled]="disabled" [class.pb-3]="getSuggestions().length > 0">
|
<div class="mb-3 paperless-input-select paperless-input-tags" [class.disabled]="disabled" [class.pb-3]="getSuggestions().length > 0">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="d-flex align-items-center" [class.col-md-3]="horizontal">
|
@if (title) {
|
||||||
<label class="form-label" [class.mb-md-0]="horizontal" for="tags">{{title}}</label>
|
<div class="d-flex align-items-center" [class.col-md-3]="horizontal">
|
||||||
</div>
|
<label class="form-label" [class.mb-md-0]="horizontal" for="tags">{{title}}</label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<div class="position-relative" [class.col-md-9]="horizontal">
|
<div class="position-relative" [class.col-md-9]="horizontal">
|
||||||
<div class="input-group flex-nowrap">
|
<div class="input-group flex-nowrap">
|
||||||
<ng-select #tagSelect name="tags" [items]="tags" bindLabel="name" bindValue="id" [(ngModel)]="value"
|
<ng-select #tagSelect name="tags" [items]="tags" bindLabel="name" bindValue="id" [(ngModel)]="value"
|
||||||
|
Reference in New Issue
Block a user