Gotta start somewhere
This commit is contained in:
parent
d7ba6d98d3
commit
f0157a36fb
@ -108,6 +108,7 @@ import { FileDropComponent } from './components/file-drop/file-drop.component'
|
|||||||
import { CustomFieldsComponent } from './components/manage/custom-fields/custom-fields.component'
|
import { CustomFieldsComponent } from './components/manage/custom-fields/custom-fields.component'
|
||||||
import { CustomFieldEditDialogComponent } from './components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
import { CustomFieldEditDialogComponent } from './components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||||
import { CustomFieldsDropdownComponent } from './components/common/custom-fields-dropdown/custom-fields-dropdown.component'
|
import { CustomFieldsDropdownComponent } from './components/common/custom-fields-dropdown/custom-fields-dropdown.component'
|
||||||
|
import { CustomFieldsLookupDropdownComponent } from './components/common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component'
|
||||||
import { ProfileEditDialogComponent } from './components/common/profile-edit-dialog/profile-edit-dialog.component'
|
import { ProfileEditDialogComponent } from './components/common/profile-edit-dialog/profile-edit-dialog.component'
|
||||||
import { PdfViewerModule } from 'ng2-pdf-viewer'
|
import { PdfViewerModule } from 'ng2-pdf-viewer'
|
||||||
import { DocumentLinkComponent } from './components/common/input/document-link/document-link.component'
|
import { DocumentLinkComponent } from './components/common/input/document-link/document-link.component'
|
||||||
@ -485,6 +486,7 @@ function initializeApp(settings: SettingsService) {
|
|||||||
CustomFieldsComponent,
|
CustomFieldsComponent,
|
||||||
CustomFieldEditDialogComponent,
|
CustomFieldEditDialogComponent,
|
||||||
CustomFieldsDropdownComponent,
|
CustomFieldsDropdownComponent,
|
||||||
|
CustomFieldsLookupDropdownComponent,
|
||||||
ProfileEditDialogComponent,
|
ProfileEditDialogComponent,
|
||||||
DocumentLinkComponent,
|
DocumentLinkComponent,
|
||||||
PreviewPopupComponent,
|
PreviewPopupComponent,
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
<div class="btn-group w-100" ngbDropdown role="group" #dropdown="ngbDropdown">
|
||||||
|
<button class="btn btn-sm btn-outline-primary" id="dropdown_{{name}}" ngbDropdownToggle [disabled]="disabled">
|
||||||
|
<i-bs name="{{icon}}"></i-bs>
|
||||||
|
<div class="d-none d-sm-inline"> {{title}}</div>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu shadow" ngbDropdownMenu attr.aria-labelledby="dropdown_{{name}}">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary ms-3" (click)="addQuery()" [disabled]="disabled">
|
||||||
|
<i-bs name="plus"></i-bs> Add query
|
||||||
|
</button>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
@for (query of selectionModel.queries; track query; let i = $index) {
|
||||||
|
<div class="list-group-item d-flex">
|
||||||
|
<div class="input-group input-group-sm flex-shrink-1 flex-nowrap">
|
||||||
|
<ng-select
|
||||||
|
class="w-50"
|
||||||
|
[items]="customFields"
|
||||||
|
[(ngModel)]="query.field"
|
||||||
|
[disabled]="disabled"
|
||||||
|
bindLabel="name"
|
||||||
|
bindValue="id"
|
||||||
|
></ng-select>
|
||||||
|
<select class="w-25 form-control" [(ngModel)]="query.operator" [disabled]="disabled">
|
||||||
|
<option *ngFor="let operator of getOperatorsForField(query.field)" [ngValue]="operator">{{operator}}</option>
|
||||||
|
</select>
|
||||||
|
@switch (query.operator) {
|
||||||
|
@case ('exists') {
|
||||||
|
<select class="w-25 form-control" [(ngModel)]="query.value" [disabled]="disabled">
|
||||||
|
<option value="true" i18n>true</option>
|
||||||
|
<option value="false" i18n>false</option>
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
@default {
|
||||||
|
<input class="w-25 form-control" type="text" [(ngModel)]="query.value" [disabled]="disabled">
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-link btn-sm pe-0" type="button" (click)="removeQuery(i)" [disabled]="disabled">
|
||||||
|
<i-bs name="x"></i-bs>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,8 @@
|
|||||||
|
.dropdown-menu {
|
||||||
|
width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .ng-select-container {
|
||||||
|
border-top-right-radius: 0 !important;
|
||||||
|
border-bottom-right-radius: 0 !important;
|
||||||
|
}
|
@ -0,0 +1,158 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
||||||
|
import { Subject, first, takeUntil } from 'rxjs'
|
||||||
|
import { CustomField } from 'src/app/data/custom-field'
|
||||||
|
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||||
|
|
||||||
|
export class CustomFieldQuery {
|
||||||
|
public changed = new Subject<CustomFieldQuery>()
|
||||||
|
|
||||||
|
private _field: string
|
||||||
|
set field(value: string) {
|
||||||
|
this._field = value
|
||||||
|
this.changed.next(this)
|
||||||
|
}
|
||||||
|
get field(): string {
|
||||||
|
return this._field
|
||||||
|
}
|
||||||
|
|
||||||
|
private _operator: string
|
||||||
|
set operator(value: string) {
|
||||||
|
this._operator = value
|
||||||
|
this.changed.next(this)
|
||||||
|
}
|
||||||
|
get operator(): string {
|
||||||
|
return this._operator
|
||||||
|
}
|
||||||
|
|
||||||
|
private _value: string
|
||||||
|
set value(value: string) {
|
||||||
|
this._value = value
|
||||||
|
this.changed.next(this)
|
||||||
|
}
|
||||||
|
get value(): string {
|
||||||
|
return this._value
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
field: string = null,
|
||||||
|
operator: string = null,
|
||||||
|
value: string = null
|
||||||
|
) {
|
||||||
|
this.field = field
|
||||||
|
this.operator = operator
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomFieldQueriesModel {
|
||||||
|
// matchingModel: MatchingModel
|
||||||
|
queries: CustomFieldQuery[] = []
|
||||||
|
|
||||||
|
changed = new Subject<CustomFieldQueriesModel>()
|
||||||
|
|
||||||
|
public clear(fireEvent = true) {
|
||||||
|
this.queries = []
|
||||||
|
if (fireEvent) {
|
||||||
|
this.changed.next(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public addQuery(query: CustomFieldQuery = new CustomFieldQuery()) {
|
||||||
|
this.queries.push(query)
|
||||||
|
query.changed.subscribe(() => {
|
||||||
|
if (query.field && query.operator && query.value) {
|
||||||
|
this.changed.next(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeQuery(index: number) {
|
||||||
|
const query = this.queries.splice(index, 1)[0]
|
||||||
|
query.changed.complete()
|
||||||
|
this.changed.next(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'pngx-custom-fields-lookup-dropdown',
|
||||||
|
templateUrl: './custom-fields-lookup-dropdown.component.html',
|
||||||
|
styleUrls: ['./custom-fields-lookup-dropdown.component.scss'],
|
||||||
|
})
|
||||||
|
export class CustomFieldsLookupDropdownComponent {
|
||||||
|
@Input()
|
||||||
|
title: string
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
filterPlaceholder: string = ''
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
icon: string
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
allowSelectNone: boolean = false
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
editing = false
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
applyOnClose = false
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return this.title ? this.title.replace(/\s/g, '_').toLowerCase() : null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean = false
|
||||||
|
|
||||||
|
_selectionModel: CustomFieldQueriesModel = new CustomFieldQueriesModel()
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set selectionModel(model: CustomFieldQueriesModel) {
|
||||||
|
model.changed.subscribe((updatedModel) => {
|
||||||
|
this.selectionModelChange.next(updatedModel)
|
||||||
|
})
|
||||||
|
this._selectionModel = model
|
||||||
|
}
|
||||||
|
|
||||||
|
get selectionModel(): CustomFieldQueriesModel {
|
||||||
|
return this._selectionModel
|
||||||
|
}
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
selectionModelChange = new EventEmitter<CustomFieldQueriesModel>()
|
||||||
|
|
||||||
|
customFields: CustomField[] = []
|
||||||
|
|
||||||
|
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||||
|
|
||||||
|
constructor(protected customFieldsService: CustomFieldsService) {
|
||||||
|
this.getFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.unsubscribeNotifier.next(this)
|
||||||
|
this.unsubscribeNotifier.complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFields() {
|
||||||
|
this.customFieldsService
|
||||||
|
.listAll()
|
||||||
|
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||||
|
.subscribe((result) => {
|
||||||
|
this.customFields = result.results
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public addQuery() {
|
||||||
|
this.selectionModel.addQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeQuery(index: number) {
|
||||||
|
this.selectionModel.removeQuery(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
getOperatorsForField(field: CustomField): string[] {
|
||||||
|
return ['exact', 'in', 'isnull', 'exists']
|
||||||
|
// TODO: implement this
|
||||||
|
}
|
||||||
|
}
|
@ -86,15 +86,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@if (permissionsService.currentUserCan(PermissionAction.View, PermissionType.CustomField) && customFields.length > 0) {
|
@if (permissionsService.currentUserCan(PermissionAction.View, PermissionType.CustomField) && customFields.length > 0) {
|
||||||
<pngx-filterable-dropdown class="flex-fill" title="Custom fields" icon="ui-radios" i18n-title
|
<pngx-custom-fields-lookup-dropdown class="flex-fill" title="Custom fields" icon="ui-radios" i18n-title
|
||||||
filterPlaceholder="Filter custom fields" i18n-filterPlaceholder
|
[(selectionModel)]="customFieldQueriesModel"
|
||||||
[items]="customFields"
|
|
||||||
[manyToOne]="true"
|
|
||||||
[(selectionModel)]="customFieldSelectionModel"
|
|
||||||
(selectionModelChange)="updateRules()"
|
(selectionModelChange)="updateRules()"
|
||||||
(opened)="onCustomFieldsDropdownOpen()"
|
></pngx-custom-fields-lookup-dropdown>
|
||||||
[documentCounts]="customFieldDocumentCounts"
|
|
||||||
[allowSelectNone]="true"></pngx-filterable-dropdown>
|
|
||||||
}
|
}
|
||||||
<pngx-dates-dropdown
|
<pngx-dates-dropdown
|
||||||
title="Dates" i18n-title
|
title="Dates" i18n-title
|
||||||
|
@ -839,9 +839,7 @@ describe('FilterEditorComponent', () => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
it('should ingest filter rules for has all custom fields', fakeAsync(() => {
|
it('should ingest filter rules for has all custom fields', fakeAsync(() => {
|
||||||
expect(component.customFieldSelectionModel.getSelectedItems()).toHaveLength(
|
expect(component.customFieldQueriesModel.getSelectedItems()).toHaveLength(0)
|
||||||
0
|
|
||||||
)
|
|
||||||
component.filterRules = [
|
component.filterRules = [
|
||||||
{
|
{
|
||||||
rule_type: FILTER_HAS_CUSTOM_FIELDS_ALL,
|
rule_type: FILTER_HAS_CUSTOM_FIELDS_ALL,
|
||||||
@ -852,10 +850,10 @@ describe('FilterEditorComponent', () => {
|
|||||||
value: '43',
|
value: '43',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
expect(component.customFieldSelectionModel.logicalOperator).toEqual(
|
expect(component.customFieldQueriesModel.logicalOperator).toEqual(
|
||||||
LogicalOperator.And
|
LogicalOperator.And
|
||||||
)
|
)
|
||||||
expect(component.customFieldSelectionModel.getSelectedItems()).toEqual(
|
expect(component.customFieldQueriesModel.getSelectedItems()).toEqual(
|
||||||
custom_fields
|
custom_fields
|
||||||
)
|
)
|
||||||
// coverage
|
// coverage
|
||||||
@ -869,9 +867,7 @@ describe('FilterEditorComponent', () => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
it('should ingest filter rules for has any custom fields', fakeAsync(() => {
|
it('should ingest filter rules for has any custom fields', fakeAsync(() => {
|
||||||
expect(component.customFieldSelectionModel.getSelectedItems()).toHaveLength(
|
expect(component.customFieldQueriesModel.getSelectedItems()).toHaveLength(0)
|
||||||
0
|
|
||||||
)
|
|
||||||
component.filterRules = [
|
component.filterRules = [
|
||||||
{
|
{
|
||||||
rule_type: FILTER_HAS_CUSTOM_FIELDS_ANY,
|
rule_type: FILTER_HAS_CUSTOM_FIELDS_ANY,
|
||||||
@ -882,10 +878,10 @@ describe('FilterEditorComponent', () => {
|
|||||||
value: '43',
|
value: '43',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
expect(component.customFieldSelectionModel.logicalOperator).toEqual(
|
expect(component.customFieldQueriesModel.logicalOperator).toEqual(
|
||||||
LogicalOperator.Or
|
LogicalOperator.Or
|
||||||
)
|
)
|
||||||
expect(component.customFieldSelectionModel.getSelectedItems()).toEqual(
|
expect(component.customFieldQueriesModel.getSelectedItems()).toEqual(
|
||||||
custom_fields
|
custom_fields
|
||||||
)
|
)
|
||||||
// coverage
|
// coverage
|
||||||
@ -898,25 +894,19 @@ describe('FilterEditorComponent', () => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
it('should ingest filter rules for has any custom field', fakeAsync(() => {
|
it('should ingest filter rules for has any custom field', fakeAsync(() => {
|
||||||
expect(component.customFieldSelectionModel.getSelectedItems()).toHaveLength(
|
expect(component.customFieldQueriesModel.getSelectedItems()).toHaveLength(0)
|
||||||
0
|
|
||||||
)
|
|
||||||
component.filterRules = [
|
component.filterRules = [
|
||||||
{
|
{
|
||||||
rule_type: FILTER_HAS_ANY_CUSTOM_FIELDS,
|
rule_type: FILTER_HAS_ANY_CUSTOM_FIELDS,
|
||||||
value: '1',
|
value: '1',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
expect(component.customFieldSelectionModel.getSelectedItems()).toHaveLength(
|
expect(component.customFieldQueriesModel.getSelectedItems()).toHaveLength(1)
|
||||||
1
|
expect(component.customFieldQueriesModel.get(null)).toBeTruthy()
|
||||||
)
|
|
||||||
expect(component.customFieldSelectionModel.get(null)).toBeTruthy()
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
it('should ingest filter rules for exclude tag(s)', fakeAsync(() => {
|
it('should ingest filter rules for exclude tag(s)', fakeAsync(() => {
|
||||||
expect(component.customFieldSelectionModel.getExcludedItems()).toHaveLength(
|
expect(component.customFieldQueriesModel.getExcludedItems()).toHaveLength(0)
|
||||||
0
|
|
||||||
)
|
|
||||||
component.filterRules = [
|
component.filterRules = [
|
||||||
{
|
{
|
||||||
rule_type: FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS,
|
rule_type: FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS,
|
||||||
@ -927,10 +917,10 @@ describe('FilterEditorComponent', () => {
|
|||||||
value: '43',
|
value: '43',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
expect(component.customFieldSelectionModel.logicalOperator).toEqual(
|
expect(component.customFieldQueriesModel.logicalOperator).toEqual(
|
||||||
LogicalOperator.And
|
LogicalOperator.And
|
||||||
)
|
)
|
||||||
expect(component.customFieldSelectionModel.getExcludedItems()).toEqual(
|
expect(component.customFieldQueriesModel.getExcludedItems()).toEqual(
|
||||||
custom_fields
|
custom_fields
|
||||||
)
|
)
|
||||||
// coverage
|
// coverage
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
import { Tag } from 'src/app/data/tag'
|
import { Tag } from 'src/app/data/tag'
|
||||||
import { Correspondent } from 'src/app/data/correspondent'
|
import { Correspondent } from 'src/app/data/correspondent'
|
||||||
import { DocumentType } from 'src/app/data/document-type'
|
import { DocumentType } from 'src/app/data/document-type'
|
||||||
import { Observable, Subject, Subscription, from } from 'rxjs'
|
import { Observable, Subject, from } from 'rxjs'
|
||||||
import {
|
import {
|
||||||
catchError,
|
catchError,
|
||||||
debounceTime,
|
debounceTime,
|
||||||
@ -63,6 +63,7 @@ import {
|
|||||||
FILTER_HAS_CUSTOM_FIELDS_ALL,
|
FILTER_HAS_CUSTOM_FIELDS_ALL,
|
||||||
FILTER_HAS_ANY_CUSTOM_FIELDS,
|
FILTER_HAS_ANY_CUSTOM_FIELDS,
|
||||||
FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS,
|
FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS,
|
||||||
|
FILTER_CUSTOM_FIELDS_LOOKUP,
|
||||||
} from 'src/app/data/filter-rule-type'
|
} from 'src/app/data/filter-rule-type'
|
||||||
import {
|
import {
|
||||||
FilterableDropdownSelectionModel,
|
FilterableDropdownSelectionModel,
|
||||||
@ -92,13 +93,16 @@ import { ComponentWithPermissions } from '../../with-permissions/with-permission
|
|||||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||||
import { CustomField } from 'src/app/data/custom-field'
|
import { CustomField } from 'src/app/data/custom-field'
|
||||||
import { SearchService } from 'src/app/services/rest/search.service'
|
import { SearchService } from 'src/app/services/rest/search.service'
|
||||||
|
import {
|
||||||
|
CustomFieldQueriesModel,
|
||||||
|
CustomFieldQuery,
|
||||||
|
} from '../../common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component'
|
||||||
|
|
||||||
const TEXT_FILTER_TARGET_TITLE = 'title'
|
const TEXT_FILTER_TARGET_TITLE = 'title'
|
||||||
const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content'
|
const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content'
|
||||||
const TEXT_FILTER_TARGET_ASN = 'asn'
|
const TEXT_FILTER_TARGET_ASN = 'asn'
|
||||||
const TEXT_FILTER_TARGET_FULLTEXT_QUERY = 'fulltext-query'
|
const TEXT_FILTER_TARGET_FULLTEXT_QUERY = 'fulltext-query'
|
||||||
const TEXT_FILTER_TARGET_FULLTEXT_MORELIKE = 'fulltext-morelike'
|
const TEXT_FILTER_TARGET_FULLTEXT_MORELIKE = 'fulltext-morelike'
|
||||||
const TEXT_FILTER_TARGET_CUSTOM_FIELDS = 'custom-fields'
|
|
||||||
|
|
||||||
const TEXT_FILTER_MODIFIER_EQUALS = 'equals'
|
const TEXT_FILTER_MODIFIER_EQUALS = 'equals'
|
||||||
const TEXT_FILTER_MODIFIER_NULL = 'is null'
|
const TEXT_FILTER_MODIFIER_NULL = 'is null'
|
||||||
@ -134,10 +138,6 @@ const DEFAULT_TEXT_FILTER_TARGET_OPTIONS = [
|
|||||||
name: $localize`Title & content`,
|
name: $localize`Title & content`,
|
||||||
},
|
},
|
||||||
{ id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` },
|
{ id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` },
|
||||||
{
|
|
||||||
id: TEXT_FILTER_TARGET_CUSTOM_FIELDS,
|
|
||||||
name: $localize`Custom fields`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: TEXT_FILTER_TARGET_FULLTEXT_QUERY,
|
id: TEXT_FILTER_TARGET_FULLTEXT_QUERY,
|
||||||
name: $localize`Advanced search`,
|
name: $localize`Advanced search`,
|
||||||
@ -321,7 +321,7 @@ export class FilterEditorComponent
|
|||||||
correspondentSelectionModel = new FilterableDropdownSelectionModel()
|
correspondentSelectionModel = new FilterableDropdownSelectionModel()
|
||||||
documentTypeSelectionModel = new FilterableDropdownSelectionModel()
|
documentTypeSelectionModel = new FilterableDropdownSelectionModel()
|
||||||
storagePathSelectionModel = new FilterableDropdownSelectionModel()
|
storagePathSelectionModel = new FilterableDropdownSelectionModel()
|
||||||
customFieldSelectionModel = new FilterableDropdownSelectionModel()
|
customFieldQueriesModel = new CustomFieldQueriesModel()
|
||||||
|
|
||||||
dateCreatedBefore: string
|
dateCreatedBefore: string
|
||||||
dateCreatedAfter: string
|
dateCreatedAfter: string
|
||||||
@ -356,7 +356,7 @@ export class FilterEditorComponent
|
|||||||
this.storagePathSelectionModel.clear(false)
|
this.storagePathSelectionModel.clear(false)
|
||||||
this.tagSelectionModel.clear(false)
|
this.tagSelectionModel.clear(false)
|
||||||
this.correspondentSelectionModel.clear(false)
|
this.correspondentSelectionModel.clear(false)
|
||||||
this.customFieldSelectionModel.clear(false)
|
this.customFieldQueriesModel.clear(false)
|
||||||
this._textFilter = null
|
this._textFilter = null
|
||||||
this._moreLikeId = null
|
this._moreLikeId = null
|
||||||
this.dateAddedBefore = null
|
this.dateAddedBefore = null
|
||||||
@ -383,8 +383,7 @@ export class FilterEditorComponent
|
|||||||
this.textFilterTarget = TEXT_FILTER_TARGET_ASN
|
this.textFilterTarget = TEXT_FILTER_TARGET_ASN
|
||||||
break
|
break
|
||||||
case FILTER_CUSTOM_FIELDS_TEXT:
|
case FILTER_CUSTOM_FIELDS_TEXT:
|
||||||
this._textFilter = rule.value
|
console.log('FILTER_CUSTOM_FIELDS_TEXT', rule.value)
|
||||||
this.textFilterTarget = TEXT_FILTER_TARGET_CUSTOM_FIELDS
|
|
||||||
break
|
break
|
||||||
case FILTER_FULLTEXT_QUERY:
|
case FILTER_FULLTEXT_QUERY:
|
||||||
let allQueryArgs = rule.value.split(',')
|
let allQueryArgs = rule.value.split(',')
|
||||||
@ -523,35 +522,28 @@ export class FilterEditorComponent
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case FILTER_HAS_CUSTOM_FIELDS_ALL:
|
case FILTER_CUSTOM_FIELDS_LOOKUP:
|
||||||
this.customFieldSelectionModel.logicalOperator = LogicalOperator.And
|
// TODO: fully implement
|
||||||
this.customFieldSelectionModel.set(
|
const query = JSON.parse(rule.value)
|
||||||
rule.value ? +rule.value : null,
|
this.customFieldQueriesModel.addQuery(
|
||||||
ToggleableItemState.Selected,
|
new CustomFieldQuery(query[0], query[1], query[2])
|
||||||
false
|
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
case FILTER_HAS_CUSTOM_FIELDS_ALL:
|
||||||
|
console.log('FILTER_HAS_CUSTOM_FIELDS_ALL', rule.value)
|
||||||
|
// TODO: fully implement
|
||||||
|
break
|
||||||
case FILTER_HAS_CUSTOM_FIELDS_ANY:
|
case FILTER_HAS_CUSTOM_FIELDS_ANY:
|
||||||
this.customFieldSelectionModel.logicalOperator = LogicalOperator.Or
|
console.log('FILTER_HAS_CUSTOM_FIELDS_ANY', rule.value)
|
||||||
this.customFieldSelectionModel.set(
|
// TODO: fully implement
|
||||||
rule.value ? +rule.value : null,
|
|
||||||
ToggleableItemState.Selected,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
case FILTER_HAS_ANY_CUSTOM_FIELDS:
|
case FILTER_HAS_ANY_CUSTOM_FIELDS:
|
||||||
this.customFieldSelectionModel.set(
|
console.log('FILTER_HAS_ANY_CUSTOM_FIELDS', rule.value)
|
||||||
null,
|
// TODO: fully implement
|
||||||
ToggleableItemState.Selected,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
case FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS:
|
case FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS:
|
||||||
this.customFieldSelectionModel.set(
|
console.log('FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS', rule.value)
|
||||||
rule.value ? +rule.value : null,
|
// TODO: fully implement
|
||||||
ToggleableItemState.Excluded,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
case FILTER_ASN_ISNULL:
|
case FILTER_ASN_ISNULL:
|
||||||
this.textFilterTarget = TEXT_FILTER_TARGET_ASN
|
this.textFilterTarget = TEXT_FILTER_TARGET_ASN
|
||||||
@ -655,15 +647,6 @@ export class FilterEditorComponent
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
this._textFilter &&
|
|
||||||
this.textFilterTarget == TEXT_FILTER_TARGET_CUSTOM_FIELDS
|
|
||||||
) {
|
|
||||||
filterRules.push({
|
|
||||||
rule_type: FILTER_CUSTOM_FIELDS_TEXT,
|
|
||||||
value: this._textFilter,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
this._textFilter &&
|
this._textFilter &&
|
||||||
this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_QUERY
|
this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_QUERY
|
||||||
@ -768,35 +751,24 @@ export class FilterEditorComponent
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (this.customFieldSelectionModel.isNoneSelected()) {
|
let queries = this.customFieldQueriesModel.queries
|
||||||
|
.filter((query) => query.field && query.operator)
|
||||||
|
.map((query) => [query.field, query.operator, query.value])
|
||||||
|
console.log(
|
||||||
|
'this.customFieldQueriesModel.queries',
|
||||||
|
this.customFieldQueriesModel.queries
|
||||||
|
)
|
||||||
|
console.log('queries', queries)
|
||||||
|
if (queries.length > 0) {
|
||||||
filterRules.push({
|
filterRules.push({
|
||||||
rule_type: FILTER_HAS_ANY_CUSTOM_FIELDS,
|
rule_type: FILTER_CUSTOM_FIELDS_LOOKUP,
|
||||||
value: 'false',
|
value:
|
||||||
|
queries.length === 1
|
||||||
|
? JSON.stringify(queries[0])
|
||||||
|
: JSON.stringify(queries),
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
const customFieldFilterType =
|
|
||||||
this.customFieldSelectionModel.logicalOperator == LogicalOperator.And
|
|
||||||
? FILTER_HAS_CUSTOM_FIELDS_ALL
|
|
||||||
: FILTER_HAS_CUSTOM_FIELDS_ANY
|
|
||||||
this.customFieldSelectionModel
|
|
||||||
.getSelectedItems()
|
|
||||||
.filter((field) => field.id)
|
|
||||||
.forEach((field) => {
|
|
||||||
filterRules.push({
|
|
||||||
rule_type: customFieldFilterType,
|
|
||||||
value: field.id?.toString(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
this.customFieldSelectionModel
|
|
||||||
.getExcludedItems()
|
|
||||||
.filter((field) => field.id)
|
|
||||||
.forEach((field) => {
|
|
||||||
filterRules.push({
|
|
||||||
rule_type: FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS,
|
|
||||||
value: field.id?.toString(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
// TODO: fully implement custom fields
|
||||||
if (this.dateCreatedBefore) {
|
if (this.dateCreatedBefore) {
|
||||||
filterRules.push({
|
filterRules.push({
|
||||||
rule_type: FILTER_CREATED_BEFORE,
|
rule_type: FILTER_CREATED_BEFORE,
|
||||||
@ -1079,10 +1051,6 @@ export class FilterEditorComponent
|
|||||||
this.storagePathSelectionModel.apply()
|
this.storagePathSelectionModel.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
onCustomFieldsDropdownOpen() {
|
|
||||||
this.customFieldSelectionModel.apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTextFilter(text, updateRules = true) {
|
updateTextFilter(text, updateRules = true) {
|
||||||
this._textFilter = text
|
this._textFilter = text
|
||||||
if (updateRules) {
|
if (updateRules) {
|
||||||
|
@ -55,6 +55,8 @@ export const FILTER_HAS_CUSTOM_FIELDS_ANY = 39
|
|||||||
export const FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS = 40
|
export const FILTER_DOES_NOT_HAVE_CUSTOM_FIELDS = 40
|
||||||
export const FILTER_HAS_ANY_CUSTOM_FIELDS = 41
|
export const FILTER_HAS_ANY_CUSTOM_FIELDS = 41
|
||||||
|
|
||||||
|
export const FILTER_CUSTOM_FIELDS_LOOKUP = 42
|
||||||
|
|
||||||
export const FILTER_RULE_TYPES: FilterRuleType[] = [
|
export const FILTER_RULE_TYPES: FilterRuleType[] = [
|
||||||
{
|
{
|
||||||
id: FILTER_TITLE,
|
id: FILTER_TITLE,
|
||||||
@ -317,6 +319,12 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
|
|||||||
multi: false,
|
multi: false,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: FILTER_CUSTOM_FIELDS_LOOKUP,
|
||||||
|
filtervar: 'custom_field_lookup',
|
||||||
|
datatype: 'string',
|
||||||
|
multi: false,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export interface FilterRuleType {
|
export interface FilterRuleType {
|
||||||
|
@ -507,6 +507,7 @@ class SavedViewFilterRule(models.Model):
|
|||||||
(39, _("has custom field in")),
|
(39, _("has custom field in")),
|
||||||
(40, _("does not have custom field in")),
|
(40, _("does not have custom field in")),
|
||||||
(41, _("does not have custom field")),
|
(41, _("does not have custom field")),
|
||||||
|
(42, _("custom fields lookup")),
|
||||||
]
|
]
|
||||||
|
|
||||||
saved_view = models.ForeignKey(
|
saved_view = models.ForeignKey(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user