mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-03 08:27:15 +00:00
Compare commits
7
Commits
dev
..
ng-select-v24
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da82f26c14 | ||
|
|
405cad4617 | ||
|
|
3b4db07488 | ||
|
|
d0195f888f | ||
|
|
3003b9e05e | ||
|
|
2fa48494c2 | ||
|
|
b0540b5fdc |
@@ -48,6 +48,7 @@ def seed_database() -> None:
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from documents.models import Correspondent
|
from documents.models import Correspondent
|
||||||
|
from documents.models import CustomField
|
||||||
from documents.models import Document
|
from documents.models import Document
|
||||||
from documents.models import DocumentType
|
from documents.models import DocumentType
|
||||||
from documents.models import Note
|
from documents.models import Note
|
||||||
@@ -81,6 +82,16 @@ def seed_database() -> None:
|
|||||||
path="e2e/{created_year}/{title}",
|
path="e2e/{created_year}/{title}",
|
||||||
owner=admin,
|
owner=admin,
|
||||||
)
|
)
|
||||||
|
CustomField.objects.create(
|
||||||
|
name="Test Select Field",
|
||||||
|
data_type=CustomField.FieldDataType.SELECT,
|
||||||
|
extra_data={
|
||||||
|
"select_options": [
|
||||||
|
{"id": "abc123", "label": "Alpha"},
|
||||||
|
{"id": "def456", "label": "Beta"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
today = timezone.localdate()
|
today = timezone.localdate()
|
||||||
documents = []
|
documents = []
|
||||||
|
|||||||
@@ -207,3 +207,41 @@ test('bulk edit', async ({ page }) => {
|
|||||||
await page.getByRole('button', { name: 'Confirm' }).click()
|
await page.getByRole('button', { name: 'Confirm' }).click()
|
||||||
await bulkEditPromise
|
await bulkEditPromise
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('permissions dropdown stays open when selecting a user', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/documents')
|
||||||
|
await page.getByRole('button', { name: 'Permissions' }).click()
|
||||||
|
const dropdown = page.locator(
|
||||||
|
'pngx-permissions-filter-dropdown .dropdown-menu'
|
||||||
|
)
|
||||||
|
await expect(dropdown).toBeVisible()
|
||||||
|
await dropdown.locator('ng-select').click()
|
||||||
|
await page.getByRole('option', { name: 'playwright' }).click()
|
||||||
|
await expect(dropdown).toBeVisible()
|
||||||
|
await expect(dropdown.locator('.ng-value-label')).toHaveText('playwright')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('custom fields query dropdown stays open when building a query', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/documents')
|
||||||
|
await page.getByRole('button', { name: 'Custom fields' }).click()
|
||||||
|
const dropdown = page.locator(
|
||||||
|
'pngx-custom-fields-query-dropdown .dropdown-menu'
|
||||||
|
)
|
||||||
|
await expect(dropdown).toBeVisible()
|
||||||
|
|
||||||
|
// field picker
|
||||||
|
await dropdown.locator('ng-select').first().click()
|
||||||
|
await page.getByRole('option', { name: 'Test Select Field' }).click()
|
||||||
|
await expect(dropdown).toBeVisible()
|
||||||
|
|
||||||
|
// value picker, shown once the operator takes a list of options
|
||||||
|
await dropdown.locator('select').first().selectOption({ label: 'In' })
|
||||||
|
await dropdown.locator('ng-select').last().click()
|
||||||
|
await page.getByRole('option', { name: 'Alpha' }).click()
|
||||||
|
await expect(dropdown).toBeVisible()
|
||||||
|
await expect(dropdown.locator('.ng-value-label').last()).toHaveText('Alpha')
|
||||||
|
})
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@
|
|||||||
"@angular/platform-browser": "~22.1.3",
|
"@angular/platform-browser": "~22.1.3",
|
||||||
"@angular/router": "~22.1.3",
|
"@angular/router": "~22.1.3",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^21.0.0",
|
"@ng-bootstrap/ng-bootstrap": "^21.0.0",
|
||||||
"@ng-select/ng-select": "~23.6.0",
|
"@ng-select/ng-select": "~24.0.2",
|
||||||
"@ngneat/dirty-check-forms": "^3.0.3",
|
"@ngneat/dirty-check-forms": "^3.0.3",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
|
|||||||
Generated
+7
-5
@@ -36,8 +36,8 @@ importers:
|
|||||||
specifier: ^21.0.0
|
specifier: ^21.0.0
|
||||||
version: 21.0.0(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(@angular/localize@22.1.3(@angular/compiler-cli@22.1.3(@angular/compiler@22.1.3)(typescript@6.0.3))(@angular/compiler@22.1.3))(@popperjs/core@2.11.8)(rxjs@7.8.2)
|
version: 21.0.0(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(@angular/localize@22.1.3(@angular/compiler-cli@22.1.3(@angular/compiler@22.1.3)(typescript@6.0.3))(@angular/compiler@22.1.3))(@popperjs/core@2.11.8)(rxjs@7.8.2)
|
||||||
'@ng-select/ng-select':
|
'@ng-select/ng-select':
|
||||||
specifier: ~23.6.0
|
specifier: ~24.0.2
|
||||||
version: 23.6.0(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))
|
version: 24.0.2(@angular/cdk@22.1.4(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))
|
||||||
'@ngneat/dirty-check-forms':
|
'@ngneat/dirty-check-forms':
|
||||||
specifier: ^3.0.3
|
specifier: ^3.0.3
|
||||||
version: 3.0.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(@angular/router@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(lodash-es@4.18.1)(rxjs@7.8.2)
|
version: 3.0.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(@angular/router@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(lodash-es@4.18.1)(rxjs@7.8.2)
|
||||||
@@ -1490,10 +1490,11 @@ packages:
|
|||||||
'@popperjs/core': ^2.11.8
|
'@popperjs/core': ^2.11.8
|
||||||
rxjs: ^6.5.3 || ^7.4.0
|
rxjs: ^6.5.3 || ^7.4.0
|
||||||
|
|
||||||
'@ng-select/ng-select@23.6.0':
|
'@ng-select/ng-select@24.0.2':
|
||||||
resolution: {integrity: sha512-0I84OZ9gncphNR26zuqOwpB/XWhPav+IP+EfJd9lDNeu3UT9Y0JhTBburCXEXcbltwQkiN6bMCKdRF93hrFHxw==}
|
resolution: {integrity: sha512-EcOQanLp5dNxkDOxK75z7+B3gZW8LvQofzwL5AgWUn04EkJOXRI7Wi6Ylp7+jIAi9yPsTwjznrRd+wSl9EZGAQ==}
|
||||||
engines: {node: ^22.12.0 || ^24.0.0 || ^26.0.0}
|
engines: {node: ^22.12.0 || ^24.0.0 || ^26.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
'@angular/cdk': ^22.0.0
|
||||||
'@angular/common': ^22.0.0
|
'@angular/common': ^22.0.0
|
||||||
'@angular/core': ^22.0.0
|
'@angular/core': ^22.0.0
|
||||||
'@angular/forms': ^22.0.0
|
'@angular/forms': ^22.0.0
|
||||||
@@ -5769,8 +5770,9 @@ snapshots:
|
|||||||
rxjs: 7.8.2
|
rxjs: 7.8.2
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@ng-select/ng-select@23.6.0(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))':
|
'@ng-select/ng-select@24.0.2(@angular/cdk@22.1.4(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/forms@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@angular/cdk': 22.1.4(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2)
|
||||||
'@angular/common': 22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2)
|
'@angular/common': 22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2)
|
||||||
'@angular/core': 22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)
|
'@angular/core': 22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)
|
||||||
'@angular/forms': 22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2)
|
'@angular/forms': 22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(@angular/platform-browser@22.1.3(@angular/common@22.1.3(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.1.3(@angular/compiler@22.1.3)(rxjs@7.8.2)))(rxjs@7.8.2)
|
||||||
|
|||||||
+6
-3
@@ -6,7 +6,7 @@
|
|||||||
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge>
|
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge>
|
||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
<div class="px-3 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown_{{name}}">
|
<div [id]="dropdownMenuId" class="px-3 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown_{{name}}">
|
||||||
<ng-container *ngTemplateOutlet="list; context: { queries: selectionModel.queries }"></ng-container>
|
<ng-container *ngTemplateOutlet="list; context: { queries: selectionModel.queries }"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,10 +64,11 @@
|
|||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
[virtualScroll]="getSelectOptionsForField(atom.field)?.length > 100"
|
[virtualScroll]="getSelectOptionsForField(atom.field)?.length > 100"
|
||||||
[searchFn]="selectOptionSearchFn"
|
[searchFn]="selectOptionSearchFn"
|
||||||
|
[appendTo]="selectAppendTo"
|
||||||
(mousedown)="$event.stopImmediatePropagation()"
|
(mousedown)="$event.stopImmediatePropagation()"
|
||||||
></ng-select>
|
></ng-select>
|
||||||
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.DocumentLink) {
|
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.DocumentLink) {
|
||||||
<pngx-input-document-link [(ngModel)]="atom.value" class="w-25 form-select doc-link-select p-0" placeholder="Search docs..." i18n-placeholder [minimal]="true"></pngx-input-document-link>
|
<pngx-input-document-link [(ngModel)]="atom.value" class="w-25 form-select doc-link-select p-0" placeholder="Search docs..." i18n-placeholder [minimal]="true" [appendTo]="selectAppendTo"></pngx-input-document-link>
|
||||||
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Monetary) {
|
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Monetary) {
|
||||||
<input class="w-25 form-control rounded-end" type="text" inputmode="decimal"
|
<input class="w-25 form-control rounded-end" type="text" inputmode="decimal"
|
||||||
[ngModel]="atom.value"
|
[ngModel]="atom.value"
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
bindLabel="name"
|
bindLabel="name"
|
||||||
bindValue="id"
|
bindValue="id"
|
||||||
[searchFn]="customFieldSearchFn"
|
[searchFn]="customFieldSearchFn"
|
||||||
|
[appendTo]="selectAppendTo"
|
||||||
(mousedown)="$event.stopImmediatePropagation()"
|
(mousedown)="$event.stopImmediatePropagation()"
|
||||||
></ng-select>
|
></ng-select>
|
||||||
<select class="w-25 form-select" [(ngModel)]="atom.operator" [disabled]="disabled">
|
<select class="w-25 form-select" [(ngModel)]="atom.operator" [disabled]="disabled">
|
||||||
@@ -121,7 +123,7 @@
|
|||||||
<ng-container *ngTemplateOutlet="comparisonValueTemplate; context: { atom: atom }"></ng-container>
|
<ng-container *ngTemplateOutlet="comparisonValueTemplate; context: { atom: atom }"></ng-container>
|
||||||
}
|
}
|
||||||
@case (CustomFieldQueryOperator.Contains) {
|
@case (CustomFieldQueryOperator.Contains) {
|
||||||
<pngx-input-document-link [(ngModel)]="atom.value" class="w-25 form-select doc-link-select p-0" placeholder="Search docs..." i18n-placeholder [minimal]="true"></pngx-input-document-link>
|
<pngx-input-document-link [(ngModel)]="atom.value" class="w-25 form-select doc-link-select p-0" placeholder="Search docs..." i18n-placeholder [minimal]="true" [appendTo]="selectAppendTo"></pngx-input-document-link>
|
||||||
}
|
}
|
||||||
@case (CustomFieldQueryOperator.In) {
|
@case (CustomFieldQueryOperator.In) {
|
||||||
<ng-select
|
<ng-select
|
||||||
@@ -133,6 +135,7 @@
|
|||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
[multiple]="true"
|
[multiple]="true"
|
||||||
[searchFn]="selectOptionSearchFn"
|
[searchFn]="selectOptionSearchFn"
|
||||||
|
[appendTo]="selectAppendTo"
|
||||||
(mousedown)="$event.stopImmediatePropagation()"
|
(mousedown)="$event.stopImmediatePropagation()"
|
||||||
></ng-select>
|
></ng-select>
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -1,3 +1,4 @@
|
|||||||
|
import { _IdGenerator } from '@angular/cdk/a11y'
|
||||||
import {
|
import {
|
||||||
getLocaleNumberSymbol,
|
getLocaleNumberSymbol,
|
||||||
NgClass,
|
NgClass,
|
||||||
@@ -250,6 +251,18 @@ export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPerm
|
|||||||
@Input()
|
@Input()
|
||||||
useDropdown: boolean = true
|
useDropdown: boolean = true
|
||||||
|
|
||||||
|
private readonly idGenerator = inject(_IdGenerator)
|
||||||
|
public readonly dropdownMenuId = this.idGenerator.getId(
|
||||||
|
'pngx-custom-fields-query-dropdown-'
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep ng-select dropdown panels inside the dropdown menu
|
||||||
|
*/
|
||||||
|
get selectAppendTo(): string {
|
||||||
|
return this.useDropdown ? `#${this.dropdownMenuId}` : null
|
||||||
|
}
|
||||||
|
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return this.title ? this.title.replace(/\s/g, '_').toLowerCase() : null
|
return this.title ? this.title.replace(/\s/g, '_').toLowerCase() : null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<i-bs width="1em" height="1em" name="calendar-event-fill"></i-bs><div class="d-none d-sm-inline ms-1">{{title}}</div>
|
<i-bs width="1em" height="1em" name="calendar-event-fill"></i-bs><div class="d-none d-sm-inline ms-1">{{title}}</div>
|
||||||
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge><span class="visually-hidden">selected</span>
|
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge><span class="visually-hidden">selected</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu date-dropdown shadow p-2" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
|
<div [id]="dropdownMenuId" class="dropdown-menu date-dropdown shadow p-2" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
|
||||||
<h6 class="dropdown-header border-bottom" i18n>Created</h6>
|
<h6 class="dropdown-header border-bottom" i18n>Created</h6>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<div class="list-group-item d-flex p-2 select-item" role="menuitem">
|
<div class="list-group-item d-flex p-2 select-item" role="menuitem">
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
bindValue="id"
|
bindValue="id"
|
||||||
bindLabel="name"
|
bindLabel="name"
|
||||||
clearable="false"
|
clearable="false"
|
||||||
|
[appendTo]="'#' + dropdownMenuId"
|
||||||
placeholder="Relative dates"
|
placeholder="Relative dates"
|
||||||
i18n-placeholder
|
i18n-placeholder
|
||||||
(change)="onSetCreatedRelativeDate($event)">
|
(change)="onSetCreatedRelativeDate($event)">
|
||||||
@@ -97,6 +98,7 @@
|
|||||||
bindValue="id"
|
bindValue="id"
|
||||||
bindLabel="name"
|
bindLabel="name"
|
||||||
clearable="false"
|
clearable="false"
|
||||||
|
[appendTo]="'#' + dropdownMenuId"
|
||||||
placeholder="Relative dates"
|
placeholder="Relative dates"
|
||||||
i18n-placeholder
|
i18n-placeholder
|
||||||
(change)="onSetAddedRelativeDate($event)">
|
(change)="onSetAddedRelativeDate($event)">
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { SettingsService } from 'src/app/services/settings.service'
|
|||||||
import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'
|
import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'
|
||||||
import { pngxPopperOptions } from 'src/app/utils/popper-options'
|
import { pngxPopperOptions } from 'src/app/utils/popper-options'
|
||||||
import { ClearableBadgeComponent } from '../clearable-badge/clearable-badge.component'
|
import { ClearableBadgeComponent } from '../clearable-badge/clearable-badge.component'
|
||||||
|
import { _IdGenerator } from '@angular/cdk/a11y'
|
||||||
|
|
||||||
export interface DateSelection {
|
export interface DateSelection {
|
||||||
createdTo?: string
|
createdTo?: string
|
||||||
@@ -68,6 +69,10 @@ export enum RelativeDate {
|
|||||||
})
|
})
|
||||||
export class DatesDropdownComponent implements OnInit, OnDestroy {
|
export class DatesDropdownComponent implements OnInit, OnDestroy {
|
||||||
public popperOptions = pngxPopperOptions
|
public popperOptions = pngxPopperOptions
|
||||||
|
private readonly idGenerator = inject(_IdGenerator)
|
||||||
|
public readonly dropdownMenuId = this.idGenerator.getId(
|
||||||
|
'pngx-dates-dropdown-'
|
||||||
|
)
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const settings = inject(SettingsService)
|
const settings = inject(SettingsService)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
[compareWith]="compareDocuments"
|
[compareWith]="compareDocuments"
|
||||||
[trackByFn]="trackByFn"
|
[trackByFn]="trackByFn"
|
||||||
[minTermLength]="2"
|
[minTermLength]="2"
|
||||||
|
[appendTo]="appendTo"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
[typeahead]="documentsInput$"
|
[typeahead]="documentsInput$"
|
||||||
(mousedown)="$event.stopImmediatePropagation()"
|
(mousedown)="$event.stopImmediatePropagation()"
|
||||||
|
|||||||
@@ -81,6 +81,12 @@ export class DocumentLinkComponent
|
|||||||
@Input()
|
@Input()
|
||||||
placeholder: string = $localize`Search for documents`
|
placeholder: string = $localize`Search for documents`
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent for ng-select dropdown, needed to prevent close on click.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
appendTo: string = null
|
||||||
|
|
||||||
get selectedDocumentIDs(): number[] {
|
get selectedDocumentIDs(): number[] {
|
||||||
return this.selectedDocuments.map((d) => d.id)
|
return this.selectedDocuments.map((d) => d.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dropdown hierarchy reveal for ng-select options
|
// Dropdown hierarchy reveal for ng-select options
|
||||||
:host ::ng-deep .ng-dropdown-panel .ng-option {
|
::ng-deep .ng-dropdown-panel .ng-option {
|
||||||
overflow-x: auto !important;
|
overflow-x: auto !important;
|
||||||
|
|
||||||
.tag-option-row {
|
.tag-option-row {
|
||||||
@@ -41,12 +41,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:host ::ng-deep .ng-dropdown-panel .ng-option:hover .hierarchy-reveal,
|
::ng-deep .ng-dropdown-panel .ng-option:hover .hierarchy-reveal,
|
||||||
:host ::ng-deep .ng-dropdown-panel .ng-option.ng-option-marked .hierarchy-reveal {
|
::ng-deep .ng-dropdown-panel .ng-option.ng-option-marked .hierarchy-reveal {
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep .ng-dropdown-panel .ng-option:hover .hierarchy-indicator,
|
::ng-deep .ng-dropdown-panel .ng-option:hover .hierarchy-indicator,
|
||||||
:host ::ng-deep .ng-dropdown-panel .ng-option.ng-option-marked .hierarchy-indicator {
|
::ng-deep .ng-dropdown-panel .ng-option.ng-option-marked .hierarchy-indicator {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -3,7 +3,7 @@
|
|||||||
<i-bs name="person-fill-lock"></i-bs><div class="d-none d-sm-inline ms-1">{{title}}</div>
|
<i-bs name="person-fill-lock"></i-bs><div class="d-none d-sm-inline ms-1">{{title}}</div>
|
||||||
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge><span class="visually-hidden">selected</span>
|
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge><span class="visually-hidden">selected</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu permission-filter-dropdown shadow py-0 w-2" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
|
<div [id]="dropdownMenuId" class="dropdown-menu permission-filter-dropdown shadow py-0 w-2" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="setFilter(OwnerFilterType.NONE)" [disabled]="disabled">
|
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="setFilter(OwnerFilterType.NONE)" [disabled]="disabled">
|
||||||
<div class="selected-icon me-1">
|
<div class="selected-icon me-1">
|
||||||
@@ -58,7 +58,10 @@
|
|||||||
<button *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }" class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" [disabled]="disabled">
|
<button *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }" class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" [disabled]="disabled">
|
||||||
<div class="selected-icon me-1">
|
<div class="selected-icon me-1">
|
||||||
@if (selectionModel.ownerFilter() === OwnerFilterType.OTHERS) {
|
@if (selectionModel.ownerFilter() === OwnerFilterType.OTHERS) {
|
||||||
<i-bs width="1em" height="1em" name="check"></i-bs>
|
<a class="text-reset focus-variants" href="javascript:void(0)" (click)="clearIncludeUsers()" aria-label="Clear selected users" i18n-aria-label>
|
||||||
|
<i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs>
|
||||||
|
<i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs>
|
||||||
|
</a>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="me-1 w-100">
|
<div class="me-1 w-100">
|
||||||
@@ -69,6 +72,7 @@
|
|||||||
(ngModelChange)="selectionModel.includeUsers.set($event)"
|
(ngModelChange)="selectionModel.includeUsers.set($event)"
|
||||||
[disabled]="disabled"
|
[disabled]="disabled"
|
||||||
[clearable]="false"
|
[clearable]="false"
|
||||||
|
[appendTo]="'#' + dropdownMenuId"
|
||||||
[items]="users()"
|
[items]="users()"
|
||||||
bindLabel="username"
|
bindLabel="username"
|
||||||
multiple="true"
|
multiple="true"
|
||||||
|
|||||||
+15
@@ -6,3 +6,18 @@
|
|||||||
min-width: 1em;
|
min-width: 1em;
|
||||||
min-height: 1em;
|
min-height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.focus-variants {
|
||||||
|
.variant-focused {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
.variant-unfocused {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.variant-focused {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+15
@@ -171,6 +171,21 @@ describe('PermissionsFilterDropdownComponent', () => {
|
|||||||
|
|
||||||
expect(component.selectionModel.ownerFilter()).toEqual(OwnerFilterType.NONE)
|
expect(component.selectionModel.ownerFilter()).toEqual(OwnerFilterType.NONE)
|
||||||
})
|
})
|
||||||
|
it('should clear selected users', () => {
|
||||||
|
component.selectionModel.includeUsers.set([12])
|
||||||
|
component.onUserSelect()
|
||||||
|
component.selectionModel.hideUnowned.set(true)
|
||||||
|
expect(component.selectionModel.ownerFilter()).toEqual(
|
||||||
|
OwnerFilterType.OTHERS
|
||||||
|
)
|
||||||
|
|
||||||
|
component.clearIncludeUsers()
|
||||||
|
|
||||||
|
expect(component.selectionModel.includeUsers()).toEqual([])
|
||||||
|
expect(component.selectionModel.ownerFilter()).toEqual(OwnerFilterType.NONE)
|
||||||
|
expect(component.selectionModel.hideUnowned()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
it('should emit a selection model depending on the type of owner filter set', () => {
|
it('should emit a selection model depending on the type of owner filter set', () => {
|
||||||
const emitted = () => ({
|
const emitted = () => ({
|
||||||
excludeUsers: ownerFilterSetResult.excludeUsers(),
|
excludeUsers: ownerFilterSetResult.excludeUsers(),
|
||||||
|
|||||||
+11
@@ -1,3 +1,4 @@
|
|||||||
|
import { _IdGenerator } from '@angular/cdk/a11y'
|
||||||
import { NgClass } from '@angular/common'
|
import { NgClass } from '@angular/common'
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
@@ -70,6 +71,11 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
|
|||||||
|
|
||||||
public OwnerFilterType = OwnerFilterType
|
public OwnerFilterType = OwnerFilterType
|
||||||
|
|
||||||
|
private readonly idGenerator = inject(_IdGenerator)
|
||||||
|
public readonly dropdownMenuId = this.idGenerator.getId(
|
||||||
|
'pngx-permissions-filter-dropdown-'
|
||||||
|
)
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
title: string
|
title: string
|
||||||
|
|
||||||
@@ -205,6 +211,11 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
|
|||||||
this.ownerFilterSet.emit(this.selectionModel)
|
this.ownerFilterSet.emit(this.selectionModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearIncludeUsers() {
|
||||||
|
this.selectionModel.includeUsers.set([])
|
||||||
|
this.onUserSelect()
|
||||||
|
}
|
||||||
|
|
||||||
onUserSelect() {
|
onUserSelect() {
|
||||||
this.selectionModel.ownerFilter.set(
|
this.selectionModel.ownerFilter.set(
|
||||||
this.selectionModel.includeUsers()?.length
|
this.selectionModel.includeUsers()?.length
|
||||||
|
|||||||
+16
-11
@@ -374,17 +374,6 @@ th[pngxSortable] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked {
|
|
||||||
background-color: var(--pngx-bg-darker) !important;
|
|
||||||
color: var(--pngx-body-color-accent) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected,
|
|
||||||
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected.ng-option-marked {
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: var(--pngx-bg-alt2) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder,
|
&.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder,
|
||||||
.ng-select-container .ng-value-container .ng-placeholder {
|
.ng-select-container .ng-value-container .ng-placeholder {
|
||||||
top: 7px;
|
top: 7px;
|
||||||
@@ -402,6 +391,22 @@ th[pngxSortable] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ng-select renders the dropdown panel in a CDK overlay outside the component
|
||||||
|
.ng-dropdown-panel {
|
||||||
|
font-size: var(--pngx-body-font-size);
|
||||||
|
|
||||||
|
.ng-dropdown-panel-items .ng-option.ng-option-marked {
|
||||||
|
background-color: var(--pngx-bg-darker) !important;
|
||||||
|
color: var(--pngx-body-color-accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ng-dropdown-panel-items .ng-option.ng-option-selected,
|
||||||
|
.ng-dropdown-panel-items .ng-option.ng-option-selected.ng-option-marked {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: var(--pngx-bg-alt2) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.paperless-input-tags {
|
.paperless-input-tags {
|
||||||
.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value {
|
.ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|||||||
@@ -237,8 +237,8 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,%3csvg xmlns='h
|
|||||||
mix-blend-mode: luminosity;
|
mix-blend-mode: luminosity;
|
||||||
}
|
}
|
||||||
|
|
||||||
.paperless-input-select .ng-select .ng-dropdown-panel .ng-dropdown-panel-items .ng-option:not(.ng-option-selected):hover,
|
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option:not(.ng-option-selected):hover,
|
||||||
.paperless-input-select .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked {
|
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked {
|
||||||
background-color: var(--bs-light) !important;
|
background-color: var(--bs-light) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user