mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-24 02:05:48 -06:00
Compare commits
1 Commits
95736eebc4
...
feature-au
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e3ff39b0c |
@@ -32,7 +32,7 @@ RUN set -eux \
|
|||||||
# Purpose: Installs s6-overlay and rootfs
|
# Purpose: Installs s6-overlay and rootfs
|
||||||
# Comments:
|
# Comments:
|
||||||
# - Don't leave anything extra in here either
|
# - Don't leave anything extra in here either
|
||||||
FROM ghcr.io/astral-sh/uv:0.9.7-python3.12-bookworm-slim AS s6-overlay-base
|
FROM ghcr.io/astral-sh/uv:0.9.4-python3.12-bookworm-slim AS s6-overlay-base
|
||||||
|
|
||||||
WORKDIR /usr/src/s6
|
WORKDIR /usr/src/s6
|
||||||
|
|
||||||
|
|||||||
@@ -354,13 +354,5 @@ describe('CustomFieldsQueryDropdownComponent', () => {
|
|||||||
model.removeElement(atom)
|
model.removeElement(atom)
|
||||||
expect(completeSpy).toHaveBeenCalled()
|
expect(completeSpy).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should subscribe to existing elements when queries are assigned', () => {
|
|
||||||
const expression = new CustomFieldQueryExpression()
|
|
||||||
const nextSpy = jest.spyOn(model.changed, 'next')
|
|
||||||
model.queries = [expression]
|
|
||||||
expression.changed.next(expression)
|
|
||||||
expect(nextSpy).toHaveBeenCalledWith(model)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
} from '@ng-bootstrap/ng-bootstrap'
|
} from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgSelectComponent, NgSelectModule } from '@ng-select/ng-select'
|
import { NgSelectComponent, NgSelectModule } from '@ng-select/ng-select'
|
||||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { first, Subject, Subscription, takeUntil } from 'rxjs'
|
import { first, Subject, takeUntil } from 'rxjs'
|
||||||
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
|
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
|
||||||
import {
|
import {
|
||||||
CUSTOM_FIELD_QUERY_MAX_ATOMS,
|
CUSTOM_FIELD_QUERY_MAX_ATOMS,
|
||||||
@@ -41,27 +41,10 @@ import { ClearableBadgeComponent } from '../clearable-badge/clearable-badge.comp
|
|||||||
import { DocumentLinkComponent } from '../input/document-link/document-link.component'
|
import { DocumentLinkComponent } from '../input/document-link/document-link.component'
|
||||||
|
|
||||||
export class CustomFieldQueriesModel {
|
export class CustomFieldQueriesModel {
|
||||||
private _queries: CustomFieldQueryElement[] = []
|
public queries: CustomFieldQueryElement[] = []
|
||||||
private rootSubscriptions: Subscription[] = []
|
|
||||||
|
|
||||||
public readonly changed = new Subject<CustomFieldQueriesModel>()
|
public readonly changed = new Subject<CustomFieldQueriesModel>()
|
||||||
|
|
||||||
public get queries(): CustomFieldQueryElement[] {
|
|
||||||
return this._queries
|
|
||||||
}
|
|
||||||
|
|
||||||
public set queries(value: CustomFieldQueryElement[]) {
|
|
||||||
this.teardownRootSubscriptions()
|
|
||||||
this._queries = value ?? []
|
|
||||||
for (const element of this._queries) {
|
|
||||||
this.rootSubscriptions.push(
|
|
||||||
element.changed.subscribe(() => {
|
|
||||||
this.changed.next(this)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear(fireEvent = true) {
|
public clear(fireEvent = true) {
|
||||||
this.queries = []
|
this.queries = []
|
||||||
if (fireEvent) {
|
if (fireEvent) {
|
||||||
@@ -124,14 +107,14 @@ export class CustomFieldQueriesModel {
|
|||||||
public addExpression(
|
public addExpression(
|
||||||
expression: CustomFieldQueryExpression = new CustomFieldQueryExpression()
|
expression: CustomFieldQueryExpression = new CustomFieldQueryExpression()
|
||||||
) {
|
) {
|
||||||
if (this.queries.length === 0) {
|
if (this.queries.length > 0) {
|
||||||
this.queries = [expression]
|
;(
|
||||||
return
|
(this.queries[0] as CustomFieldQueryExpression)
|
||||||
|
.value as CustomFieldQueryElement[]
|
||||||
|
).push(expression)
|
||||||
|
} else {
|
||||||
|
this.queries.push(expression)
|
||||||
}
|
}
|
||||||
;(
|
|
||||||
(this.queries[0] as CustomFieldQueryExpression)
|
|
||||||
.value as CustomFieldQueryElement[]
|
|
||||||
).push(expression)
|
|
||||||
expression.changed.subscribe(() => {
|
expression.changed.subscribe(() => {
|
||||||
this.changed.next(this)
|
this.changed.next(this)
|
||||||
})
|
})
|
||||||
@@ -183,13 +166,6 @@ export class CustomFieldQueriesModel {
|
|||||||
this.changed.next(this)
|
this.changed.next(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private teardownRootSubscriptions() {
|
|
||||||
for (const subscription of this.rootSubscriptions) {
|
|
||||||
subscription.unsubscribe()
|
|
||||||
}
|
|
||||||
this.rootSubscriptions = []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -210,6 +210,7 @@
|
|||||||
<pngx-input-tags
|
<pngx-input-tags
|
||||||
[allowCreate]="false"
|
[allowCreate]="false"
|
||||||
[title]="null"
|
[title]="null"
|
||||||
|
[autoHeirarchy]="false"
|
||||||
formControlName="values"
|
formControlName="values"
|
||||||
></pngx-input-tags>
|
></pngx-input-tags>
|
||||||
} @else if (
|
} @else if (
|
||||||
|
|||||||
@@ -103,6 +103,9 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
|||||||
@Input()
|
@Input()
|
||||||
multiple: boolean = true
|
multiple: boolean = true
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
autoHeirarchy: boolean = true
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
filterDocuments = new EventEmitter<Tag[]>()
|
filterDocuments = new EventEmitter<Tag[]>()
|
||||||
|
|
||||||
@@ -134,7 +137,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
|||||||
oldValue.splice(index, 1)
|
oldValue.splice(index, 1)
|
||||||
|
|
||||||
// remove children
|
// remove children
|
||||||
oldValue = this.removeChildren(oldValue, tag)
|
if (this.autoHeirarchy) oldValue = this.removeChildren(oldValue, tag)
|
||||||
|
|
||||||
this.value = [...oldValue]
|
this.value = [...oldValue]
|
||||||
this.onChange(this.value)
|
this.onChange(this.value)
|
||||||
@@ -153,7 +156,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onAdd(tag: Tag) {
|
public onAdd(tag: Tag) {
|
||||||
if (tag.parent) {
|
if (this.autoHeirarchy && tag.parent) {
|
||||||
// add all parents recursively
|
// add all parents recursively
|
||||||
const parent = this.getTag(tag.parent)
|
const parent = this.getTag(tag.parent)
|
||||||
this.value = [...this.value, parent.id]
|
this.value = [...this.value, parent.id]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { fakeAsync, tick } from '@angular/core/testing'
|
||||||
import {
|
import {
|
||||||
CustomFieldQueryElementType,
|
CustomFieldQueryElementType,
|
||||||
CustomFieldQueryLogicalOperator,
|
CustomFieldQueryLogicalOperator,
|
||||||
@@ -110,38 +111,13 @@ describe('CustomFieldQueryAtom', () => {
|
|||||||
expect(atom.serialize()).toEqual([1, 'operator', 'value'])
|
expect(atom.serialize()).toEqual([1, 'operator', 'value'])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should emit changed on value change immediately', () => {
|
it('should emit changed on value change after debounce', fakeAsync(() => {
|
||||||
const atom = new CustomFieldQueryAtom()
|
const atom = new CustomFieldQueryAtom()
|
||||||
const changeSpy = jest.spyOn(atom.changed, 'next')
|
const changeSpy = jest.spyOn(atom.changed, 'next')
|
||||||
atom.value = 'new value'
|
atom.value = 'new value'
|
||||||
|
tick(1000)
|
||||||
expect(changeSpy).toHaveBeenCalled()
|
expect(changeSpy).toHaveBeenCalled()
|
||||||
})
|
}))
|
||||||
|
|
||||||
it('should ignore duplicate array emissions', () => {
|
|
||||||
const atom = new CustomFieldQueryAtom()
|
|
||||||
atom.operator = CustomFieldQueryOperator.In
|
|
||||||
const changeSpy = jest.fn()
|
|
||||||
atom.changed.subscribe(changeSpy)
|
|
||||||
|
|
||||||
atom.value = [1, 2]
|
|
||||||
expect(changeSpy).toHaveBeenCalledTimes(1)
|
|
||||||
|
|
||||||
changeSpy.mockClear()
|
|
||||||
atom.value = [1, 2]
|
|
||||||
expect(changeSpy).not.toHaveBeenCalled()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should emit when array values differ while length matches', () => {
|
|
||||||
const atom = new CustomFieldQueryAtom()
|
|
||||||
atom.operator = CustomFieldQueryOperator.In
|
|
||||||
const changeSpy = jest.fn()
|
|
||||||
atom.changed.subscribe(changeSpy)
|
|
||||||
|
|
||||||
atom.value = [1, 2]
|
|
||||||
changeSpy.mockClear()
|
|
||||||
atom.value = [1, 3]
|
|
||||||
expect(changeSpy).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('CustomFieldQueryExpression', () => {
|
describe('CustomFieldQueryExpression', () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Subject, distinctUntilChanged } from 'rxjs'
|
import { Subject, debounceTime, distinctUntilChanged } from 'rxjs'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import {
|
import {
|
||||||
CUSTOM_FIELD_QUERY_VALUE_TYPES_BY_OPERATOR,
|
CUSTOM_FIELD_QUERY_VALUE_TYPES_BY_OPERATOR,
|
||||||
@@ -110,22 +110,7 @@ export class CustomFieldQueryAtom extends CustomFieldQueryElement {
|
|||||||
|
|
||||||
protected override connectValueModelChanged(): void {
|
protected override connectValueModelChanged(): void {
|
||||||
this.valueModelChanged
|
this.valueModelChanged
|
||||||
.pipe(
|
.pipe(debounceTime(1000), distinctUntilChanged())
|
||||||
distinctUntilChanged((previous, current) => {
|
|
||||||
if (Array.isArray(previous) && Array.isArray(current)) {
|
|
||||||
if (previous.length !== current.length) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for (let i = 0; i < previous.length; i++) {
|
|
||||||
if (previous[i] !== current[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return previous === current
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.changed.next(this)
|
this.changed.next(this)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user