mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-04 08:55:04 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da82f26c14 | ||
|
|
405cad4617 | ||
|
|
3b4db07488 | ||
|
|
d0195f888f | ||
|
|
3003b9e05e | ||
|
|
2fa48494c2 | ||
|
|
b0540b5fdc |
@@ -38,6 +38,7 @@ body:
|
|||||||
label: Installation method
|
label: Installation method
|
||||||
options:
|
options:
|
||||||
- Docker - official image
|
- Docker - official image
|
||||||
|
- Docker - linuxserver.io image
|
||||||
- Bare metal
|
- Bare metal
|
||||||
- Other (please describe above)
|
- Other (please describe above)
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -87,8 +87,10 @@ body:
|
|||||||
label: Installation method
|
label: Installation method
|
||||||
options:
|
options:
|
||||||
- Docker - official image
|
- Docker - official image
|
||||||
|
- Docker - linuxserver.io image
|
||||||
- Bare metal
|
- Bare metal
|
||||||
- Other (please describe above)
|
- Other (please describe above)
|
||||||
|
description: Note there are significant differences from the official image and linuxserver.io, please check if your issue is specific to the third-party image.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
network_mode: host
|
network_mode: host
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
greenmail:
|
greenmail:
|
||||||
image: docker.io/greenmail/standalone:2.1.13
|
image: docker.io/greenmail/standalone:2.1.11
|
||||||
hostname: greenmail
|
hostname: greenmail
|
||||||
container_name: greenmail
|
container_name: greenmail
|
||||||
environment:
|
environment:
|
||||||
@@ -35,7 +35,7 @@ services:
|
|||||||
- "3143:3143" # IMAP
|
- "3143:3143" # IMAP
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
nginx:
|
nginx:
|
||||||
image: docker.io/nginx:1.31.5-alpine
|
image: docker.io/nginx:1.31.3-alpine
|
||||||
hostname: nginx
|
hostname: nginx
|
||||||
container_name: nginx
|
container_name: nginx
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -1,69 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## paperless-ngx 3.1.3
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
- Fix: use the header loading indicator on tasks page [@shamoon](https://github.com/shamoon) ([#13949](https://github.com/paperless-ngx/paperless-ngx/pull/13949))
|
|
||||||
- Fix: fix load sidebar size animating [@shamoon](https://github.com/shamoon) ([#13947](https://github.com/paperless-ngx/paperless-ngx/pull/13947))
|
|
||||||
- Fix: wrap long words without spaces in dropdowns [@shamoon](https://github.com/shamoon) ([#13945](https://github.com/paperless-ngx/paperless-ngx/pull/13945))
|
|
||||||
- Fix: tweak tool calling localization prompt [@shamoon](https://github.com/shamoon) ([#13943](https://github.com/paperless-ngx/paperless-ngx/pull/13943))
|
|
||||||
- Fix: skip vector store document id filter for unrestricted chat users [@stumpylog](https://github.com/stumpylog) ([#13937](https://github.com/paperless-ngx/paperless-ngx/pull/13937))
|
|
||||||
- Fix: adopt the request stream when pinning an outbound host [@ThomasSteinbach](https://github.com/ThomasSteinbach) ([#13927](https://github.com/paperless-ngx/paperless-ngx/pull/13927))
|
|
||||||
- Fix: ensure apply ai suggestions always runs after document created [@shamoon](https://github.com/shamoon) ([#13940](https://github.com/paperless-ngx/paperless-ngx/pull/13940))
|
|
||||||
- Fix: Handle failures when enqueuing files for consumption [@stumpylog](https://github.com/stumpylog) ([#13935](https://github.com/paperless-ngx/paperless-ngx/pull/13935))
|
|
||||||
- Fix: Handle Celery mail task chord errors [@stumpylog](https://github.com/stumpylog) ([#13936](https://github.com/paperless-ngx/paperless-ngx/pull/13936))
|
|
||||||
- Fix/chore: refactor some signal-backed conversion technical debt [@shamoon](https://github.com/shamoon) ([#13902](https://github.com/paperless-ngx/paperless-ngx/pull/13902))
|
|
||||||
- Fix: fix slim sidebar saved view dragging appearance [@shamoon](https://github.com/shamoon) ([#13906](https://github.com/paperless-ngx/paperless-ngx/pull/13906))
|
|
||||||
- Fix: use signal-backed queries input in CF dropdown to reflect changes immediately under zoneless [@shamoon](https://github.com/shamoon) ([#13901](https://github.com/paperless-ngx/paperless-ngx/pull/13901))
|
|
||||||
- Fix: use root doc metadata for filename generation [@shamoon](https://github.com/shamoon) ([#13893](https://github.com/paperless-ngx/paperless-ngx/pull/13893))
|
|
||||||
- Fix: some css cleanup [@shamoon](https://github.com/shamoon) ([#13891](https://github.com/paperless-ngx/paperless-ngx/pull/13891))
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>7 changes</summary>
|
|
||||||
|
|
||||||
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#13958](https://github.com/paperless-ngx/paperless-ngx/pull/13958))
|
|
||||||
- docker-compose(deps): bump nginx from 1.31.3-alpine to 1.31.5-alpine in /docker/compose @[dependabot[bot]](https://github.com/apps/dependabot) ([#13909](https://github.com/paperless-ngx/paperless-ngx/pull/13909))
|
|
||||||
- docker-compose(deps): Bump greenmail/standalone from 2.1.11 to 2.1.13 in /docker/compose @[dependabot[bot]](https://github.com/apps/dependabot) ([#13907](https://github.com/paperless-ngx/paperless-ngx/pull/13907))
|
|
||||||
- Chore(deps-dev): Bump postcss-selector-parser from 6.1.2 to 6.1.4 in /src/paperless\_mail/templates in the npm\_and\_yarn group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#13905](https://github.com/paperless-ngx/paperless-ngx/pull/13905))
|
|
||||||
- Chore(deps): Bump nltk from 3.10.0 to 3.10.3 in the data-nlp-search group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#13917](https://github.com/paperless-ngx/paperless-ngx/pull/13917))
|
|
||||||
- Chore(deps): Bump the frontend-angular-dependencies group across 1 directory with 14 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#13915](https://github.com/paperless-ngx/paperless-ngx/pull/13915))
|
|
||||||
- Chore(deps): Bump djangorestframework from 3.17.1 to 3.17.2 in the uv group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#13904](https://github.com/paperless-ngx/paperless-ngx/pull/13904))
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### All App Changes
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>22 changes</summary>
|
|
||||||
|
|
||||||
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#13958](https://github.com/paperless-ngx/paperless-ngx/pull/13958))
|
|
||||||
- Chore(deps-dev): Bump postcss-selector-parser from 6.1.2 to 6.1.4 in /src/paperless\_mail/templates in the npm\_and\_yarn group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#13905](https://github.com/paperless-ngx/paperless-ngx/pull/13905))
|
|
||||||
- Chore(deps): Bump nltk from 3.10.0 to 3.10.3 in the data-nlp-search group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#13917](https://github.com/paperless-ngx/paperless-ngx/pull/13917))
|
|
||||||
- Fix: use the header loading indicator on tasks page [@shamoon](https://github.com/shamoon) ([#13949](https://github.com/paperless-ngx/paperless-ngx/pull/13949))
|
|
||||||
- Chore(deps): Bump the frontend-angular-dependencies group across 1 directory with 14 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#13915](https://github.com/paperless-ngx/paperless-ngx/pull/13915))
|
|
||||||
- Chore(deps): Bump djangorestframework from 3.17.1 to 3.17.2 in the uv group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#13904](https://github.com/paperless-ngx/paperless-ngx/pull/13904))
|
|
||||||
- Fix: fix load sidebar size animating [@shamoon](https://github.com/shamoon) ([#13947](https://github.com/paperless-ngx/paperless-ngx/pull/13947))
|
|
||||||
- Fix: wrap long words without spaces in dropdowns [@shamoon](https://github.com/shamoon) ([#13945](https://github.com/paperless-ngx/paperless-ngx/pull/13945))
|
|
||||||
- Fix: tweak tool calling localization prompt [@shamoon](https://github.com/shamoon) ([#13943](https://github.com/paperless-ngx/paperless-ngx/pull/13943))
|
|
||||||
- Fix: skip vector store document id filter for unrestricted chat users [@stumpylog](https://github.com/stumpylog) ([#13937](https://github.com/paperless-ngx/paperless-ngx/pull/13937))
|
|
||||||
- Fix: adopt the request stream when pinning an outbound host [@ThomasSteinbach](https://github.com/ThomasSteinbach) ([#13927](https://github.com/paperless-ngx/paperless-ngx/pull/13927))
|
|
||||||
- Fix: ensure apply ai suggestions always runs after document created [@shamoon](https://github.com/shamoon) ([#13940](https://github.com/paperless-ngx/paperless-ngx/pull/13940))
|
|
||||||
- Fix: Handle failures when enqueuing files for consumption [@stumpylog](https://github.com/stumpylog) ([#13935](https://github.com/paperless-ngx/paperless-ngx/pull/13935))
|
|
||||||
- Fix: Handle Celery mail task chord errors [@stumpylog](https://github.com/stumpylog) ([#13936](https://github.com/paperless-ngx/paperless-ngx/pull/13936))
|
|
||||||
- Fix/chore: refactor some signal-backed conversion technical debt [@shamoon](https://github.com/shamoon) ([#13902](https://github.com/paperless-ngx/paperless-ngx/pull/13902))
|
|
||||||
- Security: validate remote OCR endpoint [@stumpylog](https://github.com/stumpylog) ([#13897](https://github.com/paperless-ngx/paperless-ngx/pull/13897))
|
|
||||||
- Fix: fix slim sidebar saved view dragging appearance [@shamoon](https://github.com/shamoon) ([#13906](https://github.com/paperless-ngx/paperless-ngx/pull/13906))
|
|
||||||
- Security: Minor additional hardening [@stumpylog](https://github.com/stumpylog) ([#13898](https://github.com/paperless-ngx/paperless-ngx/pull/13898))
|
|
||||||
- Chore: consolidate pickle hmac signing [@shamoon](https://github.com/shamoon) ([#13899](https://github.com/paperless-ngx/paperless-ngx/pull/13899))
|
|
||||||
- Fix: use signal-backed queries input in CF dropdown to reflect changes immediately under zoneless [@shamoon](https://github.com/shamoon) ([#13901](https://github.com/paperless-ngx/paperless-ngx/pull/13901))
|
|
||||||
- Fix: use root doc metadata for filename generation [@shamoon](https://github.com/shamoon) ([#13893](https://github.com/paperless-ngx/paperless-ngx/pull/13893))
|
|
||||||
- Fix: some css cleanup [@shamoon](https://github.com/shamoon) ([#13891](https://github.com/paperless-ngx/paperless-ngx/pull/13891))
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## paperless-ngx 3.1.2
|
## paperless-ngx 3.1.2
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "paperless-ngx"
|
name = "paperless-ngx"
|
||||||
version = "3.1.3"
|
version = "3.1.2"
|
||||||
description = "A community-supported supercharged document management system: scan, index and archive all your physical documents"
|
description = "A community-supported supercharged document management system: scan, index and archive all your physical documents"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|||||||
@@ -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')
|
||||||
|
})
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "paperless-ngx-ui",
|
"name": "paperless-ngx-ui",
|
||||||
"version": "3.1.3",
|
"version": "3.1.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const environment = {
|
|||||||
apiVersion: '10', // match src/paperless/settings.py
|
apiVersion: '10', // match src/paperless/settings.py
|
||||||
appTitle: DEFAULT_APP_TITLE,
|
appTitle: DEFAULT_APP_TITLE,
|
||||||
tag: 'prod',
|
tag: 'prod',
|
||||||
version: '3.1.3',
|
version: '3.1.2',
|
||||||
webSocketHost: window.location.host,
|
webSocketHost: window.location.host,
|
||||||
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
|
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
|
||||||
webSocketBaseUrl: base_url.pathname + 'ws/',
|
webSocketBaseUrl: base_url.pathname + 'ws/',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user