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
|
||||
# Comments:
|
||||
# - 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
|
||||
|
||||
|
||||
@@ -354,13 +354,5 @@ describe('CustomFieldsQueryDropdownComponent', () => {
|
||||
model.removeElement(atom)
|
||||
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'
|
||||
import { NgSelectComponent, NgSelectModule } from '@ng-select/ng-select'
|
||||
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 {
|
||||
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'
|
||||
|
||||
export class CustomFieldQueriesModel {
|
||||
private _queries: CustomFieldQueryElement[] = []
|
||||
private rootSubscriptions: Subscription[] = []
|
||||
public queries: CustomFieldQueryElement[] = []
|
||||
|
||||
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) {
|
||||
this.queries = []
|
||||
if (fireEvent) {
|
||||
@@ -124,14 +107,14 @@ export class CustomFieldQueriesModel {
|
||||
public addExpression(
|
||||
expression: CustomFieldQueryExpression = new CustomFieldQueryExpression()
|
||||
) {
|
||||
if (this.queries.length === 0) {
|
||||
this.queries = [expression]
|
||||
return
|
||||
if (this.queries.length > 0) {
|
||||
;(
|
||||
(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(() => {
|
||||
this.changed.next(this)
|
||||
})
|
||||
@@ -183,13 +166,6 @@ export class CustomFieldQueriesModel {
|
||||
this.changed.next(this)
|
||||
}
|
||||
}
|
||||
|
||||
private teardownRootSubscriptions() {
|
||||
for (const subscription of this.rootSubscriptions) {
|
||||
subscription.unsubscribe()
|
||||
}
|
||||
this.rootSubscriptions = []
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
<pngx-input-tags
|
||||
[allowCreate]="false"
|
||||
[title]="null"
|
||||
[autoHeirarchy]="false"
|
||||
formControlName="values"
|
||||
></pngx-input-tags>
|
||||
} @else if (
|
||||
|
||||
@@ -103,6 +103,9 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
@Input()
|
||||
multiple: boolean = true
|
||||
|
||||
@Input()
|
||||
autoHeirarchy: boolean = true
|
||||
|
||||
@Output()
|
||||
filterDocuments = new EventEmitter<Tag[]>()
|
||||
|
||||
@@ -134,7 +137,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
oldValue.splice(index, 1)
|
||||
|
||||
// remove children
|
||||
oldValue = this.removeChildren(oldValue, tag)
|
||||
if (this.autoHeirarchy) oldValue = this.removeChildren(oldValue, tag)
|
||||
|
||||
this.value = [...oldValue]
|
||||
this.onChange(this.value)
|
||||
@@ -153,7 +156,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
}
|
||||
|
||||
public onAdd(tag: Tag) {
|
||||
if (tag.parent) {
|
||||
if (this.autoHeirarchy && tag.parent) {
|
||||
// add all parents recursively
|
||||
const parent = this.getTag(tag.parent)
|
||||
this.value = [...this.value, parent.id]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { fakeAsync, tick } from '@angular/core/testing'
|
||||
import {
|
||||
CustomFieldQueryElementType,
|
||||
CustomFieldQueryLogicalOperator,
|
||||
@@ -110,38 +111,13 @@ describe('CustomFieldQueryAtom', () => {
|
||||
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 changeSpy = jest.spyOn(atom.changed, 'next')
|
||||
atom.value = 'new value'
|
||||
tick(1000)
|
||||
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', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Subject, distinctUntilChanged } from 'rxjs'
|
||||
import { Subject, debounceTime, distinctUntilChanged } from 'rxjs'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {
|
||||
CUSTOM_FIELD_QUERY_VALUE_TYPES_BY_OPERATOR,
|
||||
@@ -110,22 +110,7 @@ export class CustomFieldQueryAtom extends CustomFieldQueryElement {
|
||||
|
||||
protected override connectValueModelChanged(): void {
|
||||
this.valueModelChanged
|
||||
.pipe(
|
||||
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
|
||||
})
|
||||
)
|
||||
.pipe(debounceTime(1000), distinctUntilChanged())
|
||||
.subscribe(() => {
|
||||
this.changed.next(this)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user