Compare commits

...

351 Commits

Author SHA1 Message Date
Trenton Holmes
7d8721c53c (delete me) 2022-04-02 07:14:14 -07:00
Trenton Holmes
aa67c851e3 (delete me) 2022-04-02 07:12:56 -07:00
shamoon
9737e4a24d Merge pull request #238 from schnuffle/feature-split-dockerimage
Feature split dockerimage
2022-04-02 01:24:15 -07:00
Quinn Casey
805c17565b Merge pull request #617 from paperless-ngx/fix-move-to-trash
uses shutil.move instead of rename
2022-04-02 15:17:43 +07:00
Florian Brandes
8e9d1cdd18 uses shutil.move instead of rename
fixes issues with cross-filesystem movement

Signed-off-by: Florian Brandes <florian.brandes@posteo.de>
2022-04-02 07:23:31 +02:00
shamoon
1d3300fb34 Merge pull request #610 from paperless-ngx/fix-npm-deps-010222_2
Fix npm deps 01.02.22 2
2022-04-01 21:41:54 -07:00
Trenton Holmes
26d93cf3be Fixes the name and path of the built image so it doesn't duplicate 2022-04-01 16:17:22 -07:00
Michael Shamoon
4e3183ee65 remove unused ngx-infinite-scroll
see 9993381cda
2022-04-01 14:19:59 -07:00
Michael Shamoon
8370ec58c1 bump dirty-check-forms, ngx-infinite-scroll, typescript 2022-04-01 13:54:14 -07:00
shamoon
0d1bcd3c13 Merge pull request #600 from paperless-ngx/fix-npm-deps-010222
Fix npm dependencies 01.02.22
2022-04-01 13:44:10 -07:00
Michael Shamoon
a456b968af bump @types/node, ng2-pdf-viewer, cypress 2022-04-01 13:25:36 -07:00
Michael Shamoon
3a242dc296 remove stubborn failing e2e settings test for now 2022-04-01 12:11:08 -07:00
Michael Shamoon
5aff9b6fdb bump angular deps & regenerate package-lock 2022-04-01 11:41:01 -07:00
Michael Shamoon
fac6fe0c2e Squashed commit of the following:
commit 3709bf5d7602bb2e126465870e00fca35d4f99be
Author: Michael Shamoon <4887959+shamoon@users.noreply.github.com>
Date:   Fri Apr 1 09:24:12 2022 -0700

    Attempt 2 to fix test failing on GHA
2022-04-01 09:28:47 -07:00
Michael Shamoon
efbc2a5715 Fix failing e2e settings test
[ci skip]
2022-04-01 09:09:02 -07:00
Quinn Casey
d18eebf97d Merge pull request #588 from paperless-ngx/locale-belarusian
Add Belarusian localization
2022-04-01 11:51:02 +07:00
Paperless-ngx Translation Bot [bot]
60cc7afc72 New Crowdin updates (#538)
* New translations django.po (Spanish)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations django.po (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations django.po (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations django.po (Russian)
[ci skip]

* New translations django.po (Russian)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations django.po (Belarusian)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations django.po (Belarusian)
[ci skip]

* New translations django.po (Belarusian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations django.po (Russian)
[ci skip]

* New translations django.po (Belarusian)
[ci skip]

* New translations django.po (Finnish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations django.po (Finnish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations django.po (Finnish)
[ci skip]

* New translations django.po (Finnish)
[ci skip]

* New translations django.po (Belarusian)
[ci skip]

* New translations django.po (Belarusian)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]
2022-03-31 19:47:16 -07:00
Michael Shamoon
b7949d2e69 Add Belarusian localization 2022-03-31 19:42:08 -07:00
shamoon
48175d5b8e Merge pull request #580 from paperless-ngx/docs-frontend-tests-style
Add frontend tests to docs
2022-03-31 15:43:50 -07:00
Michael Shamoon
cb8fd6597d Merge changes from #583 from @fantasticle
5496412aec
2022-03-31 15:42:46 -07:00
Michael Shamoon
70bc70ec97 Add frontend tests to docs 2022-03-30 19:09:07 -07:00
Alexey Zinchenko
be2b59431f Update troubleshooting.rst 2022-03-30 19:08:40 -07:00
shamoon
c43193b17d Add note for target branch
[ci skip]
2022-03-30 19:08:40 -07:00
Storm Heg
2147af0e6a Fix typo in api.rst 2022-03-30 19:08:30 -07:00
Trenton Holmes
2666e70706 Removes the filtering of on:pull_request event types 2022-03-30 10:10:36 -07:00
Trenton Holmes
19cf66be0f Updates the Dockerfile to utilize our new base image 1.0 which provides the pre-compiled wheels for certain dependencies and most base packages 2022-03-30 09:09:50 -07:00
Henning Häcker
8b26ddcd2c add trailing comma 2022-03-30 09:23:45 +02:00
Henning Häcker
47786dcb8c use double quotes 2022-03-30 09:23:45 +02:00
Henning Häcker
5d91d6a885 fix default value for OCR_MAX_IMAGE_PIXELS 2022-03-30 09:23:45 +02:00
Henning Häcker
559f7c2683 elaborate PAPERLESS_OCR_MAX_IMAGE_PIXELS docs 2022-03-30 09:23:45 +02:00
Henning Häcker
3b4da70c85 extract OCR_MAX_IMAGE_PIXELS into settings.py 2022-03-30 09:23:45 +02:00
Henning Häcker
95199bd325 formatting according to black 2022-03-30 09:23:45 +02:00
Henning Häcker
a8887b211e implement PAPERLESS_OCR_MAX_IMAGE_PIXELS 2022-03-30 09:23:45 +02:00
Michael Shamoon
9a758fc3dc fix management e2e tests title
[ci skip]
2022-03-29 23:30:05 -07:00
shamoon
edc9c3f01c Merge pull request #565 from paperless-ngx/more-e2e-tests
Add some more e2e tests
2022-03-29 23:24:45 -07:00
Michael Shamoon
83d769251d document-detail e2e tests
[ci skip]
2022-03-29 23:12:19 -07:00
Michael Shamoon
bd66333147 test changing pdf viewer 2022-03-29 20:20:46 -07:00
Michael Shamoon
2228678520 Fix settings tests failing because of loading time 2022-03-29 20:02:19 -07:00
Michael Shamoon
9a042118f9 Fix fixture organization
[ci skip]
2022-03-29 20:02:19 -07:00
Michael Shamoon
787ee454ff Mock some API methods in settings spec 2022-03-29 20:02:19 -07:00
Michael Shamoon
32a4587bd3 Mock some API methods 2022-03-29 20:02:19 -07:00
Michael Shamoon
474050ba6b Multiple documents, filtering, view changes, in document list e2e testing 2022-03-29 20:02:19 -07:00
Michael Shamoon
34657fd675 Some document list bulk editor e2e tests 2022-03-29 20:02:19 -07:00
Michael Shamoon
18747db17f Settings e2e tests 2022-03-29 20:02:19 -07:00
Michael Shamoon
dccea9434a Management e2e tests 2022-03-29 20:02:19 -07:00
Michael Shamoon
40b07572a9 fix index js warning 2022-03-29 15:28:55 -07:00
Trenton Holmes
9147e3a0bd Merge pull request #552 from stumpylog/bugfix-black
Bump version of black in CI/pre-commit
2022-03-29 06:14:12 -07:00
Trenton Holmes
ed25212654 Updates black version to fix issues 2022-03-28 12:23:25 -07:00
shamoon
ce5fe61e67 Merge pull request #540 from paperless-ngx/filtering-query-params
Feature: Filtering query params aka browser navigation for filtering
2022-03-28 00:07:46 -07:00
Michael Shamoon
9e9266b92a Remove unused var 2022-03-28 00:06:42 -07:00
Michael Shamoon
e329d72e8b Clarify query var transformation code 2022-03-27 23:47:53 -07:00
Michael Shamoon
92ec3fc060 Clear all subscriptions, switchMap 2022-03-27 23:41:29 -07:00
Michael Shamoon
3afb3a905c fix ci.yml comment
[ci skip]
2022-03-27 14:44:39 -07:00
Michael Shamoon
b3e6f04b30 move const 2022-03-27 00:25:27 -07:00
Michael Shamoon
0a29f51862 Fix quick filtering 2022-03-27 00:09:09 -07:00
Michael Shamoon
7149d407cd Allow filtering by document metadata 2022-03-27 00:08:08 -07:00
Michael Shamoon
fbb17df916 Remove exact document router link matching 2022-03-26 23:30:01 -07:00
Michael Shamoon
34b317da7a Query vars for filtering 2022-03-26 23:18:12 -07:00
Quinn Casey
c161829803 Merge pull request #536 from paperless-ngx/locale-turkish
Add Turkish localization
2022-03-27 07:04:16 +07:00
Michael Shamoon
7c2ae129d7 rxjs compatibility 2022-03-26 14:18:16 -07:00
Paperless-ngx Translation Bot [bot]
c49afa7caa New Crowdin updates (#517)
* New translations messages.xlf (Slovenian)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations django.po (Russian)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]
2022-03-26 13:53:04 -07:00
Michael Shamoon
534c157809 Add Turkish localization 2022-03-26 13:52:15 -07:00
shamoon
cae4d3fae3 Merge pull request #497 from stumpylog/update-dependencies
Bumps dependencies
2022-03-26 08:33:05 -07:00
Michael Shamoon
f59500c809 pipe typo
[ci skip]
2022-03-25 01:50:04 -07:00
Quinn Casey
b75bf255ba Merge pull request #527 from paperless-ngx/reorg-frontend-ci
Realign frontend ci pipeline
2022-03-25 15:29:20 +07:00
Michael Shamoon
1588242876 realign frontend ci pipeline 2022-03-25 00:49:55 -07:00
shamoon
00eff651e6 Merge pull request #526 from FrankStrieter/fix/cypress-on-arm
fix: exclude cypress from build in Dockerfile
2022-03-24 23:49:41 -07:00
Frank Strieter
a83d6a691a fix: exclude cypress from build in Dockerfile 2022-03-25 07:26:15 +01:00
Jan-Hendrik Ewers
5065f2cb80 Add arm64 compatible docker-compose for sqlite-tika - resubmission of #27 (#479)
* Create arm variant for sqlite-tika as apache/tika does not support arm64 arch right now

https://github.com/jonaswinkler/paperless-ng/discussions/1256

* Update documentation to explain why there is a seemingly duplicated docker-compose file

* Add caveat about arm arch

* Update docs to encourage use of the new docker-compose

* Remove whitespace

https://github.com/jonaswinkler/paperless-ng/pull/1354/checks?check_run_id=3756807426

* Update docker container to use official ngx

Co-authored-by: Quinn Casey <quinn@quinncasey.com>

* doesn -> does not

* Update docker/compose/docker-compose.postgres-tika.yml

Co-authored-by: Jan-Hendrik Ewers <jh.ewers@gmail.com>

* Update docker/compose/docker-compose.sqlite-tika.arm.yml

Co-authored-by: Jan-Hendrik Ewers <jh.ewers@gmail.com>

* Update docker/compose/docker-compose.sqlite-tika.yml

Co-authored-by: Jan-Hendrik Ewers <jh.ewers@gmail.com>

* Update docker/compose/docker-compose.sqlite-tika.arm.yml

* Update docker-compose.sqlite-tika.arm.yml

* Update docker/compose/docker-compose.sqlite-tika.arm.yml

Co-authored-by: Jan-Hendrik Ewers <jh.ewers@gmail.com>

* Add redisdata to volumes

Co-authored-by: Quinn Casey <quinn@quinncasey.com>
2022-03-25 06:32:16 +07:00
shamoon
a4b36b041a Merge pull request #515 from paperless-ngx/clickable-dashboard-widget-tags
Clickable tags in dashboard widgets
2022-03-24 14:36:32 -07:00
Michael Shamoon
c360d9fa18 Remove text interpolation from doc routerLink 2022-03-24 08:09:41 -07:00
Trenton Holmes
78258eb9cb Bumps django to 4.0 and fixes associated issues 2022-03-24 07:39:11 -07:00
Trenton Holmes
71e5b5cf72 Bumps pikepdf to ~5.1, dateparser to ~1.1 and other updates as possible/needed 2022-03-24 07:39:07 -07:00
shamoon
4b0229584e Merge pull request #514 from paperless-ngx/unified-management-component
Unify management lists with single template
2022-03-24 07:09:13 -07:00
Florian
b2df8297e1 Merge pull request #520 from gador/revert-pdfminer-six
Revert "Bump pdfminer-six from 20211012 to 20220319"
2022-03-24 15:06:49 +01:00
florian on nixos (Florian Brandes)
95048b14fd Revert "Bump pdfminer-six from 20211012 to 20220319"
ocrmypdf requires pdfminer-six <=20211012

This reverts commit 0932f095e1.
2022-03-24 14:28:32 +01:00
Michael Shamoon
3360791a31 Clickable tags in dashboard widgets 2022-03-23 22:08:00 -07:00
Michael Shamoon
4c65ecbe89 Unify management lists with single template 2022-03-23 13:31:00 -07:00
shamoon
65a56a1da0 Merge pull request #454 from schnuffle/pre-commit
Corrections to pass pre-commit hooks
2022-03-23 11:58:02 -07:00
shamoon
645f9b2ee2 Merge pull request #503 from paperless-ngx/testing
Add unit- & end to end test setup in frontend
2022-03-23 07:25:31 -07:00
Michael Shamoon
117157f02c Merge branch 'main' into testing 2022-03-23 07:22:52 -07:00
Quinn Casey
acab197a45 Merge pull request #508 from Unkn0wnCat/patch-1
Add API Scanning Setup section to scanners.rst
2022-03-23 20:25:27 +07:00
Kevin Kandlbinder
feed7cd556 Fix typo in docs/scanners.rst
Co-authored-by: Quinn Casey <quinn@quinncasey.com>
2022-03-23 14:07:10 +01:00
Kevin Kandlbinder
c79b70fffd Fix typo in docs/scanners.rst
Co-authored-by: Quinn Casey <quinn@quinncasey.com>
2022-03-23 14:06:53 +01:00
Kevin Kandlbinder
42a5709202 Fix typo in docs/scanners.rst
Co-authored-by: Quinn Casey <quinn@quinncasey.com>
2022-03-23 14:06:41 +01:00
Kevin Kandlbinder
806f1ec0a3 Add API Scanning Setup section to scanners.rst
* Add instructions for Doxie Q2 to scanners.rst
2022-03-23 12:15:35 +01:00
Frank Strieter
ccee85a05e fix code style issues
solve merge conflicts

format code

format code

format code
2022-03-23 09:39:55 +01:00
Frank Strieter
a27fb173dd solve merge conflicts 2022-03-23 09:24:07 +01:00
Frank Strieter
e4885badfc chore: update package.lock 2022-03-23 09:24:07 +01:00
Frank Strieter
62c488aff6 test: run tests in ci 2022-03-23 09:24:07 +01:00
Frank Strieter
afcb5fe3cf test: add cypress test for documents list 2022-03-23 09:24:07 +01:00
Frank Strieter
d38bed1334 test: remove most of the boilerplate tests 2022-03-23 09:24:07 +01:00
Frank Strieter
f6a9d5b038 chore: replace karma with jest 2022-03-23 09:23:59 +01:00
Frank Strieter
863258f23d chore: replace protractor with cypress 2022-03-23 09:22:40 +01:00
shamoon
3b76fa3f92 Fix pre-commit link
[ci skip]
2022-03-23 09:22:40 +01:00
shamoon
023a42fa07 Project actions on dev too
[ci skip]
2022-03-23 09:22:40 +01:00
Quinn Casey
537515432c Merge pull request #504 from paperless-ngx/locale-serbian
Add Serbian localization
2022-03-23 13:53:38 +07:00
shamoon
f93783052b Merge pull request #372 from paperless-ngx/feature-bottom-pagination
Feature: Add bottom pagination
2022-03-22 22:58:58 -07:00
Michael Shamoon
991bc1a1ce Add Serbian localization 2022-03-22 22:26:59 -07:00
Paperless-ngx Translation Bot [bot]
1b5c557c44 New Crowdin updates (#493)
* New translations django.po (Serbian (Latin))
* New translations messages.xlf (Serbian (Latin))
[ci skip]
2022-03-22 22:17:16 -07:00
shamoon
5794faef6c Merge pull request #313 from paperless-ngx/fix-issue-311
Fix #311 unable to click checkboxes in document list
2022-03-22 14:59:34 -07:00
Trenton Holmes
ec01c436ea Merge pull request #474 from paperless-ngx/dependabot/pip/dev/pdfminer-six-20220319
Bump pdfminer-six from 20211012 to 20220319
2022-03-22 07:44:39 -07:00
Trenton Holmes
9bb5568d8e Un-pickle and re-pickle the test models to resolve the version difference warning 2022-03-22 09:37:17 +01:00
shamoon
c25a107c04 Fix project automations failing on PRs from forks 2022-03-22 01:22:19 -07:00
shamoon
8f152aac69 Fix project automations failing from forks 2022-03-22 00:55:23 -07:00
dependabot[bot]
1cd5de697e Bump @angular/core from 13.2.5 to 13.3.0 in /src-ui (#488)
Bumps [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) from 13.2.5 to 13.3.0.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.3.0/packages/core)

---
updated-dependencies:
- dependency-name: "@angular/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-22 00:23:38 -07:00
dependabot[bot]
ce8c812669 Bump @ng-bootstrap/ng-bootstrap from 12.0.0 to 12.0.1 in /src-ui (#486)
Bumps [@ng-bootstrap/ng-bootstrap](https://github.com/ng-bootstrap/ng-bootstrap) from 12.0.0 to 12.0.1.
- [Release notes](https://github.com/ng-bootstrap/ng-bootstrap/releases)
- [Changelog](https://github.com/ng-bootstrap/ng-bootstrap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ng-bootstrap/ng-bootstrap/compare/12.0.0...12.0.1)

---
updated-dependencies:
- dependency-name: "@ng-bootstrap/ng-bootstrap"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-22 00:17:23 -07:00
dependabot[bot]
2c3ac053d8 Bump @angular/compiler from 13.2.5 to 13.3.0 in /src-ui (#487)
Bumps [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) from 13.2.5 to 13.3.0.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.3.0/packages/compiler)

---
updated-dependencies:
- dependency-name: "@angular/compiler"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-22 00:16:15 -07:00
dependabot[bot]
ca3bb6a540 Bump @types/jasmine from 3.10.3 to 4.0.0 in /src-ui (#485)
Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.10.3 to 4.0.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine)

---
updated-dependencies:
- dependency-name: "@types/jasmine"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-22 00:11:15 -07:00
dependabot[bot]
0932f095e1 Bump pdfminer-six from 20211012 to 20220319
Bumps [pdfminer-six](https://github.com/pdfminer/pdfminer.six) from 20211012 to 20220319.
- [Release notes](https://github.com/pdfminer/pdfminer.six/releases)
- [Changelog](https://github.com/pdfminer/pdfminer.six/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pdfminer/pdfminer.six/commits)

---
updated-dependencies:
- dependency-name: pdfminer-six
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-22 03:47:06 +00:00
Quinn Casey
3d3807ce41 Merge pull request #477 from paperless-ngx/dependachill
Change dependabot to check npm monthly
2022-03-22 08:01:17 +07:00
shamoon
30834eb8ff Change dependabot to check npm monthly
[ci skip]
2022-03-21 14:53:56 -07:00
dependabot[bot]
1c4e74920a Bump @types/node from 17.0.21 to 17.0.22 in /src-ui (#472)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 17.0.21 to 17.0.22.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-21 13:38:47 -07:00
dependabot[bot]
e6efff426a Bump @angular-devkit/build-angular from 13.2.6 to 13.3.0 in /src-ui (#471)
Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 13.2.6 to 13.3.0.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/13.2.6...13.3.0)

---
updated-dependencies:
- dependency-name: "@angular-devkit/build-angular"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-21 13:36:46 -07:00
dependabot[bot]
cacf60fdd9 Bump @angular/platform-browser-dynamic from 13.2.5 to 13.3.0 in /src-ui (#470)
Bumps [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) from 13.2.5 to 13.3.0.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.3.0/packages/platform-browser-dynamic)

---
updated-dependencies:
- dependency-name: "@angular/platform-browser-dynamic"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-21 13:33:59 -07:00
dependabot[bot]
352f94ff2b Bump @angular/platform-browser from 13.2.5 to 13.3.0 in /src-ui (#468)
Bumps [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) from 13.2.5 to 13.3.0.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.3.0/packages/platform-browser)

---
updated-dependencies:
- dependency-name: "@angular/platform-browser"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-21 13:30:16 -07:00
Trenton Holmes
47530d274f Merge pull request #467 from paperless-ngx/dependabot/pip/dev/scikit-learn-1.0.2
Fix failing test after updating model format version
2022-03-21 13:28:28 -07:00
dependabot[bot]
be13ec822f Bump @angular/cli from 13.2.6 to 13.3.0 in /src-ui (#469)
Bumps [@angular/cli](https://github.com/angular/angular-cli) from 13.2.6 to 13.3.0.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/13.2.6...13.3.0)

---
updated-dependencies:
- dependency-name: "@angular/cli"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-21 13:28:09 -07:00
Marc Schaefer
c6da0cc9a2 Merge branch 'pre-commit' of github.com:schnuffle/paperless-ngx into pre-commit 2022-03-21 19:46:19 +01:00
Marc Schaefer
07623f9883 Removed nested quotes 2022-03-21 19:45:46 +01:00
Schnuffle
6e0d334a0c Indentation corrections 2022-03-21 19:38:44 +01:00
shamoon
e514b99c57 Fix pre-commit link
[ci skip]
2022-03-21 10:54:48 -07:00
Johann Bauer
cffdaefe2f Fix model test 2022-03-21 18:53:53 +01:00
Johann Bauer
9de4ca61e8 Increase FORMAT_VERSION to force model re-creation 2022-03-21 18:11:18 +01:00
dependabot[bot]
d7919c45a3 Bump scikit-learn from 0.24.0 to 1.0.2
Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 0.24.0 to 1.0.2.
- [Release notes](https://github.com/scikit-learn/scikit-learn/releases)
- [Commits](https://github.com/scikit-learn/scikit-learn/compare/0.24.0...1.0.2)

---
updated-dependencies:
- dependency-name: scikit-learn
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-21 18:11:18 +01:00
shamoon
d24826a58e Project actions on dev too
[ci skip]
2022-03-21 08:55:21 -07:00
Michael Shamoon
3dfadcc397 prettier 2022-03-21 08:38:01 -07:00
Michael Shamoon
98d677dc0b Merge branch 'main' into dev 2022-03-21 08:36:44 -07:00
shamoon
4f28225188 Merge pull request #462 from paperless-ngx/update-development-documentation
Remove and integrate content from contributing.rst
2022-03-21 08:26:16 -07:00
Michael Shamoon
8059039ef4 Remove and integrate content from contributing.rst 2022-03-20 23:51:10 -07:00
Paperless Translation Bot
682f3fdc3e New Crowdin updates (#423)
* New translations messages.xlf (French)
[ci skip]

* New translations django.po (Luxembourgish)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations django.po (Portuguese, Brazilian)
[ci skip]
2022-03-20 21:09:25 -07:00
shamoon
6f7aaba7fa Add Automatic Project Actions
[ci skip]
2022-03-20 20:53:30 -07:00
Trenton Holmes
ea7a1012b9 Uses a change file action to filter only changed src/ files 2022-03-20 21:50:54 +01:00
Trenton Holmes
f24373699e Disables coveralls step for dependabot branches/pulls 2022-03-20 21:50:54 +01:00
shamoon
f74e15840d Merge pull request #393 from stumpylog/fix-imap-tools-bug
Fix imap tools bug
2022-03-20 13:37:17 -07:00
Schnuffle
c2c8a27545 Corrections to pass pre-commit hooks 2022-03-20 15:58:37 +01:00
shamoon
0979f3c5c3 Merge pull request #446 from MaaxGr/fix-dev-docs
master to main in paperless development docs and CONTRIBUTING.md
2022-03-19 12:01:04 -07:00
shamoon
6f2fd1e2da Merge pull request #449 from paperless-ngx/marbar1-fix-typo
Fix typo: paperles(s)
2022-03-19 11:58:57 -07:00
marbar1
597effc856 Fix typo: paperles(s) 2022-03-19 19:37:52 +01:00
Max
30b3510fbd master to main in CONTRIBUTING.md 2022-03-19 17:37:43 +01:00
Max
0cf9b11c3e master to main in paperless development docs 2022-03-19 17:34:28 +01:00
shamoon
0388ce3e5b Merge pull request #298 from paperless-ngx/feature-loading-screen
Feature: App loading screen
2022-03-19 07:38:21 -07:00
Quinn Casey
1ea6a14437 Merge pull request #443 from paperless-ngx/doc-unraid-template
Update documentation on how to install paperless on Unraid
2022-03-19 17:34:22 +07:00
Felix E
e8a073d538 Merge pull request #440 from addich/fix-374
Allow USERMAP_UID to re-use existing UIDs
2022-03-19 11:04:36 +01:00
Felix E
c8ac686b22 Merge pull request #35 from Tooa/1250-gotenberg-follow-up
fix(gotenberg): use command flags
2022-03-19 11:03:32 +01:00
Felix E
81cfd13b4a Merge pull request #442 from paperless-ngx/fix-allow-shorter-search
Allow shorter search strings with Enter key
2022-03-19 10:24:14 +01:00
Uli
73a3abe535 docs: use link for Unraid store 2022-03-19 09:19:31 +01:00
Uli
9006dd12f3 docs: update Unraid FAQ section 2022-03-19 09:01:53 +01:00
shamoon
2bcbb89175 Merge pull request #419 from paperless-ngx/fix-missing-migration
Add missing migration for savedviewfilterrule
2022-03-18 23:36:14 -07:00
Michael Shamoon
39daddef34 Allow shorter search strings with Enter key 2022-03-18 23:30:26 -07:00
Michael Shamoon
ff4538612e Codestyle cleanup 2022-03-18 21:37:38 -07:00
addi
1782d00cc5 fix issue 374 2022-03-18 23:26:04 +01:00
shamoon
d4f468208e Merge pull request #415 from paperless-ngx/feature-improved-delay-button
Use progress bar for delayed buttons
2022-03-18 08:51:36 -07:00
Quinn Casey
c60b708b9c Merge pull request #324 from stumpylog/more-ci-checks
Align CI checks with pre-commit (mostly)
2022-03-18 18:01:06 +07:00
Michael Shamoon
3dee012415 Use progress bar for button delay 2022-03-17 14:37:21 -07:00
Felix Eckhofer
a1d1fb962b Add missing migration for savedviewfilterrule
Change introduced in d7cefabe98.
2022-03-17 13:19:26 +01:00
shamoon
24e02a6c5f Merge pull request #401 from paperless-ngx/fix-issue-288
Add minimum length for documents text filter
2022-03-17 03:22:19 -07:00
Michael Shamoon
4f352391ae Add minimum length to text filter 2022-03-16 08:46:07 -07:00
Paperless Translation Bot
4667e0bf88 New Crowdin updates (#342)
* New translations django.po (Romanian)
[ci skip]

* New translations django.po (Dutch)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations django.po (Slovenian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations django.po (Polish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]
2022-03-15 20:58:44 -07:00
Trenton Holmes
9544e6c757 Improves the mail handling testing to use more of the imap_tools library types instead of internal types 2022-03-15 16:25:51 -07:00
shamoon
83b5e1a49d Merge pull request #388 from paperless-ngx/update-dirty-check-forms
Update @ngneat/dirty-check-forms to 2.0.0
2022-03-15 15:34:33 -07:00
Trenton Holmes
4f287b5ecd Fixes the EmailAddress which was a dict and is now a class 2022-03-15 14:00:01 -07:00
Michael Shamoon
4c346be367 Update @ngneat/dirty-check-forms to 2.0.0 2022-03-15 13:49:43 -07:00
Michael Shamoon
c87ac6f1ad Add bottom pagination for management lists 2022-03-15 10:17:19 -07:00
shamoon
02dc395880 Merge pull request #366 from paperless-ngx/fix-issue-365
Fix filterable dropdown buttons arent translated
2022-03-15 08:25:09 -07:00
Trenton Holmes
63a3e0b325 Merge pull request #330 from paperless-ngx/dependabot/pip/dev/sphinx-4.4.0
Bump sphinx from 3.4.3 to 4.4.0
2022-03-15 07:45:37 -07:00
Michael Shamoon
01ae5688d7 Add bottom pagination 2022-03-15 00:58:58 -07:00
Michael Shamoon
ec8b10c85b Fix filterable dropdown buttons arent translated 2022-03-14 22:40:45 -07:00
shamoon
19ff8339be Merge pull request #304 from paperless-ngx/pull-request-template
Create PULL_REQUEST_TEMPLATE.md
2022-03-14 16:26:04 -07:00
shamoon
a440b712de Merge pull request #355 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/rxjs-7.5.5
Bump rxjs from 6.6.7 to 7.5.5 in /src-ui
2022-03-14 16:24:26 -07:00
Michael Shamoon
3653045922 rxjs7 compatibility 2022-03-14 16:23:14 -07:00
dependabot[bot]
0d7438e398 Bump rxjs from 6.6.7 to 7.5.5 in /src-ui
Bumps [rxjs](https://github.com/reactivex/rxjs) from 6.6.7 to 7.5.5.
- [Release notes](https://github.com/reactivex/rxjs/releases)
- [Changelog](https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reactivex/rxjs/compare/6.6.7...7.5.5)

---
updated-dependencies:
- dependency-name: rxjs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 23:07:51 +00:00
shamoon
81b17bec69 Merge pull request #353 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/angular/cli-13.2.6
Bump @angular/cli from 13.2.5 to 13.2.6 in /src-ui
2022-03-14 16:06:53 -07:00
dependabot[bot]
e43c446c38 Bump @angular/cli from 13.2.5 to 13.2.6 in /src-ui
Bumps [@angular/cli](https://github.com/angular/angular-cli) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/13.2.5...13.2.6)

---
updated-dependencies:
- dependency-name: "@angular/cli"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 23:03:13 +00:00
shamoon
0cb442c6e0 Merge pull request #354 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/angular/animations-13.2.6
Bump @angular/animations from 13.2.5 to 13.2.6 in /src-ui
2022-03-14 16:02:20 -07:00
dependabot[bot]
17ea079fcd Bump @angular/animations from 13.2.5 to 13.2.6 in /src-ui
Bumps [@angular/animations](https://github.com/angular/angular/tree/HEAD/packages/animations) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.2.6/packages/animations)

---
updated-dependencies:
- dependency-name: "@angular/animations"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 22:58:58 +00:00
shamoon
2270aefdee Merge pull request #352 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/angular/common-13.2.6
Bump @angular/common from 13.2.5 to 13.2.6 in /src-ui
2022-03-14 15:58:03 -07:00
shamoon
30828bcbe0 Merge pull request #356 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/popperjs/core-2.11.4
Bump @popperjs/core from 2.11.2 to 2.11.4 in /src-ui
2022-03-14 15:50:13 -07:00
dependabot[bot]
4667adc64d Bump sphinx from 3.4.3 to 4.4.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.4.3 to 4.4.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/4.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.4.3...v4.4.0)

---
updated-dependencies:
- dependency-name: sphinx
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 22:29:17 +00:00
dependabot[bot]
de779d453c Bump imap-tools from 0.52.0 to 0.53.0
Bumps [imap-tools](https://github.com/ikvk/imap_tools) from 0.52.0 to 0.53.0.
- [Release notes](https://github.com/ikvk/imap_tools/releases)
- [Changelog](https://github.com/ikvk/imap_tools/blob/master/docs/release_notes.rst)
- [Commits](https://github.com/ikvk/imap_tools/compare/v0.52.0...v0.53.0)

---
updated-dependencies:
- dependency-name: imap-tools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 23:23:12 +01:00
dependabot[bot]
fe959b30c6 Bump pytest from 7.0.1 to 7.1.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.0.1 to 7.1.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.0.1...7.1.0)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 23:22:39 +01:00
dependabot[bot]
3fcbb17a15 Bump @popperjs/core from 2.11.2 to 2.11.4 in /src-ui
Bumps [@popperjs/core](https://github.com/popperjs/popper-core) from 2.11.2 to 2.11.4.
- [Release notes](https://github.com/popperjs/popper-core/releases)
- [Commits](https://github.com/popperjs/popper-core/compare/v2.11.2...v2.11.4)

---
updated-dependencies:
- dependency-name: "@popperjs/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 20:21:40 +00:00
dependabot[bot]
cdfde1d91f Bump @angular/common from 13.2.5 to 13.2.6 in /src-ui
Bumps [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.2.6/packages/common)

---
updated-dependencies:
- dependency-name: "@angular/common"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 20:19:28 +00:00
dependabot[bot]
64a5b24e12 Bump ocrmypdf from 13.4.0 to 13.4.1
Bumps [ocrmypdf](https://github.com/jbarlow83/ocrmypdf) from 13.4.0 to 13.4.1.
- [Release notes](https://github.com/jbarlow83/ocrmypdf/releases)
- [Changelog](https://github.com/ocrmypdf/OCRmyPDF/blob/master/docs/release_notes.rst)
- [Commits](https://github.com/jbarlow83/ocrmypdf/compare/v13.4.0...v13.4.1)

---
updated-dependencies:
- dependency-name: ocrmypdf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 19:39:06 +01:00
Trenton Holmes
7d29bd216d Adds back certain dependencies under certain Python versions to fix dependabot 2022-03-14 19:08:11 +01:00
Simon Siebert
1abd7cc2a0 Fixing Test 2022-03-14 19:03:09 +01:00
Simon Siebert
78608d92b4 Fixing code formating 2022-03-14 19:03:09 +01:00
Simon Siebert
54cbacf4f4 Update parsers.py and test_consumer.py 2022-03-14 19:03:09 +01:00
shamoon
b43aae84ab Merge pull request #247 from paperless-ngx/locale-chinese-simplified
Add Chinese localization
2022-03-14 07:22:28 -07:00
shamoon
9d9789953b Merge pull request #322 from paperless-ngx/fix-sphinx-errors
Fix minor sphinx errors
2022-03-14 06:49:25 -07:00
Paperless Translation Bot
614eb930d3 New Crowdin updates (#308)
* New translations messages.xlf (Slovenian)
[ci skip]

* New translations django.po (Polish)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations django.po (Polish)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]
2022-03-13 21:18:34 -07:00
dependabot[bot]
62094a2098 Bump @angular-devkit/build-angular from 13.2.5 to 13.2.6 in /src-ui (#329)
Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/13.2.5...13.2.6)

---
updated-dependencies:
- dependency-name: "@angular-devkit/build-angular"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-13 21:17:43 -07:00
dependabot[bot]
84ed805fd7 Bump karma-chrome-launcher from 3.1.0 to 3.1.1 in /src-ui (#328)
Bumps [karma-chrome-launcher](https://github.com/karma-runner/karma-chrome-launcher) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/karma-runner/karma-chrome-launcher/releases)
- [Changelog](https://github.com/karma-runner/karma-chrome-launcher/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma-chrome-launcher/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: karma-chrome-launcher
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-13 21:14:49 -07:00
dependabot[bot]
82a158e803 Bump @angular/localize from 13.2.5 to 13.2.6 in /src-ui (#327)
Bumps [@angular/localize](https://github.com/angular/angular) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/compare/13.2.5...13.2.6)

---
updated-dependencies:
- dependency-name: "@angular/localize"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-13 21:11:11 -07:00
dependabot[bot]
1527ae1472 Bump @angular/router from 13.2.5 to 13.2.6 in /src-ui (#326)
Bumps [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.2.6/packages/router)

---
updated-dependencies:
- dependency-name: "@angular/router"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-13 21:03:27 -07:00
dependabot[bot]
5d1e86fdc3 Bump @angular/forms from 13.2.5 to 13.2.6 in /src-ui (#325)
Bumps [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) from 13.2.5 to 13.2.6.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md)
- [Commits](https://github.com/angular/angular/commits/13.2.6/packages/forms)

---
updated-dependencies:
- dependency-name: "@angular/forms"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-13 21:00:13 -07:00
shamoon
a6d2a390f0 Add review groups 2022-03-13 20:54:06 -07:00
Michael Shamoon
a47ec7c77d Add timeout warning 2022-03-13 20:45:14 -07:00
Trenton Holmes
ee1404d99e Adds additional CI checks for the backend and frontend, to complement pre-commit hooks which should already be run 2022-03-13 19:37:34 -07:00
shamoon
2caba558d7 Revert "Bump sphinx from 3.4.3 to 4.4.0" (#323) 2022-03-13 19:27:02 -07:00
shamoon
5e4119f6a9 Merge pull request #183 from paperless-ngx/dependabot/pip/dev/sphinx-4.4.0
Bump sphinx from 3.4.3 to 4.4.0
2022-03-13 19:06:42 -07:00
Michael Shamoon
6b46b43367 Fix minor sphinx errors 2022-03-13 17:48:17 -07:00
shamoon
460f10f46a Merge pull request #314 from paperless-ngx/fix-issue-312
Fix page links hidden
2022-03-13 16:31:57 -07:00
Michael Shamoon
37c6201a5a Add Chinese localization
Addresses https://github.com/paperless-ngx/paperless-ngx/issues/134#issuecomment-1062950795
2022-03-13 14:26:52 -07:00
shamoon
4184988c0c Merge pull request #315 from paperless-ngx/locale-slovenian
Add Slovenian language for frontend
2022-03-13 14:24:59 -07:00
Trenton Holmes
3264015dac Merge pull request #296 from stumpylog/ci-cache-venv
Updates actions to use GHA Python pipenv caching
2022-03-13 14:00:23 -07:00
Michael Shamoon
d1c785d1d0 Add Slovenian language for frontend
See #303
2022-03-13 09:15:42 -07:00
Michael Shamoon
abd63df75b Fix page links hidden
Closes #312
2022-03-13 09:05:29 -07:00
Michael Shamoon
57f35292d5 Fix dark mode selected table row background color 2022-03-13 08:45:39 -07:00
Michael Shamoon
7bd6f4a4ea Prevent event collision 2022-03-13 08:41:36 -07:00
Trenton Holmes
35de8e6ad5 Changes the pipenv install to be a sync 2022-03-13 08:20:40 -07:00
Trenton Holmes
1549edfd55 Changes codestyle and documentation steps to use cache as well 2022-03-13 08:07:28 -07:00
Trenton Holmes
f33cf6cc2e Fixes coveralls not running 2022-03-13 08:07:28 -07:00
Trenton Holmes
3a8cffe3ce Removes duplicated install of pipenv, changes to use pipx as per the official example 2022-03-13 08:07:28 -07:00
Trenton Holmes
58066443de Updates GHA to use the setup-python pipenv caching 2022-03-13 08:07:28 -07:00
shamoon
20566b6571 Add note to include how to test 2022-03-13 04:14:00 -07:00
shamoon
af52544792 Update PR template with suggestions 2022-03-13 03:56:59 -07:00
Paperless Translation Bot
594445f6dd New Crowdin updates (#305)
* New translations django.po (Slovenian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]
2022-03-13 03:20:56 -07:00
shamoon
c3e86f0f21 Merge pull request #306 from lippoliv/feature-ignore-vscode-folder
ignore vscode folder
2022-03-13 01:22:34 -08:00
Oliver Lippert
d80102a7a4 ignore .vscode folder
Signed-off-by: Oliver Lippert <oliver@allesit.de>
2022-03-13 10:17:42 +01:00
Paperless Translation Bot
e886c38b45 New translations messages.xlf (Slovenian) (#303)
[ci skip]
2022-03-13 01:16:46 -08:00
shamoon
33a5823801 Update PULL_REQUEST_TEMPLATE.md 2022-03-13 01:15:15 -08:00
shamoon
b220d15fff Create PULL_REQUEST_TEMPLATE.md 2022-03-13 01:08:49 -08:00
Tooa
6fb856ee70 fix(gotenberg): use command flags
Gotenberg v7 does not use environment variables anymore, but command's flags.

See: https://gotenberg.dev/docs/get-started/docker-compose#modules-properties
2022-03-13 07:40:31 +01:00
Paperless Translation Bot
3922588716 New Crowdin updates (#292)
* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations django.po (Slovak)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations django.po (Slovak)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]
2022-03-12 20:24:22 -08:00
shamoon
940b12a908 Merge pull request #297 from stumpylog/dependabot-gha-updates
Enable dependabot GHA updates
2022-03-12 20:12:28 -08:00
Michael Shamoon
db5349881d App loading screen 2022-03-12 20:09:16 -08:00
Trenton Holmes
0edfe83a23 Enables dependabot for Github Action versions 2022-03-12 18:03:39 -08:00
Oliver Lippert
7abc6440f6 add link to setup instructions for bare metal (#221) 2022-03-12 08:43:12 -08:00
Quinn Casey
168ce2111d Merge pull request #278 from stumpylog/pre-commit-python-changes
Python Cleanup from pre-commit
2022-03-12 08:09:13 -08:00
Paperless Translation Bot
617d0bfee7 New translations messages.xlf (Portuguese, Brazilian) (#286)
[ci skip]
2022-03-12 03:10:58 -08:00
Quinn Casey
0d0da0d623 Merge pull request #275 from paperless-ngx/org-membership
Add Organization Structure & Membership
2022-03-11 12:39:42 -08:00
Trenton Holmes
dc657f2eb0 Maybe make CodeQL happy about this exception handling 2022-03-11 12:39:40 -08:00
shamoon
ef2b4a7536 Merge pull request #276 from paperless-ngx/prettier-cleanup-ts-js-md
Prettier cleanup for .ts .js and .md files
2022-03-11 12:31:21 -08:00
Michael Shamoon
e41d75c374 Prettier code cleanup for PR #273 2022-03-11 12:00:31 -08:00
Michael Shamoon
eb55f5655f Prettier code cleanup for .md files 2022-03-11 11:58:19 -08:00
Michael Shamoon
9f72bf7745 Prettier code cleanup for .js files
See #182
2022-03-11 11:58:19 -08:00
Michael Shamoon
f34202a82a Prettier code cleanup for .ts files
See #182
2022-03-11 11:58:19 -08:00
shamoon
f8c8161a3e Merge pull request #273 from GruberViktor/dev
Added nav buttons in the document detail view
2022-03-11 11:57:03 -08:00
GruberViktor
63aafd3133 remove automatic focus on title in document-detail view
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2022-03-11 20:54:24 +01:00
Trenton Holmes
e2303235cd Fixes what looks like a conflict between black and flake8 2022-03-11 11:34:32 -08:00
Trenton Holmes
1771d18a21 Runs the pre-commit hooks over all the Python files 2022-03-11 11:34:28 -08:00
GruberViktor
d02a0b2213 remove text from close-button in the document-detail view
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2022-03-11 20:22:39 +01:00
GruberViktor
6cbbd0c515 Apply suggestions from code review
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2022-03-11 20:16:53 +01:00
Quinn Casey
cae26f4f70 Fix typo 2022-03-11 11:01:24 -08:00
dependabot[bot]
f328d1461f Bump sphinx from 3.4.3 to 4.4.0
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.4.3 to 4.4.0.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/4.x/CHANGES)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.4.3...v4.4.0)

---
updated-dependencies:
- dependency-name: sphinx
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-11 18:56:10 +00:00
Quinn Casey
d3e9799279 Merge pull request #182 from stumpylog/pre-commit-hooks
Adds pre-commit hooks for linting and formatting
2022-03-11 10:50:04 -08:00
Paperless Translation Bot
14eefe1f5d New Crowdin updates (#265)
* New translations django.po (Portuguese)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations django.po (German)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]
2022-03-11 10:49:59 -08:00
Trenton Holmes
6c2cc4cf50 Configures prettier formatting further 2022-03-11 10:32:25 -08:00
shamoon
440f4729ac Merge pull request #253 from paperless-ngx/feature-better-date-keyboard-input
Improve date keyboard input
2022-03-11 10:27:56 -08:00
Quinn Casey
e1c6042189 Add Organization Structure & Membership 2022-03-11 10:23:59 -08:00
Quinn Casey
55a057307c Merge pull request #274 from paperless-ngx/add-code-of-conduct-1
Add `CODE_OF_CONDUCT.md`
2022-03-11 09:44:50 -08:00
Trenton Holmes
8a5176e593 Updates the documentation to include installation of the pre-commit hooks 2022-03-11 09:26:41 -08:00
Quinn Casey
a757778fba Create CODE_OF_CONDUCT.md 2022-03-11 09:09:48 -08:00
Viktor
1259911275 Added nav buttons in the document detail view
Sometimes, when you are looking for a document, you need to go into the document-detail view
to read the pdf. To view the next document in the detail view, normally you would go back and
then click on the next.

Here I added two buttons to the toolbar to traverse throught the documents easily.
2022-03-11 17:35:38 +01:00
Michael Shamoon
4e4035a867 Fix enter key was prevented 2022-03-11 08:11:35 -08:00
shamoon
9bd87e78dc Merge pull request #263 from paperless-ngx/fix-dropdown-count
Fix: Include excluded items in dropdown count
2022-03-11 08:08:54 -08:00
Trenton Holmes
12a1c4ccbf Ensures Pipfile and requirements are up to date 2022-03-11 07:07:28 -08:00
Trenton Holmes
888e17cb91 Removes flake8 ignored warnings and errors, as black formatting will take care of almost all of these 2022-03-11 07:07:28 -08:00
Trenton Holmes
0fa48cea2a Updates the beautysh hook to use tabs, as this reduces the diff of the output. Updates .editorconfig to use spaces in Markdown files to match prettier formatting 2022-03-11 07:07:27 -08:00
Trenton Holmes
9b7d393d5d Removes migrations exclusion from black formatting 2022-03-11 07:07:27 -08:00
Trenton Holmes
cc702cbdfa Adds commenting and a little organization to the hook configuration 2022-03-11 07:07:26 -08:00
Trenton Holmes
e8ddb0c427 Removes tslint which doesn't work. Adds exclusions of the migrations folder to Python related hooks 2022-03-11 07:07:26 -08:00
Trenton Holmes
feb677e656 Adds and configures pre-commit hooks for linting and formatting during development 2022-03-11 07:07:25 -08:00
Quinn Casey
c19dd81ecf Merge pull request #242 from stumpylog/resolve-test-warnings
Reduce warnings in test suite
2022-03-11 05:54:19 -08:00
shamoon
01a50a3a98 Merge pull request #262 from kpj/fix-install_url
Fix install url in docs
2022-03-11 01:27:18 -08:00
Michael Shamoon
8920a32c75 Include excluded items in dropdown count 2022-03-11 01:17:19 -08:00
Michael Shamoon
4773d0bb7f semicolons 2022-03-11 01:03:43 -08:00
Michael Shamoon
20a6c5e7b7 more code cleanup 2022-03-11 00:52:32 -08:00
Michael Shamoon
0826e0f96b code cleanup 2022-03-11 00:48:06 -08:00
Kim
bd374f4c36 Also update other occurrences of master branch to main 2022-03-11 09:45:44 +01:00
Kim
bac8849f2d Use main instead of master branch in install URL 2022-03-11 09:39:01 +01:00
Michael Shamoon
ad87c3c87d Fix dropdown inputs 2022-03-11 00:29:59 -08:00
Michael Shamoon
4c7eb34290 Move padding into date formatter 2022-03-11 00:28:06 -08:00
Michael Shamoon
a1fd9f7310 Limit date input field chars and length 2022-03-11 00:11:59 -08:00
Michael Shamoon
9433908218 Delineate -ngx from -ng in changelog 2022-03-10 23:15:12 -08:00
shamoon
8f1c4cd9c4 Merge pull request #243 from paperless-ngx/css-variables
Custom color theming
2022-03-10 19:26:15 -08:00
Trenton Holmes
85b210ebf6 Reduces number of warnings from testing from 165 to 128. In doing so, fixes a few minor things in the decrypt and export commands 2022-03-10 18:12:48 -08:00
Michael Shamoon
af7ffa3878 Allow date dropdowns to use new formatter 2022-03-10 16:48:03 -08:00
Michael Shamoon
96a84d16a6 Merge branch 'main' into dev 2022-03-10 16:40:38 -08:00
Michael Shamoon
0737ea30e8 fix comment 2022-03-10 15:27:02 -08:00
Michael Shamoon
1807811903 Allow formatting non-padded dates 2022-03-10 15:17:32 -08:00
Michael Shamoon
a33dce1948 Code formatting 2022-03-10 15:17:32 -08:00
Michael Shamoon
ef4dc1b49e strip all delimiters 2022-03-10 15:17:31 -08:00
Michael Shamoon
0f886be109 semicolon 2022-03-10 15:17:31 -08:00
shamoon
73a597855f Merge pull request #250 from GruberViktor/date_parser
Parse dates when entered without separators
2022-03-10 15:16:50 -08:00
Quinn Casey
86d9c94962 Fix failed docker run on multi-tags 2022-03-10 14:58:28 -08:00
Quinn Casey
21ec2dfa68 Merge pull request #251 from paperless-ngx/dependabot-label-fix
Make dependabot labels consistent
2022-03-10 14:06:28 -08:00
Quinn Casey
296d1d1b61 Make dependabot labels consistent 2022-03-10 14:01:58 -08:00
Michael Shamoon
af536dfefb Fix outline buttons become invisible in light mode 2022-03-10 13:59:31 -08:00
Michael Shamoon
7d7c5207d7 Fix changing theme incorrectly affects dark mode settings 2022-03-10 13:56:22 -08:00
Viktor
52f0a3dfb9 Parse dates when entered without separators
This adds date dividers if none are entered.
It also adds the current year if it wasn't entered.

This allows users to just enter 1003, 100322, 10032022 and
have it expanded to 10.03.2022, in the case of the German format.
(All other formats are also supported)

It also replaces commas with the date divider.
This allows quick entry of the date on the numpad.
2022-03-10 21:31:54 +01:00
Quinn Casey
4532bed7bc 1.6.0 2022-03-10 12:09:19 -08:00
shamoon
d3bccc049b 1.6.0
[skip ci]
2022-03-10 12:03:00 -08:00
shamoon
333321e600 Merge pull request #213 from paperless-ngx/beta
Merge 1.6.0 Release Candidate
2022-03-10 12:01:31 -08:00
Ingo Sigmund
081f11af40 Merge pull request #214 from isigmund/dev 2022-03-10 15:09:33 +01:00
Ingo Sigmund
9f0f458a02 Merge pull request #23 from flofeld/patch-1 2022-03-10 15:06:12 +01:00
Paperless Translation Bot
e74c716588 New Crowdin updates (#244)
* New translations django.po (Italian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]
2022-03-09 16:21:06 -08:00
Florian Feldmann
89bd0791dc Apply suggestions from code review
Co-authored-by: Ingo Sigmund <Ingo.sigmund@web.de>
2022-03-10 01:11:23 +01:00
Michael Shamoon
a591614a39 Component methods arent really private 2022-03-09 15:43:06 -08:00
Michael Shamoon
0085c8351e Prevent overriding other settings 2022-03-09 15:40:04 -08:00
Michael Shamoon
4df7f92a56 Working conversion 2022-03-09 15:34:26 -08:00
Michael Shamoon
1841cefbd8 Converting colors experiment 2022-03-09 15:19:42 -08:00
Michael Shamoon
f13ae930a5 Allow non-hex color modes from color component 2022-03-09 14:12:39 -08:00
Michael Shamoon
dbe233f0ae Skeleton implementation of color setting 2022-03-09 14:12:28 -08:00
Michael Shamoon
17e5f6d76b refactor variable names 2022-03-09 11:13:58 -08:00
Michael Shamoon
f52d167da3 fix some missed focus styles 2022-03-09 11:10:26 -08:00
Michael Shamoon
63aa7128a7 Increase contrast for dark mode colored buttons 2022-03-08 16:48:31 -08:00
Michael Shamoon
d30a652fc1 Make correspondent links on cards buttons 2022-03-08 16:45:36 -08:00
Michael Shamoon
1cd0684f62 tweak dark mode bg coloring 2022-03-08 16:41:56 -08:00
Michael Shamoon
bc97a13a62 fix logo coloring, saved view widget link, card coloring 2022-03-08 16:41:49 -08:00
Michael Shamoon
db98eed392 fix some light mode stuff due to specificity 2022-03-08 16:28:58 -08:00
Michael Shamoon
76115d6a81 checkbox focus color 2022-03-08 16:05:21 -08:00
Michael Shamoon
9e2fd52434 tab switching styling 2022-03-08 16:03:32 -08:00
Michael Shamoon
7ca12c3dc4 toasts 2022-03-08 16:02:16 -08:00
Michael Shamoon
3dffa09977 fix some focus styling 2022-03-08 15:50:10 -08:00
Michael Shamoon
7c313eed33 unify some button colors 2022-03-08 15:38:16 -08:00
Michael Shamoon
383cf7f4d5 fix some buttons, focus shadow 2022-03-08 15:22:17 -08:00
Michael Shamoon
4babf0d102 Initial conversion to css variables 2022-03-08 14:49:40 -08:00
Quinn Casey
df4567f9e4 Merge pull request #236 from stumpylog/minimal-pipfile
Remove non-direct dependencies from Pipfile
2022-03-08 06:25:58 -08:00
Quinn Casey
db2bf66eee Merge pull request #235 from paperless-ngx/1.6.0-rc1-dependency-updates
Update @angular/common, @angular/forms, @angular/platform-browser, ts-node, @angular/router
2022-03-08 06:12:49 -08:00
Michael Shamoon
36eaafa52a Update @angular/common, @angular/forms, @angular/platform-browser, ts-node, @angular/router
Closes #228
Closes #229
Closes #230
Closes #231
Closes #232
2022-03-07 13:07:04 -08:00
Trenton Holmes
f4d09d46f4 Removes certain packages from the Pipfile 2022-03-07 12:15:16 -08:00
shamoon
01c1b42319 Merge pull request #226 from paperless-ngx/fix-issue-225-management-page-filtering
Fix issue #225 management page filtering, add esc clearing of filter field
2022-03-07 10:50:52 -08:00
Michael Shamoon
472a3a54ab Allow esc key clearing, autofocus on management lists 2022-03-07 09:45:58 -08:00
Michael Shamoon
9fbf9923dc Page parameter breaks filtering on mangement pages
Closes #225
2022-03-07 09:45:39 -08:00
Ingo Sigmund
9d3242c13e Merge branch 'dev' of https://github.com/isigmund/paperless-ngx into dev 2022-03-06 18:03:24 +01:00
Ingo Sigmund
08c6a21bbb Revert "remove logic to delete dangling volumes: node"
This reverts commit c2da0ce521.
2022-03-06 18:03:19 +01:00
Ingo Sigmund
7d18be9928 Merge branch 'paperless-ngx:dev' into dev 2022-03-06 17:43:57 +01:00
Quinn Casey
748fe3b89f Merge pull request #219 from paperless-ngx/1.6.0-rc1-frontend-fixes1
1.6.0 rc1 frontend fixes 1
2022-03-06 08:38:34 -08:00
Michael Shamoon
b383e7dd08 Reduce debounce to avoid title erasing
Closes #216
2022-03-05 20:12:17 -08:00
Michael Shamoon
33ab69e010 Clone tags array to prevent false dirty check
Closes #215
2022-03-05 20:12:17 -08:00
shamoon
c52070d554 Merge pull request #212 from paperless-ngx/l10n_dev
New Crowdin updates
2022-03-05 20:10:52 -08:00
Quinn Casey
1d67c32351 [skip ci] Add variable body to fix incorrect changelog 2022-03-05 14:49:52 -08:00
Paperless Translation Bot
23d6589a73 New translations messages.xlf (Spanish)
[ci skip]
2022-03-05 08:50:51 -08:00
Ingo Sigmund
3ae73e7df5 Merge branch 'paperless-ngx:dev' into dev 2022-03-05 12:12:42 +01:00
Paperless Translation Bot
8f3f60d249 New translations messages.xlf (Spanish)
[ci skip]
2022-03-05 03:09:56 -08:00
Ingo Sigmund
16664789d2 remove volume: if no named volumes are used 2022-03-05 12:07:52 +01:00
Paperless Translation Bot
f97aae1fd8 New translations django.po (Luxembourgish)
[ci skip]
2022-03-04 15:16:09 -08:00
Paperless Translation Bot
7e1bbecc9f New translations django.po (German)
[ci skip]
2022-03-04 15:16:08 -08:00
Paperless Translation Bot
376a56df26 New translations django.po (Luxembourgish)
[ci skip]
2022-03-04 14:17:33 -08:00
Quinn Casey
c41b86eb68 [skip ci] Add #24 to changelog 2022-03-04 13:17:24 -08:00
Ingo Sigmund
e75ea257e8 Correct install script (stop creating unused named volumes) 2022-03-03 15:17:54 +01:00
shamoon
630cdaf08f Add documents screenshots w browser chrome 2022-02-25 01:26:34 -08:00
shamoon
140b179607 Merge pull request #125 from paperless-ngx/stalebot
Add stale.yml
2022-02-21 18:17:36 -08:00
shamoon
c8ad4e9bcd Add fixpending label to prevent stale 2022-02-21 16:11:22 -08:00
shamoon
49bc8f95f6 Update stale.yml 2022-02-21 16:05:21 -08:00
shamoon
50bab47f43 Create stale.yml 2022-02-21 14:43:33 -08:00
Stéphane Brunner
785fcfb998 Use the image on ghcr.io (#104) 2022-02-20 09:23:18 +01:00
Johann Bauer
c7541cb516 Enable dependabot for repository (#86) 2022-02-18 16:06:56 +01:00
Florian Feldmann
7680bf7c0d Added a sentence about python-dotenv format
Something like this would have helped me to get the configuration right without debugging
2021-08-09 12:15:01 +02:00
400 changed files with 40298 additions and 13491 deletions

View File

@@ -17,3 +17,5 @@
**/htmlcov
/src/.pytest_cache
.idea
.venv/
.vscode/

View File

@@ -18,14 +18,20 @@ max_line_length = off
indent_size = 4
indent_style = space
[*.yml]
[*.{yml,yaml}]
indent_style = space
[*.rst]
indent_style = space
[*.md]
indent_style = space
# Tests don't get a line width restriction. It's still a good idea to follow
# the 79 character rule, but in the interests of clarity, tests often need to
# violate it.
[**/test_*.py]
max_line_length = off
[Dockerfile]
indent_style = space

2
.env
View File

@@ -1,2 +1,2 @@
COMPOSE_PROJECT_NAME=paperless
export PROMPT="(pipenv-projectname)$P$G"
export PROMPT="(pipenv-projectname)$P$G"

View File

@@ -1,10 +1,9 @@
---
name: Bug report
about: Something is not working
title: "[BUG] Concise description of the issue"
title: '[BUG] Concise description of the issue'
labels: ''
assignees: ''
---
<!---
@@ -24,6 +23,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@@ -36,13 +36,15 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Webserver logs**
```
If available, post any logs from the web server related to your issue.
```
**Relevant information**
- Host OS of the machine running paperless: [e.g. Archlinux / Ubuntu 20.04]
- Browser [e.g. chrome, safari]
- Version [e.g. 1.0.0]
- Installation method: [docker / bare metal]
- Any configuration changes you made in `docker-compose.yml`, `docker-compose.env` or `paperless.conf`.
- Host OS of the machine running paperless: [e.g. Archlinux / Ubuntu 20.04]
- Browser [e.g. chrome, safari]
- Version [e.g. 1.0.0]
- Installation method: [docker / bare metal]
- Any configuration changes you made in `docker-compose.yml`, `docker-compose.env` or `paperless.conf`.

View File

@@ -1,10 +1,9 @@
---
name: Other
about: Anything that is not a feature request or bug.
title: "[Other] Title of your issue"
title: '[Other] Title of your issue'
labels: ''
assignees: ''
---
<!--

40
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,40 @@
<!--
Note: All PRs with code changes should be targeted to the `dev` branch, pure documentation changes can target `main`
-->
## Proposed change
<!--
Please include a summary of the change and which issue is fixed (if any) and any relevant motivation / context. List any dependencies that are required for this change. If appropriate, please include an explanation of how your poposed change can be tested. Screenshots and / or videos can also be helpful if appropriate.
-->
Fixes # (issue)
<!--
Please also tag the relevant team to help with review. You can tag any of the following:
@paperless-ngx/backend (Python / django, database, etc.)
@paperless-ngx/frontend (JavaScript/Typescript, HTML, CSS, etc.)
@paperless-ngx/ci-cd (GitHub Actions, deployment)
@paperless-ngx/test (General testing for larger PRs)
-->
## Type of change
<!--
What type of change does your PR introduce to Paperless-ngx?
NOTE: Please check only one box!
-->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Other (please explain)
## Checklist:
- [ ] I have read & agree with the [contributing guidelines](https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md).
- [ ] If applicable, I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers.
- [ ] If applicable, I have checked that all tests pass, see [documentation](https://paperless-ngx.readthedocs.io/en/latest/extending.html#back-end-development).
- [ ] I have run all `pre-commit` hooks, see [documentation](https://paperless-ngx.readthedocs.io/en/latest/extending.html#code-formatting-with-pre-commit-hooks).
- [ ] I have made corresponding changes to the documentation as needed.
- [ ] I have checked my modifications for any breaking changes.

View File

@@ -8,9 +8,12 @@ updates:
target-branch: "dev"
# Look for `package.json` and `lock` files in the `root` directory
directory: "/src-ui"
# Check the npm registry for updates every week
# Check the npm registry for updates every month
schedule:
interval: "weekly"
interval: "monthly"
# Add reviewers
reviewers:
- "paperless-ngx/frontend"
# Enable version updates for Python
- package-ecosystem: "pip"
@@ -20,3 +23,19 @@ updates:
# Check for updates once a week
schedule:
interval: "weekly"
labels:
- "backend"
- "dependencies"
# Enable updates for Github Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every month
interval: "monthly"
labels:
- "ci-cd"
- "dependencies"
# Add reviewers
reviewers:
- "paperless-ngx/backend"

View File

@@ -13,90 +13,100 @@ on:
jobs:
documentation:
name: "Build Documentation"
runs-on: ubuntu-20.04
steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
-
name: Install pipenv
run: pipx install pipenv
-
name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v3
with:
python-version: 3.9
-
name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
-
name: Persistent Github pip cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip3.8}
cache: "pipenv"
cache-dependency-path: 'Pipfile.lock'
-
name: Install dependencies
run: |
pip install --upgrade pipenv
pipenv install --system --dev --ignore-pipfile
pipenv sync --dev
-
name: Make documentation
run: |
cd docs/
make html
pipenv run make html
-
name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: documentation
path: docs/_build/html/
codestyle:
code-checks-backend:
name: "Backend Code Checks"
runs-on: ubuntu-20.04
steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
-
name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
-
name: Get pip cache dir
id: pip-cache
name: Install checkers
run: |
echo "::set-output name=dir::$(pip cache dir)"
pipx install reorder-python-imports
pipx install yesqa
pipx install add-trailing-comma
pipx install flake8
-
name: Persistent Github pip cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip${{ matrix.python-version }}
-
name: Install dependencies
name: Run reorder-python-imports
run: |
pip install --upgrade pipenv
pipenv install --system --dev --ignore-pipfile
find src/ -type f -name '*.py' ! -path "*/migrations/*" | xargs reorder-python-imports
-
name: Codestyle
name: Run yesqa
run: |
cd src/
pycodestyle --max-line-length=88 --ignore=E121,E123,E126,E226,E24,E704,W503,W504,E203
codeformatting:
runs-on: ubuntu-20.04
steps:
find src/ -type f -name '*.py' ! -path "*/migrations/*" | xargs yesqa
-
name: Checkout
uses: actions/checkout@v2
name: Run add-trailing-comma
run: |
find src/ -type f -name '*.py' ! -path "*/migrations/*" | xargs add-trailing-comma
# black is placed after add-trailing-comma because it may format differently
# if a trailing comma is added
-
name: Run black
uses: psf/black@stable
with:
options: "--check --diff"
version: "22.1.0"
version: "22.3.0"
-
name: Run flake8 checks
run: |
cd src/
flake8 --max-line-length=88 --ignore=E203,W503
tests:
code-checks-frontend:
name: "Frontend Code Checks"
runs-on: ubuntu-20.04
steps:
-
name: Checkout
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
-
name: Install prettier
run: |
npm install prettier
-
name: Run prettier
run:
npx prettier --check --ignore-path Pipfile.lock **/*.js **/*.ts *.md **/*.md
tests-backend:
needs: [code-checks-backend]
name: "Backend Tests (${{ matrix.python-version }})"
runs-on: ubuntu-20.04
strategy:
matrix:
@@ -105,73 +115,93 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 2
-
name: Install pipenv
run: pipx install pipenv
-
name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v3
with:
python-version: "${{ matrix.python-version }}"
cache: "pipenv"
cache-dependency-path: 'Pipfile.lock'
-
name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
-
name: Persistent Github pip cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip${{ matrix.python-version }}
-
name: Install dependencies
name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -qq --no-install-recommends unpaper tesseract-ocr imagemagick ghostscript optipng
pip install --upgrade pipenv
pipenv install --system --dev --ignore-pipfile
-
name: Install Python dependencies
run: |
pipenv sync --dev
-
name: Tests
run: |
cd src/
pytest
pipenv run pytest
-
name: Get changed files
id: changed-files-specific
uses: tj-actions/changed-files@v18.1
with:
files: |
src/**
-
name: List all changed files
run: |
for file in ${{ steps.changed-files-specific.outputs.all_changed_files }}; do
echo "${file} was changed"
done
-
name: Publish coverage results
if: matrix.python-version == '3.9'
if: matrix.python-version == '3.9' && steps.changed-files-specific.outputs.any_changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# https://github.com/coveralls-clients/coveralls-python/issues/251
run: |
cd src/
coveralls --service=github
pipenv run coveralls --service=github
tests-frontend:
needs: [code-checks-frontend]
name: "Frontend Tests"
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: cd src-ui && npm ci
- run: cd src-ui && npm run test
- run: cd src-ui && npm run e2e:ci
# build and push image to docker hub.
build-docker-image:
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/beta' || startsWith(github.ref, 'refs/tags/ngx-') || startsWith(github.ref, 'refs/tags/beta-'))
runs-on: ubuntu-latest
needs: [tests, codeformatting, codestyle]
runs-on: ubuntu-20.04
needs: [tests-backend, tests-frontend]
steps:
-
name: Prepare
id: prepare
run: |
IMAGE_NAME=ghcr.io/${{ github.repository }}
if [[ $GITHUB_REF == refs/tags/ngx-* ]]; then
TAGS=${IMAGE_NAME}:${GITHUB_REF#refs/tags/ngx-},${IMAGE_NAME}:latest
INSPECT_TAG=${IMAGE_NAME}:latest
elif [[ $GITHUB_REF == refs/tags/beta-* ]]; then
TAGS=${IMAGE_NAME}:beta
INSPECT_TAG=${TAGS}
elif [[ $GITHUB_REF == refs/heads/* ]]; then
TAGS=${IMAGE_NAME}:${GITHUB_REF#refs/heads/}
INSPECT_TAG=${TAGS}
else
exit 1
fi
echo ::set-output name=tags::${TAGS}
echo ::set-output name=inspect_tag::${INSPECT_TAG}
name: Gather Docker metadata
id: docker-meta
uses: docker/metadata-action@v3
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=match,pattern=ngx-(\d.\d.\d),group=1
type=semver,pattern=ngx-{{version}}
type=semver,pattern=ngx-{{major}}.{{minor}}
type=ref,event=branch
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
@@ -192,36 +222,37 @@ jobs:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm/v7,linux/arm64
push: true
tags: ${{ steps.prepare.outputs.tags }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker-meta.outputs.tags }}
labels: ${{ steps.docker-meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
-
name: Inspect image
run: |
docker buildx imagetools inspect ${{ steps.prepare.outputs.inspect_tag }}
docker buildx imagetools inspect ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }}
-
name: Export frontend artifact from docker
run: |
docker run -d --name frontend-extract ${{ steps.prepare.outputs.tags }}
docker create --name frontend-extract ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }}
docker cp frontend-extract:/usr/src/paperless/src/documents/static/frontend src/documents/static/frontend/
-
name: Upload frontend artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: frontend-compiled
path: src/documents/static/frontend/
build-release:
needs: [build-docker-image, documentation, tests, codeformatting, codestyle]
needs: [build-docker-image, documentation]
runs-on: ubuntu-20.04
steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
-
name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v3
with:
python-version: 3.9
-
@@ -233,13 +264,13 @@ jobs:
pip3 install -r requirements.txt
-
name: Download frontend artifact
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: frontend-compiled
path: src/documents/static/frontend/
-
name: Download documentation artifact
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: documentation
path: docs/_build/html/
@@ -274,19 +305,19 @@ jobs:
tar -cJf paperless-ngx.tar.xz paperless-ngx/
-
name: Upload release artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: release
path: dist/paperless-ngx.tar.xz
publish-release:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
needs: build-release
if: contains(github.ref, 'refs/tags/ngx-') || contains(github.ref, 'refs/tags/beta-')
steps:
-
name: Download release artifact
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: release
path: ./
@@ -297,9 +328,11 @@ jobs:
if [[ $GITHUB_REF == refs/tags/ngx-* ]]; then
echo ::set-output name=version::${GITHUB_REF#refs/tags/ngx-}
echo ::set-output name=prerelease::false
echo ::set-output name=body::"For a complete list of changes, see the changelog at https://paperless-ngx.readthedocs.io/en/latest/changelog.html"
elif [[ $GITHUB_REF == refs/tags/beta-* ]]; then
echo ::set-output name=version::${GITHUB_REF#refs/tags/beta-}
echo ::set-output name=prerelease::true
echo ::set-output name=body::"For a complete list of changes, see the changelog at https://github.com/paperless-ngx/paperless-ngx/blob/beta/docs/changelog.rst"
fi
-
name: Create release
@@ -312,8 +345,7 @@ jobs:
release_name: Paperless-ngx ${{ steps.get_version.outputs.version }}
draft: false
prerelease: ${{ steps.get_version.outputs.prerelease }}
body: |
For a complete list of changes, see the changelog at https://paperless-ngx.readthedocs.io/en/latest/changelog.html.
body: ${{ steps.get_version.outputs.body }}
-
name: Upload release archive
id: upload-release-asset
@@ -324,4 +356,4 @@ jobs:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./paperless-ngx.tar.xz
asset_name: paperless-ngx-${{ steps.get_version.outputs.version }}.tar.xz
asset_content_type: application/x-xz
asset_content_type: application/x-xz

47
.github/workflows/project-actions.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: Project Automations
on:
issues:
types:
- opened
- reopened
pull_request_target: #_target allows access to secrets
types:
- opened
- reopened
branches:
- main
- dev
env:
todo: Todo
done: Done
in_progress: In Progress
jobs:
issue_opened_or_reopened:
name: issue_opened_or_reopened
runs-on: ubuntu-latest
if: github.event_name == 'issues' && (github.event.action == 'opened' || github.event.action == 'reopened')
steps:
- name: Set issue status to ${{ env.todo }}
uses: leonsteinhaeuser/project-beta-automations@v1.2.1
with:
gh_token: ${{ secrets.GH_TOKEN }}
organization: paperless-ngx
project_id: 2
resource_node_id: ${{ github.event.issue.node_id }}
status_value: ${{ env.todo }} # Target status
pr_opened_or_reopened:
name: pr_opened_or_reopened
runs-on: ubuntu-latest
if: github.event_name == 'pull_request_target' && (github.event.action == 'opened' || github.event.action == 'reopened')
steps:
- name: Set PR status to ${{ env.in_progress }}
uses: leonsteinhaeuser/project-beta-automations@v1.2.1
with:
gh_token: ${{ secrets.GH_TOKEN }}
organization: paperless-ngx
project_id: 2
resource_node_id: ${{ github.event.pull_request.node_id }}
status_value: ${{ env.in_progress }} # Target status

3
.gitignore vendored
View File

@@ -61,6 +61,9 @@ target/
# PyCharm
.idea
# VS Code
.vscode
# Other stuff that doesn't belong
.virtualenv
virtualenv

80
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,80 @@
# This file configures pre-commit hooks.
# See https://pre-commit.com/ for general information
# See https://pre-commit.com/hooks.html for a listing of possible hooks
repos:
# General hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
hooks:
- id: check-docstring-first
- id: check-json
exclude: "tsconfig.*json"
- id: check-yaml
- id: check-toml
- id: check-executables-have-shebangs
- id: end-of-file-fixer
exclude_types:
- svg
- pofile
exclude: "(^LICENSE$)"
- id: mixed-line-ending
args:
- "--fix=lf"
- id: trailing-whitespace
exclude_types:
- svg
- id: check-case-conflict
- id: detect-private-key
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v2.6.1"
hooks:
- id: prettier
types_or:
- javascript
- ts
- markdown
exclude: "(^Pipfile\\.lock$)"
# Python hooks
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.0.1
hooks:
- id: reorder-python-imports
exclude: "(migrations)"
- repo: https://github.com/asottile/yesqa
rev: "v1.3.0"
hooks:
- id: yesqa
exclude: "(migrations)"
- repo: https://github.com/asottile/add-trailing-comma
rev: "v2.2.1"
hooks:
- id: add-trailing-comma
exclude: "(migrations)"
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
files: ^src/
args:
- "--config=./src/setup.cfg"
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
# Dockerfile hooks
- repo: https://github.com/pryorda/dockerfilelint-precommit-hooks
rev: "v0.1.0"
hooks:
- id: dockerfilelint
# Shell script hooks
- repo: https://github.com/lovesegfault/beautysh
rev: v6.2.1
hooks:
- id: beautysh
args:
- "--tab"
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: "v0.8.0.4"
hooks:
- id: shellcheck

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
# https://prettier.io/docs/en/options.html#semicolons
semi: false
# https://prettier.io/docs/en/options.html#quotes
singleQuote: true

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hello@paperless-ngx.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -4,10 +4,10 @@ If you feel like contributing to the project, please do! Bug fixes and improveme
If you want to implement something big:
* Please start a discussion about that in the issues! Maybe something similar is already in development and we can make it happen together.
* When making additions to the project, consider if the majority of users will benefit from your change. If not, you're probably better of forking the project.
* Also consider if your change will get in the way of other users. A good change is a change that enhances the experience of some users who want that change and does not affect users who do not care about the change.
* Please see the [paperless-ngx merge process](#merging-prs) below.
- Please start a discussion about that in the issues! Maybe something similar is already in development and we can make it happen together.
- When making additions to the project, consider if the majority of users will benefit from your change. If not, you're probably better of forking the project.
- Also consider if your change will get in the way of other users. A good change is a change that enhances the experience of some users who want that change and does not affect users who do not care about the change.
- Please see the [paperless-ngx merge process](#merging-prs) below.
## Python
@@ -15,7 +15,7 @@ Paperless supports python 3.8 and 3.9. We format Python code with [Black](https:
## Branches
`master` always reflects the latest release. Apart from changes to the documentation or readme, absolutely no functional changes on this branch in between releases.
`main` always reflects the latest release. Apart from changes to the documentation or readme, absolutely no functional changes on this branch in between releases.
`dev` contains all changes that will be part of the next release. Use this branch to start making your changes.
@@ -27,6 +27,8 @@ Please format and test your code! I know it's a hassle, but it makes sure that y
To test your code, execute `pytest` in the src/ directory. This also generates a html coverage report, which you can use to see if you missed anything important during testing.
Before you can run `pytest`, ensure to [properly set up your local environment](https://paperless-ngx.readthedocs.io/en/latest/extending.html#initial-setup-and-first-start).
## More info:
... is available in the documentation. https://paperless-ngx.readthedocs.io/en/latest/extending.html
@@ -41,9 +43,9 @@ PRs deemed `non-trivial` will go through a stricter review process before being
Examples of `non-trivial` PRs might include:
* Additional features
* Large changes to many distinct files
* Breaking or depreciation of existing features
- Additional features
- Large changes to many distinct files
- Breaking or depreciation of existing features
Our community review process for `non-trivial` PRs is the following:
@@ -75,21 +77,56 @@ If a language has already been added, and you would like to contribute new trans
If you would like the project to be translated to another language, first head over to https://crwd.in/paperless-ngx to check if that language has already been enabled for translation.
If not, please request the language to be added by creating an issue on GitHub. The issue should contain:
* English name of the language (the localized name can be added on Crowdin).
* ISO language code. A list of those can be found here: https://support.crowdin.com/enterprise/language-codes/
* Date format commonly used for the language, e.g. dd/mm/yyyy, mm/dd/yyyy, etc.
- English name of the language (the localized name can be added on Crowdin).
- ISO language code. A list of those can be found here: https://support.crowdin.com/enterprise/language-codes/
- Date format commonly used for the language, e.g. dd/mm/yyyy, mm/dd/yyyy, etc.
After the language has been added and some translations have been made on Crowdin, the language needs to be enabled in the code.
Note that there is no need to manually add a .po of .xlf file as those will be automatically generated and imported from Crowdin.
The following files need to be changed:
* src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key)
* src/paperless/settings.py (in the _LANGUAGES_ array)
* src-ui/src/app/services/settings.service.ts (inside the _getLanguageOptions_ method)
* src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_)
- src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key)
- src/paperless/settings.py (in the _LANGUAGES_ array)
- src-ui/src/app/services/settings.service.ts (inside the _getLanguageOptions_ method)
- src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_)
Please add the language in the correct order, alphabetically by locale.
Note that _en-us_ needs to stay on top of the list, as it is the default project language
If you are familiar with Git, feel free to send a Pull Request with those changes.
If not, let us know in the issue you created for the language, so that another developer can make these changes.
# Organization Structure & Membership
Paperless-ngx is a community project. We do our best to delegate permission and responsibility among a team of people to ensure the longevity of the project.
## Structure
As of writing, there are 21 members in paperless-ngx. 4 of these people have complete administrative privileges to the repo:
- [@shamoon](https://github.com/shamoon)
- [@bauerj](https://github.com/bauerj)
- [@qcasey](https://github.com/qcasey)
- [@FrankStrieter](https://github.com/FrankStrieter)
There are 5 teams collaborating on specific tasks within paperless-ngx:
- @paperless-ngx/backend (Python / django)
- @paperless-ngx/frontend (JavaScript / Typescript)
- @paperless-ngx/ci-cd (GitHub Actions / Deployment)
- @paperless-ngx/issues (Issue triage)
- @paperless-ngx/test (General testing for larger PRs)
## Permissions
All team members are notified when mentioned or assigned to a relevant issue or pull request. Additionally, each team has slightly different access to paperless-ngx:
- The **test** team has no special permissions.
- The **issues** team has `triage` access. This means they can organize issues and pull requests.
- The **backend**, **frontend**, and **ci-cd** teams have `write` access. This means they can approve PRs and push code, containers, releases, and more.
## Joining
We are not overly strict with inviting people to the organization. If you have read the [team permissions](#permissions) and think having additional access would enhance your contributions, please reach out to an [admin](#structure) of the team.
The admins occasionally invite contributors directly if we believe having them on a team will accelerate their work.

View File

@@ -3,64 +3,16 @@ FROM node:16 AS compile-frontend
COPY . /src
WORKDIR /src/src-ui
RUN npm update npm -g && npm install
RUN npm update npm -g && npm ci --no-optional
RUN ./node_modules/.bin/ng build --configuration production
FROM ghcr.io/paperless-ngx/builder/ngx-base:1.0 as main-app
FROM ubuntu:20.04 AS jbig2enc
WORKDIR /usr/src/jbig2enc
RUN apt-get update && apt-get install -y --no-install-recommends build-essential automake libtool libleptonica-dev zlib1g-dev git ca-certificates
RUN git clone https://github.com/agl/jbig2enc .
RUN ./autogen.sh
RUN ./configure && make
FROM python:3.9-slim-bullseye
# Binary dependencies
RUN apt-get update \
&& apt-get -y --no-install-recommends install \
# Basic dependencies
curl \
gnupg \
imagemagick \
gettext \
tzdata \
gosu \
# fonts for text file thumbnail generation
fonts-liberation \
# for Numpy
libatlas-base-dev \
libxslt1-dev \
# thumbnail size reduction
optipng \
libxml2 \
pngquant \
unpaper \
zlib1g \
ghostscript \
icc-profiles-free \
# Mime type detection
file \
libmagic-dev \
media-types \
# OCRmyPDF dependencies
liblept5 \
tesseract-ocr \
tesseract-ocr-eng \
tesseract-ocr-deu \
tesseract-ocr-fra \
tesseract-ocr-ita \
tesseract-ocr-spa \
&& rm -rf /var/lib/apt/lists/*
# copy jbig2enc
COPY --from=jbig2enc /usr/src/jbig2enc/src/.libs/libjbig2enc* /usr/local/lib/
COPY --from=jbig2enc /usr/src/jbig2enc/src/jbig2 /usr/local/bin/
COPY --from=jbig2enc /usr/src/jbig2enc/src/*.h /usr/local/include/
LABEL org.opencontainers.image.authors="paperless-ngx team <hello@paperless-ngx.com>"
LABEL org.opencontainers.image.documentation="https://paperless-ngx.readthedocs.io/en/latest/"
LABEL org.opencontainers.image.source="https://github.com/paperless-ngx/paperless-ngx"
LABEL org.opencontainers.image.url="https://github.com/paperless-ngx/paperless-ngx"
LABEL org.opencontainers.image.licenses="GPL-3.0-only"
WORKDIR /usr/src/paperless/src/
@@ -68,47 +20,31 @@ COPY requirements.txt ../
# Python dependencies
RUN apt-get update \
# python-Levenshtein still needs to be compiled here
&& apt-get -y --no-install-recommends install \
build-essential \
libpq-dev \
git \
zlib1g-dev \
libjpeg62-turbo-dev \
&& if [ "$(uname -m)" = "armv7l" ] || [ "$(uname -m)" = "aarch64" ]; \
then echo "Building qpdf" \
&& mkdir -p /usr/src/qpdf \
&& cd /usr/src/qpdf \
&& git clone https://github.com/qpdf/qpdf.git . \
&& git checkout --quiet release-qpdf-10.6.2 \
&& ./configure \
&& make \
&& make install \
&& cd /usr/src/paperless/src/ \
&& rm -rf /usr/src/qpdf; \
else \
echo "Skipping qpdf build because pikepdf binary wheels are available."; \
fi \
&& python3 -m pip install --upgrade pip wheel \
&& python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor \
&& python3 -m pip install --default-timeout=1000 --no-cache-dir -r ../requirements.txt \
&& apt-get -y purge build-essential git zlib1g-dev libjpeg62-turbo-dev \
&& apt-get -y autoremove --purge \
&& rm -rf /var/lib/apt/lists/*
build-essential \
&& python3 -m pip install --upgrade --no-cache-dir pip wheel \
&& python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor \
&& python3 -m pip install --default-timeout=1000 --no-cache-dir -r ../requirements.txt \
&& apt-get -y purge build-essential \
&& apt-get -y autoremove --purge \
&& rm -rf /var/lib/apt/lists/*
# setup docker-specific things
COPY docker/ ./docker/
RUN cd docker \
&& cp imagemagick-policy.xml /etc/ImageMagick-6/policy.xml \
&& mkdir /var/log/supervisord /var/run/supervisord \
&& cp supervisord.conf /etc/supervisord.conf \
&& cp docker-entrypoint.sh /sbin/docker-entrypoint.sh \
&& cp docker-prepare.sh /sbin/docker-prepare.sh \
&& chmod 755 /sbin/docker-entrypoint.sh \
&& chmod +x install_management_commands.sh \
&& ./install_management_commands.sh \
&& cd .. \
&& rm docker -rf
&& cp imagemagick-policy.xml /etc/ImageMagick-6/policy.xml \
&& mkdir /var/log/supervisord /var/run/supervisord \
&& cp supervisord.conf /etc/supervisord.conf \
&& cp docker-entrypoint.sh /sbin/docker-entrypoint.sh \
&& chmod 755 /sbin/docker-entrypoint.sh \
&& cp docker-prepare.sh /sbin/docker-prepare.sh \
&& chmod 755 /sbin/docker-prepare.sh \
&& chmod +x install_management_commands.sh \
&& ./install_management_commands.sh \
&& cd .. \
&& rm -rf docker/
COPY gunicorn.conf.py ../
@@ -117,18 +53,18 @@ COPY --from=compile-frontend /src/src/ ./
# add users, setup scripts
RUN addgroup --gid 1000 paperless \
&& useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \
&& chown -R paperless:paperless ../ \
&& gosu paperless python3 manage.py collectstatic --clear --no-input \
&& gosu paperless python3 manage.py compilemessages
&& useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \
&& chown -R paperless:paperless ../ \
&& gosu paperless python3 manage.py collectstatic --clear --no-input \
&& gosu paperless python3 manage.py compilemessages
VOLUME ["/usr/src/paperless/data", \
"/usr/src/paperless/media", \
"/usr/src/paperless/consume", \
"/usr/src/paperless/export"]
VOLUME ["/usr/src/paperless/data", "/usr/src/paperless/media", "/usr/src/paperless/consume", "/usr/src/paperless/export"]
ENTRYPOINT ["/sbin/docker-entrypoint.sh"]
EXPOSE 8000
CMD ["/usr/local/bin/supervisord", "-c", "/etc/supervisord.conf"]
LABEL org.opencontainers.image.authors="paperless-ngx team <hello@paperless-ngx.com>"
LABEL org.opencontainers.image.documentation="https://paperless-ngx.readthedocs.io/en/latest/"
LABEL org.opencontainers.image.source="https://github.com/paperless-ngx/paperless-ngx"
LABEL org.opencontainers.image.url="https://github.com/paperless-ngx/paperless-ngx"
LABEL org.opencontainers.image.licenses="GPL-3.0-only"
EXPOSE 8000
CMD ["/usr/local/bin/supervisord", "-c", "/etc/supervisord.conf"]

31
Pipfile
View File

@@ -9,35 +9,36 @@ verify_ssl = true
name = "piwheels"
[packages]
dateparser = "~=1.1.0"
django = "~=3.2"
dateparser = "~=1.1"
django = "~=4.0"
django-cors-headers = "*"
django-extensions = "*"
django-filter = "~=21.1"
django-q = "~=1.3.4"
djangorestframework = "~=3.13.1"
django-q = "~=1.3"
djangorestframework = "~=3.13"
filelock = "*"
fuzzywuzzy = {extras = ["speedup"], version = "*"}
gunicorn = "*"
imap-tools = "*"
langdetect = "*"
numpy = "~=1.22.0"
pathvalidate = "*"
pillow = "~=9.0"
pikepdf = "~=5.0"
# Any version update to pikepdf requires a base image update
pikepdf = "~=5.1"
python-gnupg = "*"
python-dotenv = "*"
python-dateutil = "*"
python-magic = "*"
psycopg2-binary = "*"
# Any version update to psycopg2 requires a base image update
psycopg2 = "*"
redis = "*"
# Pinned because aarch64 wheels and updates cause warnings when loading the classifier model.
scikit-learn="==0.24.0"
scikit-learn="==1.0.2"
whitenoise = "~=6.0.0"
watchdog = "~=2.1.0"
whoosh="~=2.7.4"
inotifyrecursive = "~=0.3.4"
ocrmypdf = "~=13.4.0"
inotifyrecursive = "~=0.3"
ocrmypdf = "~=13.4"
tqdm = "*"
tika = "*"
# TODO: This will sadly also install daphne+dependencies,
@@ -46,11 +47,10 @@ channels = "~=3.0"
channels-redis = "*"
uvicorn = {extras = ["standard"], version = "*"}
concurrent-log-handler = "*"
# uvloop 0.15+ incompatible with python 3.6
uvloop = "~=0.16"
cryptography = "~=36.0.1"
"pdfminer.six" = "*"
"backports.zoneinfo" = "*"
"backports.zoneinfo" = {version = "*", markers = "python_version < '3.9'"}
"importlib-resources" = {version = "*", markers = "python_version < '3.9'"}
zipp = {version = "*", markers = "python_version < '3.9'"}
[dev-packages]
coveralls = "*"
@@ -62,7 +62,8 @@ pytest-django = "*"
pytest-env = "*"
pytest-sugar = "*"
pytest-xdist = "*"
sphinx = "~=3.4.2"
sphinx = "~=4.4.0"
sphinx_rtd_theme = "*"
tox = "*"
black = "*"
pre-commit = "*"

1035
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,23 +10,23 @@
</p>
<!-- omit in toc -->
# Paperless-ngx
Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, *less paper*.
Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, _less paper_.
Paperless-ngx forked from [paperless-ng](https://github.com/jonaswinkler/paperless-ng) to continue the great work and distribute responsibility of supporting and advancing the project among a team of people. [Consider joining us!](#community-support) Discussion of this transition can be found in issues
[#1599](https://github.com/jonaswinkler/paperless-ng/issues/1599) and [#1632](https://github.com/jonaswinkler/paperless-ng/issues/1632).
A demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) using login `demo` / `demo`. *Note: demo content is reset frequently and confidential information should not be uploaded.*
A demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) using login `demo` / `demo`. _Note: demo content is reset frequently and confidential information should not be uploaded._
- [Features](#features)
- [Getting started](#getting-started)
- [Contributing](#contributing)
- [Community Support](#community-support)
- [Translation](#translation)
- [Feature Requests](#feature-requests)
- [Bugs](#bugs)
- [Community Support](#community-support)
- [Translation](#translation)
- [Feature Requests](#feature-requests)
- [Bugs](#bugs)
- [Affiliated Projects](#affiliated-projects)
- [Important Note](#important-note)
@@ -35,28 +35,28 @@ A demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com)
![Dashboard](https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docs/_static/screenshots/documents-wchrome.png#gh-light-mode-only)
![Dashboard](https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docs/_static/screenshots/documents-wchrome-dark.png#gh-dark-mode-only)
* Organize and index your scanned documents with tags, correspondents, types, and more.
* Performs OCR on your documents, adds selectable text to image only documents and adds tags, correspondents and document types to your documents.
* Supports PDF documents, images, plain text files, and Office documents (Word, Excel, Powerpoint, and LibreOffice equivalents).
* Office document support is optional and provided by Apache Tika (see [configuration](https://paperless-ngx.readthedocs.io/en/latest/configuration.html#tika-settings))
* Paperless stores your documents plain on disk. Filenames and folders are managed by paperless and their format can be configured freely.
* Single page application front end.
* Includes a dashboard that shows basic statistics and has document upload.
* Filtering by tags, correspondents, types, and more.
* Customizable views can be saved and displayed on the dashboard.
* Full text search helps you find what you need.
* Auto completion suggests relevant words from your documents.
* Results are sorted by relevance to your search query.
* Highlighting shows you which parts of the document matched the query.
* Searching for similar documents ("More like this")
* Email processing: Paperless adds documents from your email accounts.
* Configure multiple accounts and filters for each account.
* When adding documents from mail, paperless can move these mail to a new folder, mark them as read, flag them as important or delete them.
* Machine learning powered document matching.
* Paperless-ngx learns from your documents and will be able to automatically assign tags, correspondents and types to documents once you've stored a few documents in paperless.
* Optimized for multi core systems: Paperless-ngx consumes multiple documents in parallel.
* The integrated sanity checker makes sure that your document archive is in good health.
* [More screenshots are available in the documentation](https://paperless-ngx.readthedocs.io/en/latest/screenshots.html).
- Organize and index your scanned documents with tags, correspondents, types, and more.
- Performs OCR on your documents, adds selectable text to image only documents and adds tags, correspondents and document types to your documents.
- Supports PDF documents, images, plain text files, and Office documents (Word, Excel, Powerpoint, and LibreOffice equivalents).
- Office document support is optional and provided by Apache Tika (see [configuration](https://paperless-ngx.readthedocs.io/en/latest/configuration.html#tika-settings))
- Paperless stores your documents plain on disk. Filenames and folders are managed by paperless and their format can be configured freely.
- Single page application front end.
- Includes a dashboard that shows basic statistics and has document upload.
- Filtering by tags, correspondents, types, and more.
- Customizable views can be saved and displayed on the dashboard.
- Full text search helps you find what you need.
- Auto completion suggests relevant words from your documents.
- Results are sorted by relevance to your search query.
- Highlighting shows you which parts of the document matched the query.
- Searching for similar documents ("More like this")
- Email processing: Paperless adds documents from your email accounts.
- Configure multiple accounts and filters for each account.
- When adding documents from mail, paperless can move these mail to a new folder, mark them as read, flag them as important or delete them.
- Machine learning powered document matching.
- Paperless-ngx learns from your documents and will be able to automatically assign tags, correspondents and types to documents once you've stored a few documents in paperless.
- Optimized for multi core systems: Paperless-ngx consumes multiple documents in parallel.
- The integrated sanity checker makes sure that your document archive is in good health.
- [More screenshots are available in the documentation](https://paperless-ngx.readthedocs.io/en/latest/screenshots.html).
# Getting started
@@ -65,7 +65,7 @@ The easiest way to deploy paperless is docker-compose. The files in the [`/docke
If you'd like to jump right in, you can configure a docker-compose environment with our install script:
```bash
bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/install-paperless-ngx.sh)"
bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"
```
Alternatively, you can install the dependencies and setup apache and a database server yourself. The [documentation](https://paperless-ngx.readthedocs.io/en/latest/setup.html#installation) has a step by step guide on how to do it.
@@ -73,6 +73,7 @@ Alternatively, you can install the dependencies and setup apache and a database
Migrating from Paperless-ng is easy, just drop in the new docker image! See the [documentation on migrating](https://paperless-ngx.readthedocs.io/en/latest/setup.html#migrating-from-paperless-ng) for more details.
<!-- omit in toc -->
### Documentation
The documentation for Paperless-ngx is available on [ReadTheDocs](https://paperless-ngx.readthedocs.io/).
@@ -101,18 +102,18 @@ For bugs please [open an issue](https://github.com/paperless-ngx/paperless-ngx/i
Paperless has been around a while now, and people are starting to build stuff on top of it. If you're one of those people, we can add your project to this list:
* [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless-ngx. Also works with the original Paperless and Paperless-ngx.
* [Paperless Share](https://github.com/qcasey/paperless_share). Share any files from your Android application with paperless. Very simple, but works with all of the mobile scanning apps out there that allow you to share scanned documents.
* [Scan to Paperless](https://github.com/sbrunner/scan-to-paperless): Scan and prepare (crop, deskew, OCR, ...) your documents for Paperless.
- [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless-ngx. Also works with the original Paperless and Paperless-ngx.
- [Paperless Share](https://github.com/qcasey/paperless_share). Share any files from your Android application with paperless. Very simple, but works with all of the mobile scanning apps out there that allow you to share scanned documents.
- [Scan to Paperless](https://github.com/sbrunner/scan-to-paperless): Scan and prepare (crop, deskew, OCR, ...) your documents for Paperless.
These projects also exist, but their status and compatibility with paperless-ngx is unknown.
* [paperless-cli](https://github.com/stgarf/paperless-cli): A golang command line binary to interact with a Paperless instance.
- [paperless-cli](https://github.com/stgarf/paperless-cli): A golang command line binary to interact with a Paperless instance.
This project also exists, but needs updates to be compatible with paperless-ngx.
* [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): A desktop UI for your Paperless installation. Runs on Mac, Linux, and Windows.
Known issues on Mac: (Could not load reminders and documents)
- [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): A desktop UI for your Paperless installation. Runs on Mac, Linux, and Windows.
Known issues on Mac: (Could not load reminders and documents)
# Important Note

View File

@@ -1,6 +1,7 @@
# docker-compose file for running paperless from the Docker Hub.
# docker-compose file for running paperless from the docker container registry.
# This file contains everything paperless needs to run.
# Paperless supports amd64, arm and arm64 hardware.
# Paperless supports amd64, arm and arm64 hardware. The apache/tika image
# does not support arm or arm64, however.
#
# All compose files of paperless configure paperless in the following way:
#
@@ -79,8 +80,9 @@ services:
gotenberg:
image: gotenberg/gotenberg:7
restart: unless-stopped
environment:
CHROMIUM_DISABLE_ROUTES: 1
command:
- "gotenberg"
- "--chromium-disable-routes=true"
tika:
image: apache/tika

View File

@@ -0,0 +1,84 @@
# docker-compose file for running paperless from the docker container registry.
# This file contains everything paperless needs to run.
# Paperless supports amd64, arm and arm64 hardware.
#
# All compose files of paperless configure paperless in the following way:
#
# - Paperless is (re)started on system boot, if it was running before shutdown.
# - Docker volumes for storing data are managed by Docker.
# - Folders for importing and exporting files are created in the same directory
# as this file and mounted to the correct folders inside the container.
# - Paperless listens on port 8000.
#
# SQLite is used as the database. The SQLite file is stored in the data volume.
#
# iwishiwasaneagle/apache-tika-arm docker image is used to enable arm64 arch
# which apache/tika does not currently support.
#
# In addition to that, this docker-compose file adds the following optional
# configurations:
#
# - Apache Tika and Gotenberg servers are started with paperless and paperless
# is configured to use these services. These provide support for consuming
# Office documents (Word, Excel, Power Point and their LibreOffice counter-
# parts.
#
# To install and update paperless with this file, do the following:
#
# - Copy this file as 'docker-compose.yml' and the files 'docker-compose.env'
# and '.env' into a folder.
# - Run 'docker-compose pull'.
# - Run 'docker-compose run --rm webserver createsuperuser' to create a user.
# - Run 'docker-compose up -d'.
#
# For more extensive installation and update instructions, refer to the
# documentation.
version: "3.4"
services:
broker:
image: redis:6.0
restart: unless-stopped
volumes:
- redisdata:/data
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
- broker
- gotenberg
- tika
ports:
- 8000:8000
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
volumes:
- data:/usr/src/paperless/data
- media:/usr/src/paperless/media
- ./export:/usr/src/paperless/export
- ./consume:/usr/src/paperless/consume
env_file: docker-compose.env
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
image: thecodingmachine/gotenberg
restart: unless-stopped
environment:
DISABLE_GOOGLE_CHROME: 1
tika:
image: iwishiwasaneagle/apache-tika-arm@sha256:a78c25ffe57ecb1a194b2859d42a61af46e9e845191512b8f1a4bf90578ffdfd
restart: unless-stopped
volumes:
data:
media:
redisdata:

View File

@@ -1,6 +1,7 @@
# docker-compose file for running paperless from the Docker Hub.
# docker-compose file for running paperless from the docker container registry.
# This file contains everything paperless needs to run.
# Paperless supports amd64, arm and arm64 hardware.
# Paperless supports amd64, arm and arm64 hardware. The apache/tika image
# does not support arm or arm64, however.
#
# All compose files of paperless configure paperless in the following way:
#
@@ -68,8 +69,9 @@ services:
gotenberg:
image: gotenberg/gotenberg:7
restart: unless-stopped
environment:
CHROMIUM_DISABLE_ROUTES: 1
command:
- "gotenberg"
- "--chromium-disable-routes=true"
tika:
image: apache/tika

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
@@ -10,7 +10,7 @@ map_uidgid() {
USERMAP_NEW_GID=${USERMAP_GID:-${USERMAP_ORIG_GID:-$USERMAP_NEW_UID}}
if [[ ${USERMAP_NEW_UID} != "${USERMAP_ORIG_UID}" || ${USERMAP_NEW_GID} != "${USERMAP_ORIG_GID}" ]]; then
echo "Mapping UID and GID for paperless:paperless to $USERMAP_NEW_UID:$USERMAP_NEW_GID"
usermod -u "${USERMAP_NEW_UID}" paperless
usermod -o -u "${USERMAP_NEW_UID}" paperless
groupmod -o -g "${USERMAP_NEW_GID}" paperless
fi
}
@@ -56,12 +56,12 @@ install_languages() {
# continue
#fi
if dpkg -s $pkg &>/dev/null; then
if dpkg -s "$pkg" &>/dev/null; then
echo "Package $pkg already installed!"
continue
fi
if ! apt-cache show $pkg &>/dev/null; then
if ! apt-cache show "$pkg" &>/dev/null; then
echo "Package $pkg not found! :("
continue
fi
@@ -77,7 +77,7 @@ install_languages() {
echo "Paperless-ngx docker container starting..."
# Install additional languages if specified
if [[ ! -z "$PAPERLESS_OCR_LANGUAGES" ]]; then
if [[ -n "$PAPERLESS_OCR_LANGUAGES" ]]; then
install_languages "$PAPERLESS_OCR_LANGUAGES"
fi

View File

@@ -6,14 +6,11 @@ wait_for_postgres() {
echo "Waiting for PostgreSQL to start..."
host="${PAPERLESS_DBHOST}"
port="${PAPERLESS_DBPORT}"
host="${PAPERLESS_DBHOST:=localhost}"
port="${PAPERLESS_DBPORT:=5342}"
if [[ -z $port ]]; then
port="5432"
fi
while ! </dev/tcp/$host/$port; do
while [ ! "$(pg_isready -h $host -p $port)" ]; do
if [ $attempt_num -eq $max_attempts ]; then
echo "Unable to connect to database."
@@ -23,7 +20,7 @@ wait_for_postgres() {
fi
attempt_num=$(expr "$attempt_num" + 1)
attempt_num=$(("$attempt_num" + 1))
sleep 5
done
}

View File

@@ -1,3 +1,5 @@
#!/usr/bin/env bash
for command in document_archiver document_exporter document_importer mail_fetcher document_create_classifier document_index document_renamer document_retagger document_thumbnails document_sanity_checker manage_superuser;
do
echo "installing $command..."

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
@@ -6,10 +6,10 @@ cd /usr/src/paperless/src/
if [[ $(id -u) == 0 ]] ;
then
gosu paperless python3 manage.py management_command "$@"
gosu paperless python3 manage.py management_command "$@"
elif [[ $(id -un) == "paperless" ]] ;
then
python3 manage.py management_command "$@"
python3 manage.py management_command "$@"
else
echo "Unknown user."
echo "Unknown user."
fi

View File

@@ -1,5 +1,4 @@
FROM python:3.5.1
MAINTAINER Pit Kleyersburg <pitkley@googlemail.com>
# Install Sphinx and Pygments
RUN pip install Sphinx Pygments

View File

@@ -379,7 +379,7 @@ the naming scheme.
The command takes no arguments and processes all your documents at once.
Learn how to use :ref:`Management Utilities<Management utilities>`.
Learn how to use :ref:`Management Utilities<utilities-management-commands>`.
.. _utilities-sanity-checker:

View File

@@ -179,13 +179,14 @@ Assumed you have ``/home/foo/paperless-ngx/scripts/post-consumption-example.sh``
You can pass that script into the consumer container via a host mount in your ``docker-compose.yml``.
.. code:: bash
...
consumer:
...
volumes:
...
- /home/paperless-ngx/scripts:/path/in/container/scripts/
...
...
consumer:
...
volumes:
...
- /home/paperless-ngx/scripts:/path/in/container/scripts/
...
Example (docker-compose.yml): ``- /home/foo/paperless-ngx/scripts:/usr/src/paperless/scripts``

View File

@@ -60,7 +60,7 @@ The endpoints correctly serve the response header fields ``Content-Disposition``
and ``Content-Type`` to indicate the filename for download and the type of content of
the document.
In order to download or preview the original document when an archied document is available,
In order to download or preview the original document when an archived document is available,
supply the query parameter ``original=true``.
.. hint::

View File

@@ -23,6 +23,7 @@ Version 1.6.0 merges several pending PRs from jonaswinkler's repo and includes n
* `@shamoon`_ added 'any' / 'all' and 'not' filtering with tags (#10).
* `@shamoon`_ added warnings for unsaved changes, with smart edit buttons (#13).
* `@benjaminfrank`_ enabled a non-root access to port 80 via systemd (#18).
* `@tribut`_ added simple "delete to trash" functionality (#24). See ``PAPERLESS_TRASH_DIR``.
* `@amenk`_ fixed the search box overlay menu on mobile (#32).
* `@dblitt`_ updated the login form to not auto-capitalize usernames (#36).
* `@evilsidekick293`_ made the worker timeout configurable (#37). See ``PAPERLESS_WORKER_TIMEOUT``.
@@ -51,8 +52,11 @@ Another big thanks to the people who have contributed translations:
* Lars Sørensen (Lrss) suggested 167 translations into Danish.
* Philmo67 suggested 11 translations into French.
Paperless-ng
############
paperless-ng 1.5.0
##################
==================
Support for Python 3.6 was dropped.
@@ -63,7 +67,7 @@ Support for Python 3.6 was dropped.
* `Daniel Albers`_ added support for making the files and folders ignored by the paperless consume folder scanner configurable. See ``PAPERLESS_CONSUMER_IGNORE_PATTERNS``.
paperless-ng 1.4.5
##################
==================
This is a maintenance release.
@@ -76,7 +80,7 @@ This is a maintenance release.
with PDFminer even from non-PDF files.
paperless-ng 1.4.4
##################
==================
* Drastically decreased the startup time of the docker container. The startup script adjusts file permissions of all data only if changes are required.
* Paperless mail: Added ability to specify the character set for each server.
@@ -85,7 +89,7 @@ paperless-ng 1.4.4
* Updated translations.
paperless-ng 1.4.3
##################
==================
* Additions and changes
@@ -102,12 +106,12 @@ paperless-ng 1.4.3
* Fixed an issue with the document consumer crashing on certain documents due to issues with pdfminer.six. This library is used for PDF text extraction.
paperless-ng 1.4.2
##################
==================
* Fixed an issue with ``sudo`` that caused paperless to not start on many Raspberry Pi devices. Thank you `WhiteHatTux`_!
paperless-ng 1.4.1
##################
==================
* Added Polish locale.
@@ -123,7 +127,7 @@ paperless-ng 1.4.1
``PAPERLESS_ADMIN_PASSWORD`` as environment variables to the docker container.
paperless-ng 1.4.0
##################
==================
* Docker images now use tesseract 4.1.1, which should fix a series of issues with OCR.
@@ -156,7 +160,7 @@ paperless-ng 1.4.0
(see :ref:`administration-index`).
paperless-ng 1.3.2
##################
==================
* Added translation into Portuguese.
@@ -171,7 +175,7 @@ paperless-ng 1.3.2
* Fixed an issue with any/all/exact matching when characters used in regular expressions were used for the match.
paperless-ng 1.3.1
##################
==================
* Added translation into Spanish and Russian.
@@ -196,7 +200,7 @@ paperless-ng 1.3.1
* Fixed ``AUTO_LOGIN_USERNAME``: Unable to perform POST/PUT/DELETE requests and unable to receive WebSocket messages.
paperless-ng 1.3.0
##################
==================
This release contains new database migrations.
@@ -222,7 +226,7 @@ This release contains new database migrations.
paperless-ng 1.2.1
##################
==================
* `Rodrigo Avelino <https://github.com/rodavelino>`_ translated Paperless into Portuguese (Brazil)!
@@ -235,7 +239,7 @@ paperless-ng 1.2.1
* Regression fix: Dates on the front end did not respect date locale settings in some cases.
paperless-ng 1.2.0
##################
==================
* Changes to the OCRmyPDF integration
@@ -259,14 +263,14 @@ paperless-ng 1.2.0
* Paperless no longer depends on ``libpoppler-cpp-dev``.
paperless-ng 1.1.4
##################
==================
* Added English (GB) locale.
* Added ISO-8601 date display option.
paperless-ng 1.1.3
##################
==================
* Added a docker-specific configuration option to adjust the number of
worker processes of the web server. See :ref:`configuration-docker`.
@@ -276,7 +280,7 @@ paperless-ng 1.1.3
* Don't show inbox statistics if no inbox tag is defined.
paperless-ng 1.1.2
##################
==================
* Always show top left corner of thumbnails, even for extra wide documents.
@@ -292,7 +296,7 @@ paperless-ng 1.1.2
* Some memory usage optimizations.
paperless-ng 1.1.1
##################
==================
This release contains new database migrations.
@@ -313,7 +317,7 @@ This release contains new database migrations.
also ensure that they're always executed as the paperless user and you're less likely to run into permission issues. See :ref:`utilities-management-commands`.
paperless-ng 1.1.0
##################
==================
* Document processing status
@@ -373,7 +377,7 @@ paperless-ng 1.1.0
``PAPERLESS_LOGROTATE_MAX_BACKUPS``.
paperless-ng 1.0.0
##################
==================
Nothing special about this release, but since there are relatively few bug reports coming in, I think that this is reasonably stable.
@@ -396,7 +400,7 @@ Nothing special about this release, but since there are relatively few bug repor
paperless-ng 0.9.14
###################
===================
Starting with this version, releases are getting built automatically. This release also comes with changes on how to install and
update paperless.
@@ -444,13 +448,13 @@ update paperless.
* An issue with the consumer crashing when invalid regular expression were used was fixed.
paperless-ng 0.9.13
###################
===================
* Fixed an issue with Paperless not starting due to the new Tika integration when ``USERMAP_UID`` and ``USERMAP_GID`` was used
in the ``docker-compose.env`` file.
paperless-ng 0.9.12
###################
===================
* Paperless localization
@@ -492,13 +496,13 @@ paperless-ng 0.9.12
a document that did not yet exist in the database.
paperless-ng 0.9.11
###################
===================
* Fixed an issue with the docker image not starting at all due to a configuration change of the web server.
paperless-ng 0.9.10
###################
===================
* Bulk editing
@@ -531,7 +535,7 @@ paperless-ng 0.9.10
by :ref:`running the management command document_index with the argument reindex <administration-index>`.
paperless-ng 0.9.9
##################
==================
Christmas release!
@@ -565,7 +569,7 @@ Christmas release!
* Most of the guesswork features have been removed. Paperless no longer tries to extract correspondents and tags from file names.
paperless-ng 0.9.8
##################
==================
This release addresses two severe issues with the previous release.
@@ -574,7 +578,7 @@ This release addresses two severe issues with the previous release.
paperless-ng 0.9.7
##################
==================
* Front end
@@ -616,7 +620,7 @@ paperless-ng 0.9.7
paperless-ng 0.9.6
##################
==================
This release focusses primarily on many small issues with the UI.
@@ -657,7 +661,7 @@ This release focusses primarily on many small issues with the UI.
paperless-ng 0.9.5
##################
==================
This release concludes the big changes I wanted to get rolled into paperless. The next releases before 1.0 will
focus on fixing issues, primarily.
@@ -707,7 +711,7 @@ focus on fixing issues, primarily.
* Assigning correspondents from mail sender names failed for very long names. Paperless no longer assigns correspondents in these cases.
paperless-ng 0.9.4
##################
==================
* Searching:
@@ -735,7 +739,7 @@ paperless-ng 0.9.4
how to setup the development environment.
paperless-ng 0.9.3
##################
==================
* Setting ``PAPERLESS_AUTO_LOGIN_USERNAME`` replaces ``PAPERLESS_DISABLE_LOGIN``.
You have to specify your username.
@@ -753,7 +757,7 @@ paperless-ng 0.9.3
* Added lots of tests for various parts of the application.
paperless-ng 0.9.2
##################
==================
* Major changes to the front end (colors, logo, shadows, layout of the cards,
better mobile support)
@@ -783,7 +787,7 @@ paperless-ng 0.9.2
up in the admin.
paperless-ng 0.9.1
##################
==================
* Moved documentation of the settings to the actual documentation.
* Updated release script to force the user to choose between SQLite
@@ -791,7 +795,7 @@ paperless-ng 0.9.1
paperless-ng 0.9.0
##################
==================
* **Deprecated:** GnuPG. :ref:`See this note on the state of GnuPG in paperless-ng. <utilities-encyption>`
This features will most likely be removed in future versions.
@@ -1684,4 +1688,4 @@ bulk of the work on this big change.
.. _a new home on Docker Hub: https://hub.docker.com/r/danielquinn/paperless/
.. _optipng: http://optipng.sourceforge.net/
.. _DjangoQL: https://github.com/ivelum/djangoql
.. _ansible repo: https://github.com/paperless-ngx/paperless-ngx-ansible
.. _ansible repo: https://github.com/paperless-ngx/paperless-ngx-ansible

View File

@@ -389,6 +389,15 @@ PAPERLESS_OCR_IMAGE_DPI=<num>
Default is none, which will automatically calculate image DPI so that
the produced PDF documents are A4 sized.
PAPERLESS_OCR_MAX_IMAGE_PIXELS=<num>
Paperless will not OCR images that have more pixels than this limit.
This is intended to prevent decompression bombs from overloading paperless.
Increasing this limit is desired if you face a DecompressionBombError despite
the concerning file not being malicious; this could e.g. be caused by invalidly
recognized metadata.
If you have enough resources or if you are certain that your uploaded files
are not malicious you can increase this value to your needs.
The default value is 256000000, an image with more pixels than that would not be parsed.
PAPERLESS_OCR_USER_ARGS=<json>
OCRmyPDF offers many more options. Use this parameter to specify any
@@ -462,8 +471,9 @@ requires are as follows:
gotenberg:
image: gotenberg/gotenberg:7
restart: unless-stopped
environment:
CHROMIUM_DISABLE_ROUTES: 1
command:
- "gotenberg"
- "--chromium-disable-routes=true"
tika:
image: apache/tika
@@ -473,6 +483,8 @@ Add the configuration variables to the environment of the webserver (alternative
put the configuration in the ``docker-compose.env`` file) and add the additional
services below the webserver service. Watch out for indentation.
Make sure to use the correct format `PAPERLESS_TIKA_ENABLED = 1` so python_dotenv can parse the statement correctly.
Software tweaks
###############

View File

@@ -1,145 +0,0 @@
.. _contributing:
Contributing to Paperless
#########################
.. warning::
This section is not updated to paperless-ngx yet.
Maybe you've been using Paperless for a while and want to add a feature or two,
or maybe you've come across a bug that you have some ideas how to solve. The
beauty of Free software is that you can see what's wrong and help to get it
fixed for everyone!
How to Get Your Changes Rolled Into Paperless
=============================================
If you've found a bug, but don't know how to fix it, you can always post an
issue on `GitHub`_ in the hopes that someone will have the time to fix it for
you. If however you're the one with the time, pull requests are always
welcome, you just have to make sure that your code conforms to a few standards:
Pep8
----
It's the standard for all Python development, so it's `very well documented`_.
The short version is:
* Lines should wrap at 79 characters
* Use ``snake_case`` for variables, ``CamelCase`` for classes, and ``ALL_CAPS``
for constants.
* Space out your operators: ``stuff + 7`` instead of ``stuff+7``
* Two empty lines between classes, and functions, but 1 empty line between
class methods.
There's more to it than that, but if you follow those, you'll probably be
alright. When you submit your pull request, there's a pep8 checker that'll
look at your code to see if anything is off. If it finds anything, it'll
complain at you until you fix it.
Additional Style Guides
-----------------------
Where pep8 is ambiguous, I've tried to be a little more specific. These rules
aren't hard-and-fast, but if you can conform to them, I'll appreciate it and
spend less time trying to conform your PR before merging:
Function calls
..............
If you're calling a function and that necessitates more than one line of code,
please format it like this:
.. code:: python
my_function(
argument1,
kwarg1="x",
kwarg2="y"
another_really_long_kwarg="some big value"
a_kwarg_calling_another_long_function=another_function(
another_arg,
another_kwarg="kwarg!"
)
)
This is all in the interest of code uniformity rather than anything else. If
we stick to a style, everything is understandable in the same way.
Quoting Strings
...............
pep8 is a little too open-minded on this for my liking. Python strings should
be quoted with double quotes (``"``) except in cases where the resulting string
would require too much escaping of a double quote, in which case, a single
quoted, or triple-quoted string will do:
.. code:: python
my_string = "This is my string"
problematic_string = 'This is a "string" with "quotes" in it'
In HTML templates, please use double-quotes for tag attributes, and single
quotes for arguments passed to Django template tags:
.. code:: html
<div class="stuff">
<a href="{% url 'some-url-name' pk='w00t' %}">link this</a>
</div>
This is to keep linters happy they look at an HTML file and see an attribute
closing the ``"`` before it should have been.
--
That's all there is in terms of guidelines, so I hope it's not too daunting.
Indentation & Spacing
.....................
When it comes to indentation:
* For Python, the rule is: follow pep8 and use 4 spaces.
* For Javascript, CSS, and HTML, please use 1 tab.
Additionally, Django templates making use of block elements like ``{% if %}``,
``{% for %}``, and ``{% block %}`` etc. should be indented:
Good:
.. code:: html
{% block stuff %}
<h1>This is the stuff</h1>
{% endblock %}
Bad:
.. code:: html
{% block stuff %}
<h1>This is the stuff</h1>
{% endblock %}
The Code of Conduct
===================
Paperless has a `code of conduct`_. It's a lot like the other ones you see out
there, with a few small changes, but basically it boils down to:
> Don't be an ass, or you might get banned.
I'm proud to say that the CoC has never had to be enforced because everyone has
been awesome, friendly, and professional.
.. _GitHub: https://github.com/the-paperless-project/paperless/issues
.. _very well documented: https://www.python.org/dev/peps/pep-0008/
.. _code of conduct: https://github.com/the-paperless-project/paperless/blob/master/CODE_OF_CONDUCT.md

View File

@@ -1,13 +1,13 @@
.. _extending:
Paperless development
#####################
Paperless-ngx Development
#########################
This section describes the steps you need to take to start development on paperless-ngx.
Check out the source from github. The repository is organized in the following way:
* ``master`` always represents the latest release and will only see changes
* ``main`` always represents the latest release and will only see changes
when a new release is made.
* ``dev`` contains the code that will be in the next release.
* ``feature-X`` contain bigger changes that will be in some release, but not
@@ -23,6 +23,33 @@ Apart from that, the folder structure is as follows:
* ``scripts/`` - Various scripts that help with different parts of development.
* ``docker/`` - Files required to build the docker image.
Contributing to Paperless
=========================
Maybe you've been using Paperless for a while and want to add a feature or two,
or maybe you've come across a bug that you have some ideas how to solve. The
beauty of open source software is that you can see what's wrong and help to get
it fixed for everyone!
Before contributing please review our `code of conduct`_ and other important
information in the `contributing guidelines`_.
.. _code-formatting-with-pre-commit-hooks:
Code formatting with pre-commit Hooks
=====================================
To ensure a consistent style and formatting across the project source, the project
utilizes a Git `pre-commit` hook to perform some formatting and linting before a
commit is allowed. That way, everyone uses the same style and some common issues
can be caught early on. See below for installation instructions.
Once installed, hooks will run when you commit. If the formatting isn't quite right
or a linter catches something, the commit will be rejected. You'll need to look at the
output and fix the issue. Some hooks, such as the Python formatting tool `black`,
will format failing files, so all you need to do is `git add` those files again and
retry your commit.
Initial setup and first start
=============================
@@ -37,13 +64,19 @@ To do the setup you need to perform the steps from the following chapters in a c
$ npm install -g @angular/cli
4. Create ``consume`` and ``media`` folders in the cloned root folder.
4. Install pre-commit
.. code:: shell-session
pre-commit install
5. Create ``consume`` and ``media`` folders in the cloned root folder.
.. code:: shell-session
mkdir -p consume media
5. You can now either ...
6. You can now either ...
* install redis or
* use the included scripts/start-services.sh to use docker to fire up a redis instance (and some other services such as tika, gotenberg and a postgresql server) or
@@ -53,41 +86,42 @@ To do the setup you need to perform the steps from the following chapters in a c
docker run -d -p 6379:6379 --restart unless-stopped redis:latest
6. Install the python dependencies by performing in the src/ directory.
7. Install the python dependencies by performing in the src/ directory.
.. code:: shell-session
pipenv install --dev
* Make sure you're using python 3.9.x or lower. Otherwise you might get issues with building dependencies. You can use `pyenv <https://github.com/pyenv/pyenv>`_ to install a specific python version.
7. Generate the static UI so you can perform a login to get session that is required for frontend development (this needs to be done one time only). From src-ui directory:
8. Generate the static UI so you can perform a login to get session that is required for frontend development (this needs to be done one time only). From src-ui directory:
.. code:: shell-session
npm install .
./node_modules/.bin/ng build --configuration production
8. Apply migrations and create a superuser for your dev instance:
9. Apply migrations and create a superuser for your dev instance:
.. code:: shell-session
python3 manage.py migrate
python3 manage.py createsuperuser
9. Now spin up the dev backend. Depending on which part of paperless you're developing for, you need to have some or all of them running.
10. Now spin up the dev backend. Depending on which part of paperless you're developing for, you need to have some or all of them running.
.. code:: shell-session
python3 manage.py runserver & python3 manage.py document_consumer & python3 manage.py qcluster
10. Login with the superuser credentials provided in step 8 at ``http://localhost:8000`` to create a session that enables you to use the backend.
11. Login with the superuser credentials provided in step 8 at ``http://localhost:8000`` to create a session that enables you to use the backend.
Backend development environment is now ready, to start Frontend development go to ``/src-ui`` and run ``ng serve``. From there you can use ``http://localhost:4200`` for a preview.
Back end development
====================
The backend is a django application. I use PyCharm for development, but you can use whatever
The backend is a django application. PyCharm works well for development, but you can use whatever
you want.
Configure the IDE to use the src/ folder as the base source folder. Configure the following
@@ -108,8 +142,9 @@ Testing and code style:
* Run ``pytest`` in the src/ directory to execute all tests. This also generates a HTML coverage
report. When runnings test, paperless.conf is loaded as well. However: the tests rely on the default
configuration. This is not ideal. But for now, make sure no settings except for DEBUG are overridden when testing.
* Run ``black`` to format your code.
* Run ``pycodestyle`` to test your code for issues with the configured code style settings.
* Coding style is enforced by the Git pre-commit hooks. These will ensure your code is formatted and do some
linting when you do a `git commit`.
* You can also run ``black`` manually to format your code
.. note::
@@ -121,9 +156,8 @@ Testing and code style:
Front end development
=====================
The front end is build using angular. I use the ``Code - OSS`` IDE for development.
In order to get started, you need ``npm``. Install the Angular CLI interface with
The front end is built using Angular. In order to get started, you need ``npm``.
Install the Angular CLI interface with
.. code:: shell-session
@@ -152,6 +186,31 @@ X-Frame-Options are in place so that the front end behaves exactly as in product
relies on you being logged into the back end. Without a valid session, The front end will simply
not work.
Testing and code style:
* The frontend code (.ts, .html, .scss) use ``prettier`` for code formatting via the Git
``pre-commit`` hooks which run automatically on commit. See
:ref:`above <code-formatting-with-pre-commit-hooks>` for installation. You can also run this
via cli with a command such as
.. code:: shell-session
$ git ls-files -- '*.ts' | xargs pre-commit run prettier --files
* Frontend testing uses jest and cypress. There is currently a need for significantly more
frontend tests. Unit tests and e2e tests, respectively, can be run non-interactively with:
.. code:: shell-session
$ ng test
$ npm run e2e:ci
Cypress also includes a UI which can be run from within the ``src-ui`` directory with
.. code:: shell-session
$ ./node_modules/.bin/cypress open
In order to build the front end and serve it as part of django, execute
.. code:: shell-session
@@ -361,3 +420,6 @@ that returns information about your parser:
download. We could guess that from the file extensions, but some mime types have many extensions
associated with them and the python methods responsible for guessing the extension do not always
return the same value.
.. _code of conduct: https://github.com/paperless-ngx/paperless-ngx/blob/main/CODE_OF_CONDUCT.md
.. _contributing guidelines: https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md

View File

@@ -5,11 +5,11 @@ Frequently asked questions
**Q:** *What's the general plan for Paperless-ngx?*
**A:** While Paperless-ngx is already considered largely "feature-complete" it is a community-driven
**A:** While Paperless-ngx is already considered largely "feature-complete" it is a community-driven
project and development will be guided in this way. New features can be submitted via
GitHub discussions and "up-voted" by the community but this is not a garauntee the feature
will be implemented. This project will always be open to collaboration in the form of PRs,
ideas etc.
ideas etc.
**Q:** *I'm using docker. Where are my documents?*
@@ -81,11 +81,10 @@ python requirements do not have precompiled packages for ARM / ARM64. Installati
of these will require additional development libraries and compilation will take
a long time.
**Q:** *How do I run this on unRaid?*
**Q:** *How do I run this on Unraid?*
**A:** Head over to `<https://github.com/selfhosters/unRAID-CA-templates>`_,
`Uli Fahrer <https://github.com/Tooa>`_ created a container template for that.
I don't exactly know how to use that though, since I don't use unRaid.
**A:** Paperless-ngx is available as `community app <https://unraid.net/community/apps?q=paperless-ngx>`_
in Unraid. `Uli Fahrer <https://github.com/Tooa>`_ created a container template for that.
**Q:** *How do I run this on my toaster?*

View File

@@ -70,7 +70,6 @@ Contents
faq
troubleshooting
extending
contributing
scanners
screenshots
changelog

View File

@@ -112,3 +112,23 @@ On Android, you can use these applications in combination with one of the :ref:`
.. _hannahswain: https://github.com/hannahswain
.. _benjaminfrank: https://github.com/benjaminfrank
API Scanning Setup
==================
This sections contains information on how to set up scanners to post directly to :ref:`Paperless API <api-file_uploads>`.
Doxie Q2
--------
This part assumes your Doxie is connected to WiFi and you know its IP.
1. Open your Doxie web UI by navigating to its IP address
2. Navigate to Options -> Webhook
3. Set the *URL* to ``https://[your-paperless-ngx-instance]/api/documents/post_document/``
4. Set the *File Parameter Name* to ``document``
5. Add the username and password to the respective fields (Consider creating a user just for your Doxie)
6. Click *Submit* at the bottom of the page
Congrats, you can now scan directly from your Doxie to your Paperless-ngx instance!

View File

@@ -42,4 +42,3 @@ Mobile support in the future? This kinda works, however some layouts are still
too wide.
.. image:: _static/screenshots/mobile.png

View File

@@ -110,7 +110,7 @@ performs all the steps described in :ref:`setup-docker_hub` automatically.
.. code:: shell-session
$ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/install-paperless-ngx.sh)"
$ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"
.. _setup-docker_hub:
@@ -477,7 +477,7 @@ Migrating from Paperless-ng
===========================
Paperless-ngx is meant to be a drop-in replacement for Paperless-ng and thus upgrading should be
trivial for most users, especially when using docker. However, as with any major change, it is
trivial for most users, especially when using docker. However, as with any major change, it is
recommended to take a full backup first. Once you are ready, simply change the docker image to
point to the new source. E.g. if using Docker Compose, edit ``docker-compose.yml`` and change:
@@ -490,12 +490,12 @@ to
.. code::
image: ghcr.io/paperless-ngx/paperless-ngx:latest
and then run ``docker-compose up -d`` which will pull the new image recreate the container.
That's it!
Users who installed with the bare-metal route should also update their Git clone to point to
``https://github.com/paperless-ngx/paperless-ngx``, e.g. using the command
Users who installed with the bare-metal route should also update their Git clone to point to
``https://github.com/paperless-ngx/paperless-ngx``, e.g. using the command
``git remote set-url origin https://github.com/paperless-ngx/paperless-ngx`` and then pull the
lastest version.
@@ -724,6 +724,8 @@ configuring some options in paperless can help improve performance immensely:
times. Thumbnails will be about 20% larger.
* If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to
1. This will save some memory.
* Use the arm compatible docker-compose if you're wanting to use Tika on something like
a raspberry pi. The official apache/tika image does not support the arm architecture.
For details, refer to :ref:`configuration`.

View File

@@ -25,6 +25,19 @@ Check for the following issues:
* Go to the admin interface, and check if there are failed tasks. If so, the
tasks will contain an error message.
Consumer warns ``OCR for XX failed``
####################################
If you find the OCR accuracy to be too low, and/or the document consumer warns
that ``OCR for XX failed, but we're going to stick with what we've got since
FORGIVING_OCR is enabled``, then you might need to install the
`Tesseract language files <http://packages.ubuntu.com/search?keywords=tesseract-ocr>`_
marching your document's languages.
As an example, if you are running Paperless-ngx from any Ubuntu or Debian
box, and your documents are written in Spanish you may need to run::
apt-get install -y tesseract-ocr-spa
Consumer fails to pickup any new files
######################################
@@ -106,7 +119,7 @@ You may experience these errors when using the optional TIKA integration:
Gotenberg is a server that converts Office documents into PDF documents and has a default timeout of 30 seconds.
When conversion takes longer, Gotenberg raises this error.
You can increase the timeout by configuring an environment variable for Gotenberg (see also `here <https://gotenberg.dev/docs/modules/api#properties>`__).
You can increase the timeout by configuring a command flag for Gotenberg (see also `here <https://gotenberg.dev/docs/modules/api#properties>`__).
If using docker-compose, this is achieved by the following configuration change in the ``docker-compose.yml`` file:
.. code:: yaml
@@ -114,9 +127,10 @@ If using docker-compose, this is achieved by the following configuration change
gotenberg:
image: gotenberg/gotenberg:7
restart: unless-stopped
environment:
CHROMIUM_DISABLE_ROUTES: 1
API_PROCESS_TIMEOUT: 60
command:
- "gotenberg"
- "--chromium-disable-routes=true"
- "--api-timeout=60"
Permission denied errors in the consumption directory
#####################################################

View File

@@ -3,16 +3,16 @@
ask() {
while true ; do
if [[ -z $3 ]] ; then
read -p "$1 [$2]: " result
read -r -p "$1 [$2]: " result
else
read -p "$1 ($3) [$2]: " result
read -r -p "$1 ($3) [$2]: " result
fi
if [[ -z $result ]]; then
ask_result=$2
return
fi
array=$3
if [[ -z $3 || " ${array[@]} " =~ " ${result} " ]]; then
if [[ -z $3 || " ${array[*]} " =~ ${result} ]]; then
ask_result=$result
return
else
@@ -24,7 +24,7 @@ ask() {
ask_docker_folder() {
while true ; do
read -p "$1 [$2]: " result
read -r -p "$1 [$2]: " result
if [[ -z $result ]]; then
ask_result=$2
@@ -64,8 +64,7 @@ fi
# Check if user has permissions to run Docker by trying to get the status of Docker (docker status).
# If this fails, the user probably does not have permissions for Docker.
docker stats --no-stream 2>/dev/null 1>&2
if [ $? -ne 0 ] ; then
if [ ! "$(docker stats --no-stream 2>/dev/null 1>&2)" ] ; then
echo ""
echo "WARN: It look like the current user does not have Docker permissions."
echo "WARN: Use 'sudo usermod -aG docker $USER' to assign Docker permissions to the user."
@@ -162,7 +161,7 @@ ask "Target folder" "$(pwd)/paperless-ngx"
TARGET_FOLDER=$ask_result
echo ""
echo "The consume folder is where paperles will search for new documents."
echo "The consume folder is where paperless will search for new documents."
echo "Point this to a folder where your scanner is able to put your scanned"
echo "documents."
echo ""
@@ -228,7 +227,7 @@ ask "Paperless username" "$(whoami)"
USERNAME=$ask_result
while true; do
read -sp "Paperless password: " PASSWORD
read -r -sp "Paperless password: " PASSWORD
echo ""
if [[ -z $PASSWORD ]] ; then
@@ -236,7 +235,7 @@ while true; do
continue
fi
read -sp "Paperless password (again): " PASSWORD_REPEAT
read -r -sp "Paperless password (again): " PASSWORD_REPEAT
echo ""
if [[ ! "$PASSWORD" == "$PASSWORD_REPEAT" ]] ; then
@@ -285,7 +284,7 @@ echo "Paperless username: $USERNAME"
echo "Paperless email: $EMAIL"
echo ""
read -p "Press any key to install."
read -r -p "Press any key to install."
echo ""
echo "Installing paperless..."
@@ -301,10 +300,10 @@ if [[ $TIKA_ENABLED == "yes" ]] ; then
DOCKER_COMPOSE_VERSION="$DOCKER_COMPOSE_VERSION-tika"
fi
wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/docker/compose/docker-compose.$DOCKER_COMPOSE_VERSION.yml" -O docker-compose.yml
wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/docker/compose/.env" -O .env
wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.$DOCKER_COMPOSE_VERSION.yml" -O docker-compose.yml
wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env" -O .env
SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1)
SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 64 | head -n 1)
DEFAULT_LANGUAGES="deu eng fra ita spa"
@@ -318,7 +317,7 @@ DEFAULT_LANGUAGES="deu eng fra ita spa"
echo "PAPERLESS_TIME_ZONE=$TIME_ZONE"
echo "PAPERLESS_OCR_LANGUAGE=$OCR_LANGUAGE"
echo "PAPERLESS_SECRET_KEY=$SECRET_KEY"
if [[ ! " ${DEFAULT_LANGUAGES[@]} " =~ " ${OCR_LANGUAGE} " ]] ; then
if [[ ! " ${DEFAULT_LANGUAGES[*]} " =~ ${OCR_LANGUAGE} ]] ; then
echo "PAPERLESS_OCR_LANGUAGES=$OCR_LANGUAGE"
fi
} > docker-compose.env
@@ -329,16 +328,29 @@ sed -i "s#- \./consume:/usr/src/paperless/consume#- $CONSUME_FOLDER:/usr/src/pap
if [[ -n $MEDIA_FOLDER ]] ; then
sed -i "s#- media:/usr/src/paperless/media#- $MEDIA_FOLDER:/usr/src/paperless/media#g" docker-compose.yml
sed -i "/^\s*media:/d" docker-compose.yml
fi
if [[ -n $DATA_FOLDER ]] ; then
sed -i "s#- data:/usr/src/paperless/data#- $DATA_FOLDER:/usr/src/paperless/data#g" docker-compose.yml
sed -i "/^\s*data:/d" docker-compose.yml
fi
if [[ -n $POSTGRES_FOLDER ]] ; then
sed -i "s#- pgdata:/var/lib/postgresql/data#- $POSTGRES_FOLDER:/var/lib/postgresql/data#g" docker-compose.yml
sed -i "/^\s*pgdata:/d" docker-compose.yml
fi
# remove trailing blank lines from end of file
sed -i -e :a -e '/^\n*$/{$d;N;};/\n$/ba' docker-compose.yml
# if last line in file contains "volumes:", remove that line since no more named volumes are left
l1=$(grep -n '^volumes:' docker-compose.yml | cut -d : -f 1) # get line number containing volume: at begin of line
l2=$(wc -l < docker-compose.yml) # get total number of lines
if [ "$l1" -eq "$l2" ] ; then
sed -i "/^volumes:/d" docker-compose.yml
fi
docker-compose pull
docker-compose run --rm -e DJANGO_SUPERUSER_PASSWORD="$PASSWORD" webserver createsuperuser --noinput --username "$USERNAME" --email "$EMAIL"

View File

@@ -8,17 +8,18 @@
-i https://pypi.python.org/simple
--extra-index-url https://www.piwheels.org/simple
aioredis==1.3.1
anyio==3.5.0; python_full_version >= '3.6.2'
arrow==1.2.2; python_version >= '3.6'
asgiref==3.5.0; python_version >= '3.7'
async-timeout==4.0.2; python_version >= '3.6'
attrs==21.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
autobahn==22.2.2; python_version >= '3.7'
automat==20.2.0
backports.zoneinfo==0.2.1
backports.zoneinfo==0.2.1; python_version < '3.9'
blessed==1.19.1; python_version >= '2.7'
certifi==2021.10.8
cffi==1.15.0
channels-redis==3.3.1
channels-redis==3.4.0
channels==3.0.4
chardet==4.0.0; python_version >= '3.1'
charset-normalizer==2.0.12; python_version >= '3'
@@ -26,28 +27,28 @@ click==8.0.4; python_version >= '3.6'
coloredlogs==15.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
concurrent-log-handler==0.9.20
constantly==15.1.0
cryptography==36.0.1
cryptography==36.0.2; python_version >= '3.6'
daphne==3.0.2; python_version >= '3.6'
dateparser==1.1.0
dateparser==1.1.1
django-cors-headers==3.11.0
django-extensions==3.1.5
django-filter==21.1
django-picklefield==3.0.1; python_version >= '3'
django-q==1.3.9
django==3.2.12
django==4.0.3
djangorestframework==3.13.1
filelock==3.6.0
fuzzywuzzy[speedup]==0.18.0
gunicorn==20.1.0
h11==0.13.0; python_version >= '3.6'
hiredis==2.0.0; python_version >= '3.6'
httptools==0.3.0
httptools==0.4.0
humanfriendly==10.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
hyperlink==21.0.0
idna==3.3; python_version >= '3.5'
imap-tools==0.51.1
imap-tools==0.53.0
img2pdf==0.4.3
importlib-resources==5.4.0; python_version < '3.9'
importlib-resources==5.6.0; python_version < '3.9'
incremental==21.3.0
inotify-simple==1.3.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
inotifyrecursive==0.3.5
@@ -55,55 +56,56 @@ joblib==1.1.0; python_version >= '3.6'
langdetect==1.0.9
lxml==4.8.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
msgpack==1.0.3
numpy==1.22.2
ocrmypdf==13.4.0
numpy==1.22.3; python_version >= '3.8'
ocrmypdf==13.4.1
packaging==21.3; python_version >= '3.6'
pathvalidate==2.5.0
pdfminer.six==20211012
pikepdf==5.0.1
pikepdf==5.1.0
pillow==9.0.1
pluggy==1.0.0; python_version >= '3.6'
portalocker==2.4.0; python_version >= '3'
psycopg2-binary==2.9.3
psycopg2==2.9.3
pyasn1-modules==0.2.8
pyasn1==0.4.8
pycparser==2.21; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
pyopenssl==22.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
pycparser==2.21
pyopenssl==22.0.0
pyparsing==3.0.7; python_version >= '3.6'
python-dateutil==2.8.2
python-dotenv==0.19.2
python-dotenv==0.20.0
python-gnupg==0.4.8
python-levenshtein==0.12.2
python-magic==0.4.25
pytz-deprecation-shim==0.1.0.post0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'
pytz==2021.3
pytz==2022.1
pyyaml==6.0
redis==3.5.3
regex==2022.1.18
reportlab==3.6.7; python_version >= '3.6' and python_version < '4'
regex==2022.3.2; python_version >= '3.6'
reportlab==3.6.9; python_version >= '3.7' and python_version < '4'
requests==2.27.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'
scikit-learn==0.24.0
scikit-learn==1.0.2
scipy==1.8.0; python_version < '3.11' and python_version >= '3.8'
service-identity==21.1.0
setuptools==60.9.3; python_version >= '3.7'
setuptools==61.1.1; python_version >= '3.7'
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
sniffio==1.2.0; python_version >= '3.5'
sqlparse==0.4.2; python_version >= '3.5'
threadpoolctl==3.1.0; python_version >= '3.6'
tika==1.24
tqdm==4.62.3
twisted[tls]==22.1.0; python_full_version >= '3.6.7'
tqdm==4.63.1
twisted[tls]==22.2.0; python_full_version >= '3.6.7'
txaio==22.2.1; python_version >= '3.6'
typing-extensions==4.1.1; python_version >= '3.6'
tzdata==2021.5; python_version >= '3.6'
tzdata==2022.1; python_version >= '3.6'
tzlocal==4.1; python_version >= '3.6'
urllib3==1.26.8; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'
uvicorn[standard]==0.17.5
urllib3==1.26.9; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'
uvicorn[standard]==0.17.6
uvloop==0.16.0
watchdog==2.1.6
watchgod==0.7
watchdog==2.1.7
watchgod==0.8.1
wcwidth==0.2.5
websockets==10.2
whitenoise==6.0.0
whoosh==2.7.4
zipp==3.7.0; python_version < '3.10'
zipp==3.7.0; python_version < '3.9'
zope.interface==5.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'

View File

@@ -1,3 +1,5 @@
#!/usr/bin/env bash
docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:13
docker run -d -p 6379:6379 redis:latest
docker run -p 3000:3000 -d gotenberg/gotenberg:7

4
src-ui/.gitignore vendored
View File

@@ -45,3 +45,7 @@ testem.log
# System Files
.DS_Store
Thumbs.db
# Cypress
cypress/videos/**/*
cypress/screenshots/**/*

View File

@@ -16,6 +16,7 @@
"i18n": {
"sourceLocale": "en-US",
"locales": {
"be-BY": "src/locale/messages.be_BY.xlf",
"cs-CZ": "src/locale/messages.cs_CZ.xlf",
"da-DK": "src/locale/messages.da_DK.xlf",
"de-DE": "src/locale/messages.de_DE.xlf",
@@ -30,8 +31,12 @@
"pt-PT": "src/locale/messages.pt_PT.xlf",
"ro-RO": "src/locale/messages.ro_RO.xlf",
"ru-RU": "src/locale/messages.ru_RU.xlf",
"sv-SE": "src/locale/messages.sv_SE.xlf"
}
"sl-SI": "src/locale/messages.sl_SI.xlf",
"sr-CS": "src/locale/messages.sr_CS.xlf",
"sv-SE": "src/locale/messages.sv_SE.xlf",
"tr-TR": "src/locale/messages.tr_TR.xlf",
"zh-CN": "src/locale/messages.zh_CN.xlf"
}
},
"architect": {
"build": {
@@ -121,12 +126,9 @@
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"builder": "@angular-builders/jest:run",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/apple-touch-icon.png",
@@ -140,9 +142,21 @@
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"builder": "@cypress/schematic:cypress",
"options": {
"devServerTarget": "paperless-ui:serve",
"watch": true,
"headless": false
},
"configurations": {
"production": {
"devServerTarget": "paperless-ui:serve:production"
}
}
},
"cypress-run": {
"builder": "@cypress/schematic:cypress",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "paperless-ui:serve"
},
"configurations": {
@@ -150,6 +164,13 @@
"devServerTarget": "paperless-ui:serve:production"
}
}
},
"cypress-open": {
"builder": "@cypress/schematic:cypress",
"options": {
"watch": true,
"headless": false
}
}
}
}

9
src-ui/cypress.json Normal file
View File

@@ -0,0 +1,9 @@
{
"integrationFolder": "cypress/integration",
"supportFile": "cypress/support/index.ts",
"videosFolder": "cypress/videos",
"screenshotsFolder": "cypress/screenshots",
"pluginsFile": "cypress/plugins/index.ts",
"fixturesFolder": "cypress/fixtures",
"baseUrl": "http://localhost:4200"
}

View File

@@ -0,0 +1 @@
{"count":27,"next":"http://localhost:8000/api/correspondents/?page=2","previous":null,"results":[{"id":9,"slug":"abc-test-correspondent","name":"ABC Test Correspondent","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":13,"slug":"corresp-10","name":"Corresp 10","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":14,"slug":"corresp-11","name":"Corresp 11","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":15,"slug":"corresp-12","name":"Corresp 12","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":16,"slug":"corresp-13","name":"Corresp 13","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":18,"slug":"corresp-15","name":"Corresp 15","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":19,"slug":"corresp-16","name":"Corresp 16","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":20,"slug":"corresp-17","name":"Corresp 17","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":21,"slug":"corresp-18","name":"Corresp 18","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":22,"slug":"corresp-19","name":"Corresp 19","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":23,"slug":"corresp-20","name":"Corresp 20","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":24,"slug":"corresp-21","name":"Corresp 21","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":25,"slug":"corresp-22","name":"Corresp 22","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":26,"slug":"corresp-23","name":"Corresp 23","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":5,"slug":"corresp-3","name":"Corresp 3","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":6,"slug":"corresp-4","name":"Corresp 4","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":7,"slug":"corresp-5","name":"Corresp 5","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":8,"slug":"corresp-6","name":"Corresp 6","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":10,"slug":"corresp-7","name":"Corresp 7","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":11,"slug":"corresp-8","name":"Corresp 8","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":12,"slug":"corresp-9","name":"Corresp 9","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":17,"slug":"correspondent-14","name":"Correspondent 14","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":2,"slug":"correspondent-2","name":"Correspondent 2","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":7,"last_correspondence":"2021-01-20T23:37:58.204614Z"},{"id":27,"slug":"michael-shamoon","name":"Michael Shamoon","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":1,"last_correspondence":"2022-03-16T03:48:50.089624Z"},{"id":4,"slug":"newest-correspondent","name":"Newest Correspondent","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":1,"last_correspondence":"2021-02-07T08:00:00Z"}]}

View File

@@ -0,0 +1 @@
{"count":1,"next":null,"previous":null,"results":[{"id":1,"slug":"test","name":"Test Doc Type","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0}]}

View File

@@ -0,0 +1 @@
{"original_checksum":"e959bc7d593245d92685213264e962ba","original_size":963754,"original_mime_type":"application/pdf","media_filename":"2022/lorem-ipsum.pdf","has_archive_version":true,"original_metadata":[],"archive_checksum":"5a1f46a9150bcade978c764b039ce4d0","archive_media_filename":"2022/lorem-ipsum.pdf","archive_size":351160,"archive_metadata":[{"namespace":"http://ns.adobe.com/pdf/1.3/","prefix":"pdf","key":"Producer","value":"pikepdf5.0.1"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"ModifyDate","value":"2022-03-22T04:53:18+00:00"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"CreateDate","value":"2022-03-22T18:05:43+00:00"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"CreatorTool","value":"ocrmypdf13.4.0/TesseractOCR-PDF4.1.1"},{"namespace":"http://ns.adobe.com/xap/1.0/mm/","prefix":"xmpMM","key":"DocumentID","value":"uuid:df27edcf-e34a-11f7-0000-8fa6067a3c04"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"format","value":"application/pdf"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"title","value":"ScannedDocument"},{"namespace":"http://www.aiim.org/pdfa/ns/id/","prefix":"pdfaid","key":"part","value":"2"},{"namespace":"http://www.aiim.org/pdfa/ns/id/","prefix":"pdfaid","key":"conformance","value":"B"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"creator","value":"None"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"MetadataDate","value":"2022-03-22T21:53:18.882551-07:00"}]}

View File

@@ -0,0 +1 @@
{"correspondents":[],"tags":[3],"document_types":[1]}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View File

@@ -0,0 +1 @@
{"count":3,"next":null,"previous":null,"results":[{"id":1,"name":"Inbox","show_on_dashboard":true,"show_in_sidebar":true,"sort_field":"created","sort_reverse":true,"filter_rules":[{"rule_type":6,"value":"18"}]},{"id":2,"name":"Recently Added","show_on_dashboard":true,"show_in_sidebar":false,"sort_field":"created","sort_reverse":true,"filter_rules":[]},{"id":11,"name":"Taxes","show_on_dashboard":false,"show_in_sidebar":true,"sort_field":"created","sort_reverse":true,"filter_rules":[{"rule_type":6,"value":"39"}]}]}

View File

@@ -0,0 +1 @@
{"count":8,"next":null,"previous":null,"results":[{"id":4,"slug":"another-sample-tag","name":"Another Sample Tag","color":"#a6cee3","text_color":"#000000","match":"","matching_algorithm":6,"is_insensitive":true,"is_inbox_tag":false,"document_count":3},{"id":7,"slug":"newone","name":"NewOne","color":"#9e4ad1","text_color":"#ffffff","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":2},{"id":6,"slug":"partial-tag","name":"Partial Tag","color":"#72dba7","text_color":"#000000","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":1},{"id":2,"slug":"tag-2","name":"Tag 2","color":"#612db7","text_color":"#ffffff","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":3},{"id":3,"slug":"tag-3","name":"Tag 3","color":"#b2df8a","text_color":"#000000","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":4},{"id":5,"slug":"tagwithpartial","name":"TagWithPartial","color":"#3b2db4","text_color":"#ffffff","match":"","matching_algorithm":6,"is_insensitive":true,"is_inbox_tag":false,"document_count":2},{"id":8,"slug":"test-another","name":"Test Another","color":"#3ccea5","text_color":"#000000","match":"","matching_algorithm":4,"is_insensitive":true,"is_inbox_tag":false,"document_count":0},{"id":1,"slug":"test-tag","name":"Test Tag","color":"#fb9a99","text_color":"#000000","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":4}]}

View File

@@ -0,0 +1,64 @@
describe('document-detail', () => {
beforeEach(() => {
this.modifiedDocuments = []
cy.fixture('documents/documents.json').then((documentsJson) => {
cy.intercept('GET', 'http://localhost:8000/api/documents/1/', (req) => {
let response = { ...documentsJson }
response = response.results.find((d) => d.id == 1)
req.reply(response)
})
})
cy.intercept('PUT', 'http://localhost:8000/api/documents/1/', (req) => {
this.modifiedDocuments.push(req.body) // store this for later
req.reply({ result: 'OK' })
}).as('saveDoc')
cy.intercept('http://localhost:8000/api/documents/1/metadata/', {
fixture: 'documents/1/metadata.json',
})
cy.intercept('http://localhost:8000/api/documents/1/suggestions/', {
fixture: 'documents/1/suggestions.json',
})
cy.intercept('http://localhost:8000/api/saved_views/*', {
fixture: 'saved_views/savedviews.json',
})
cy.intercept('http://localhost:8000/api/tags/*', {
fixture: 'tags/tags.json',
})
cy.intercept('http://localhost:8000/api/correspondents/*', {
fixture: 'correspondents/correspondents.json',
})
cy.intercept('http://localhost:8000/api/document_types/*', {
fixture: 'document_types/doctypes.json',
})
cy.viewport(1024, 1024)
cy.visit('/documents/1/')
})
it('should activate / deactivate save button when changes are saved', () => {
cy.contains('button', 'Save').should('be.disabled')
cy.get('app-input-text[formcontrolname="title"]')
.type(' additional')
.wait(1500) // this delay is for frontend debounce
cy.contains('button', 'Save').should('not.be.disabled')
})
it('should warn on unsaved changes', () => {
cy.get('app-input-text[formcontrolname="title"]')
.type(' additional')
.wait(1500) // this delay is for frontend debounce
cy.get('button[title="Close"]').click()
cy.contains('You have unsaved changes')
cy.contains('button', 'Cancel').click().wait(150)
cy.contains('button', 'Save').click().wait('@saveDoc').wait(2000) // navigates away after saving
cy.contains('You have unsaved changes').should('not.exist')
})
})

View File

@@ -0,0 +1,143 @@
describe('documents-list', () => {
beforeEach(() => {
this.bulkEdits = {}
// mock API methods
cy.fixture('documents/documents.json').then((documentsJson) => {
// bulk edit
cy.intercept(
'POST',
'http://localhost:8000/api/documents/bulk_edit/',
(req) => {
this.bulkEdits = req.body // store this for later
req.reply({ result: 'OK' })
}
)
cy.intercept('GET', 'http://localhost:8000/api/documents/*', (req) => {
let response = { ...documentsJson }
// bulkEdits was set earlier by bulk_edit intercept
if (this.bulkEdits.hasOwnProperty('documents')) {
response.results = response.results.map((d) => {
if ((this.bulkEdits['documents'] as Array<number>).includes(d.id)) {
switch (this.bulkEdits['method']) {
case 'modify_tags':
d.tags = (d.tags as Array<number>).concat([
this.bulkEdits['parameters']['add_tags'],
])
break
case 'set_correspondent':
d.correspondent =
this.bulkEdits['parameters']['correspondent']
break
case 'set_document_type':
d.document_type =
this.bulkEdits['parameters']['document_type']
break
}
}
return d
})
} else if (req.query.hasOwnProperty('tags__id__all')) {
// filtering e.g. http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&tags__id__all=2
const tag_id = +req.query['tags__id__all']
response.results = (documentsJson.results as Array<any>).filter((d) =>
(d.tags as Array<number>).includes(tag_id)
)
response.count = response.results.length
}
req.reply(response)
})
})
cy.intercept('http://localhost:8000/api/documents/1/thumb/', {
fixture: 'documents/lorem-ipsum.png',
})
cy.intercept('http://localhost:8000/api/tags/*', {
fixture: 'tags/tags.json',
})
cy.intercept('http://localhost:8000/api/correspondents/*', {
fixture: 'correspondents/correspondents.json',
})
cy.intercept('http://localhost:8000/api/document_types/*', {
fixture: 'document_types/doctypes.json',
})
cy.visit('/documents')
})
it('should show a list of documents rendered as cards with thumbnails', () => {
cy.contains('3 documents')
cy.contains('lorem-ipsum')
cy.get('app-document-card-small:first-of-type img')
.invoke('attr', 'src')
.should('eq', 'http://localhost:8000/api/documents/1/thumb/')
})
it('should change to table "details" view', () => {
cy.get('div.btn-group-toggle input[value="details"]').parent().click()
cy.get('table')
})
it('should change to large cards view', () => {
cy.get('div.btn-group-toggle input[value="largeCards"]').parent().click()
cy.get('app-document-card-large')
})
it('should filter tags', () => {
cy.get('app-filter-editor app-filterable-dropdown[title="Tags"]').within(
() => {
cy.contains('button', 'Tags').click()
cy.contains('button', 'Tag 2').click()
}
)
cy.contains('One document')
})
it('should apply tags', () => {
cy.get('app-document-card-small:first-of-type').click()
cy.get('app-bulk-editor app-filterable-dropdown[title="Tags"]').within(
() => {
cy.contains('button', 'Tags').click()
cy.contains('button', 'Test Tag').click()
cy.contains('button', 'Apply').click()
}
)
cy.contains('button', 'Confirm').click()
cy.get('app-document-card-small:first-of-type').contains('Test Tag')
})
it('should apply correspondent', () => {
cy.get('app-document-card-small:first-of-type').click()
cy.get(
'app-bulk-editor app-filterable-dropdown[title="Correspondent"]'
).within(() => {
cy.contains('button', 'Correspondent').click()
cy.contains('button', 'ABC Test Correspondent').click()
cy.contains('button', 'Apply').click()
})
cy.contains('button', 'Confirm').click()
cy.get('app-document-card-small:first-of-type').contains(
'ABC Test Correspondent'
)
})
it('should apply document type', () => {
cy.get('app-document-card-small:first-of-type').click()
cy.get(
'app-bulk-editor app-filterable-dropdown[title="Document type"]'
).within(() => {
cy.contains('button', 'Document type').click()
cy.contains('button', 'Test Doc Type').click()
cy.contains('button', 'Apply').click()
})
cy.contains('button', 'Confirm').click()
cy.get('app-document-card-small:first-of-type').contains('Test Doc Type')
})
})

View File

@@ -0,0 +1,32 @@
describe('manage', () => {
beforeEach(() => {
cy.intercept('http://localhost:8000/api/correspondents/*', {
fixture: 'correspondents/correspondents.json',
})
cy.intercept('http://localhost:8000/api/tags/*', {
fixture: 'tags/tags.json',
})
})
it('should show a list of correspondents with bottom pagination as well', () => {
cy.visit('/correspondents')
cy.get('tbody').find('tr').its('length').should('eq', 25)
cy.get('ngb-pagination').its('length').should('eq', 2)
})
it('should show a list of tags without bottom pagination', () => {
cy.visit('/tags')
cy.get('tbody').find('tr').its('length').should('eq', 8)
cy.get('ngb-pagination').its('length').should('eq', 1)
})
it('should show a list of documents filtered by tag', () => {
cy.intercept('http://localhost:8000/api/documents/*', (req) => {
if (req.url.indexOf('tags__id__all=4'))
req.reply({ count: 3, next: null, previous: null, results: [] })
})
cy.visit('/tags')
cy.get('tbody').find('button').contains('Documents').first().click() // id = 4
cy.contains('3 documents')
})
})

View File

@@ -0,0 +1,91 @@
describe('settings', () => {
beforeEach(() => {
this.modifiedViews = []
// mock API methods
cy.fixture('saved_views/savedviews.json').then((savedViewsJson) => {
// saved views PATCH
cy.intercept(
'PATCH',
'http://localhost:8000/api/saved_views/*',
(req) => {
this.modifiedViews.push(req.body) // store this for later
req.reply({ result: 'OK' })
}
)
cy.intercept('GET', 'http://localhost:8000/api/saved_views/*', (req) => {
let response = { ...savedViewsJson }
if (this.modifiedViews.length) {
response.results = response.results.map((v) => {
if (this.modifiedViews.find((mv) => mv.id == v.id))
v = this.modifiedViews.find((mv) => mv.id == v.id)
return v
})
}
req.reply(response)
}).as('savedViews')
})
cy.fixture('documents/documents.json').then((documentsJson) => {
cy.intercept('GET', 'http://localhost:8000/api/documents/1/', (req) => {
let response = { ...documentsJson }
response = response.results.find((d) => d.id == 1)
req.reply(response)
})
})
cy.intercept('http://localhost:8000/api/documents/1/metadata/', {
fixture: 'documents/1/metadata.json',
})
cy.intercept('http://localhost:8000/api/documents/1/suggestions/', {
fixture: 'documents/1/suggestions.json',
})
cy.viewport(1024, 1024)
cy.visit('/settings')
cy.wait('@savedViews')
})
it('should activate / deactivate save button when settings change and are saved', () => {
cy.contains('button', 'Save').should('be.disabled')
cy.contains('Use system settings').click()
cy.contains('button', 'Save').should('not.be.disabled')
cy.contains('button', 'Save').click()
cy.contains('button', 'Save').should('be.disabled')
})
it('should warn on unsaved changes', () => {
cy.contains('Use system settings').click()
cy.contains('a', 'Dashboard').click()
cy.contains('You have unsaved changes')
cy.contains('button', 'Cancel').click()
cy.contains('button', 'Save').click().wait('@savedViews')
cy.contains('a', 'Dashboard').click()
cy.contains('You have unsaved changes').should('not.exist')
})
it('should apply appearance changes when set', () => {
cy.contains('Use system settings').click()
cy.get('body').should('not.have.class', 'color-scheme-system')
cy.contains('Enable dark mode').click()
cy.get('body').should('have.class', 'color-scheme-dark')
})
it('should remove saved view from sidebar when unset', () => {
cy.contains('a', 'Saved views').click()
cy.get('#show_in_sidebar_1').click()
cy.contains('button', 'Save').click().wait('@savedViews')
cy.contains('li', 'Inbox').should('not.exist')
})
it('should remove saved view from dashboard when unset', () => {
cy.contains('a', 'Saved views').click()
cy.get('#show_on_dashboard_1').click()
cy.contains('button', 'Save').click().wait('@savedViews')
cy.visit('/dashboard')
cy.get('app-saved-view-widget').contains('Inbox').should('not.exist')
})
})

View File

@@ -0,0 +1,3 @@
// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress
// For more info, visit https://on.cypress.io/plugins-api
module.exports = (on, config) => {}

View File

@@ -0,0 +1,43 @@
// ***********************************************
// This example namespace declaration will help
// with Intellisense and code completion in your
// IDE or Text Editor.
// ***********************************************
// declare namespace Cypress {
// interface Chainable<Subject = any> {
// customCommand(param: any): typeof customCommand;
// }
// }
//
// function customCommand(param: any): void {
// console.warn(param);
// }
//
// NOTE: You can use it like so:
// Cypress.Commands.add('customCommand', customCommand);
//
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

View File

@@ -0,0 +1,17 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// When a command from ./commands is ready to use, import with `import './commands'` syntax
// import './commands';

View File

@@ -0,0 +1,8 @@
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"compilerOptions": {
"sourceMap": false,
"types": ["cypress"]
}
}

View File

@@ -2,18 +2,16 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter')
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
specs: ['./src/**/*.e2e-spec.ts'],
capabilities: {
browserName: 'chrome'
browserName: 'chrome',
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
@@ -21,16 +19,18 @@ exports.config = {
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
print: function () {},
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY
}
}));
}
};
project: require('path').join(__dirname, './tsconfig.json'),
})
jasmine.getEnv().addReporter(
new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY,
},
})
)
},
}

View File

@@ -1,23 +1,25 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
import { AppPage } from './app.po'
import { browser, logging } from 'protractor'
describe('workspace-project App', () => {
let page: AppPage;
let page: AppPage
beforeEach(() => {
page = new AppPage();
});
page = new AppPage()
})
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('paperless-ui app is running!');
});
page.navigateTo()
expect(page.getTitleText()).toEqual('paperless-ui app is running!')
})
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
const logs = await browser.manage().logs().get(logging.Type.BROWSER)
expect(logs).not.toContain(
jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry)
)
})
})

View File

@@ -1,11 +1,13 @@
import { browser, by, element } from 'protractor';
import { browser, by, element } from 'protractor'
export class AppPage {
navigateTo(): Promise<unknown> {
return browser.get(browser.baseUrl) as Promise<unknown>;
return browser.get(browser.baseUrl) as Promise<unknown>
}
getTitleText(): Promise<string> {
return element(by.css('app-root .content span')).getText() as Promise<string>;
return element(
by.css('app-root .content span')
).getText() as Promise<string>
}
}

8
src-ui/jest.config.js Normal file
View File

@@ -0,0 +1,8 @@
module.exports = {
moduleNameMapper: {
'@core/(.*)': '<rootDir>/src/app/core/$1',
},
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
testPathIgnorePatterns: ['/node_modules/', '/cypress/'],
}

View File

@@ -1,32 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/paperless-ui'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

15205
src-ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,53 +7,52 @@
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"e2e": "ng e2e",
"cy:run": "cypress run",
"e2e:ci": "concurrently 'npm run start' 'wait-on http-get://localhost:4200 && npm run cy:run' --kill-others --success first"
},
"private": true,
"dependencies": {
"@angular/animations": "~13.2.4",
"@angular/common": "~13.2.4",
"@angular/compiler": "~13.2.4",
"@angular/core": "~13.2.4",
"@angular/forms": "~13.2.4",
"@angular/localize": "~13.2.4",
"@angular/platform-browser": "~13.2.4",
"@angular/platform-browser-dynamic": "~13.2.4",
"@angular/router": "~13.2.4",
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
"@angular/common": "~13.3.1",
"@angular/compiler": "~13.3.1",
"@angular/core": "~13.3.1",
"@angular/forms": "~13.3.1",
"@angular/localize": "~13.3.1",
"@angular/platform-browser": "~13.3.1",
"@angular/platform-browser-dynamic": "~13.3.1",
"@angular/router": "~13.3.1",
"@ng-bootstrap/ng-bootstrap": "^12.0.1",
"@ng-select/ng-select": "^8.1.1",
"@ngneat/dirty-check-forms": "^1.1.0",
"@popperjs/core": "^2.11.2",
"@ngneat/dirty-check-forms": "^3.0.2",
"@popperjs/core": "^2.11.4",
"bootstrap": "^5.1.3",
"file-saver": "^2.0.5",
"ng2-pdf-viewer": "^8.0.1",
"ng2-pdf-viewer": "^9.0.0",
"ngx-color": "^7.3.3",
"ngx-cookie-service": "^13.1.2",
"ngx-file-drop": "^13.0.0",
"ngx-infinite-scroll": "^10.0.1",
"rxjs": "~6.6.7",
"rxjs": "~7.5.5",
"tslib": "^2.3.1",
"uuid": "^8.3.1",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~13.2.5",
"@angular/cli": "~13.2.5",
"@angular/compiler-cli": "~13.2.4",
"@types/jasmine": "~3.10.3",
"@types/jasminewd2": "~2.0.10",
"@types/node": "^17.0.21",
"@angular-builders/jest": "13.0.3",
"@angular-devkit/build-angular": "~13.3.1",
"@angular/cli": "~13.3.1",
"@angular/compiler-cli": "~13.3.1",
"@types/jest": "27.4.1",
"@types/node": "^17.0.23",
"codelyzer": "^6.0.2",
"jasmine-core": "~4.0.1",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.3.16",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"protractor": "~7.0.0",
"ts-node": "~10.5.0",
"concurrently": "7.0.0",
"jest": "27.5.1",
"ts-node": "~10.7.0",
"tslint": "~6.1.3",
"typescript": "~4.5.5"
"typescript": "~4.6.3",
"wait-on": "~6.0.1"
},
"optionalDependencies": {
"cypress": "~9.5.3",
"@cypress/schematic": "^1.6.0"
}
}

30
src-ui/setup-jest.ts Normal file
View File

@@ -0,0 +1,30 @@
import 'jest-preset-angular/setup-jest'
/* global mocks for jsdom */
const mock = () => {
let storage: { [key: string]: string } = {}
return {
getItem: (key: string) => (key in storage ? storage[key] : null),
setItem: (key: string, value: string) => (storage[key] = value || ''),
removeItem: (key: string) => delete storage[key],
clear: () => (storage = {}),
}
}
Object.defineProperty(window, 'localStorage', { value: mock() })
Object.defineProperty(window, 'sessionStorage', { value: mock() })
Object.defineProperty(window, 'getComputedStyle', {
value: () => ['-webkit-appearance'],
})
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
}
},
})
/* output shorter and more meaningful Zone error stack traces */
// Error.stackTraceLimit = 2

View File

@@ -1,39 +1,47 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppFrameComponent } from './components/app-frame/app-frame.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { DocumentDetailComponent } from './components/document-detail/document-detail.component';
import { DocumentListComponent } from './components/document-list/document-list.component';
import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component';
import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component';
import { LogsComponent } from './components/manage/logs/logs.component';
import { SettingsComponent } from './components/manage/settings/settings.component';
import { TagListComponent } from './components/manage/tag-list/tag-list.component';
import { NotFoundComponent } from './components/not-found/not-found.component';
import {DocumentAsnComponent} from "./components/document-asn/document-asn.component";
import { DirtyFormGuard } from './guards/dirty-form.guard';
import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router'
import { AppFrameComponent } from './components/app-frame/app-frame.component'
import { DashboardComponent } from './components/dashboard/dashboard.component'
import { DocumentDetailComponent } from './components/document-detail/document-detail.component'
import { DocumentListComponent } from './components/document-list/document-list.component'
import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'
import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component'
import { LogsComponent } from './components/manage/logs/logs.component'
import { SettingsComponent } from './components/manage/settings/settings.component'
import { TagListComponent } from './components/manage/tag-list/tag-list.component'
import { NotFoundComponent } from './components/not-found/not-found.component'
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
import { DirtyFormGuard } from './guards/dirty-form.guard'
const routes: Routes = [
{path: '', redirectTo: 'dashboard', pathMatch: 'full'},
{path: '', component: AppFrameComponent, children: [
{path: 'dashboard', component: DashboardComponent },
{path: 'documents', component: DocumentListComponent },
{path: 'view/:id', component: DocumentListComponent },
{path: 'documents/:id', component: DocumentDetailComponent },
{path: 'asn/:id', component: DocumentAsnComponent },
{path: 'tags', component: TagListComponent },
{path: 'documenttypes', component: DocumentTypeListComponent },
{path: 'correspondents', component: CorrespondentListComponent },
{path: 'logs', component: LogsComponent },
{path: 'settings', component: SettingsComponent, canDeactivate: [DirtyFormGuard] },
]},
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{
path: '',
component: AppFrameComponent,
children: [
{ path: 'dashboard', component: DashboardComponent },
{ path: 'documents', component: DocumentListComponent },
{ path: 'view/:id', component: DocumentListComponent },
{ path: 'documents/:id', component: DocumentDetailComponent },
{ path: 'asn/:id', component: DocumentAsnComponent },
{ path: 'tags', component: TagListComponent },
{ path: 'documenttypes', component: DocumentTypeListComponent },
{ path: 'correspondents', component: CorrespondentListComponent },
{ path: 'logs', component: LogsComponent },
{
path: 'settings',
component: SettingsComponent,
canDeactivate: [DirtyFormGuard],
},
],
},
{path: '404', component: NotFoundComponent},
{path: '**', redirectTo: '/404', pathMatch: 'full'}
];
{ path: '404', component: NotFoundComponent },
{ path: '**', redirectTo: '/404', pathMatch: 'full' },
]
@NgModule({
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
exports: [RouterModule]
exports: [RouterModule],
})
export class AppRoutingModule { }
export class AppRoutingModule {}

View File

@@ -1,35 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'paperless-ui'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('paperless-ui');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('paperless-ui app is running!');
});
});

View File

@@ -1,25 +1,29 @@
import { SettingsService, SETTINGS_KEYS } from './services/settings.service';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { ConsumerStatusService } from './services/consumer-status.service';
import { ToastService } from './services/toast.service';
import { SettingsService, SETTINGS_KEYS } from './services/settings.service'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Router } from '@angular/router'
import { Subscription } from 'rxjs'
import { ConsumerStatusService } from './services/consumer-status.service'
import { ToastService } from './services/toast.service'
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy {
newDocumentSubscription: Subscription
successSubscription: Subscription
failedSubscription: Subscription
newDocumentSubscription: Subscription;
successSubscription: Subscription;
failedSubscription: Subscription;
constructor (private settings: SettingsService, private consumerStatusService: ConsumerStatusService, private toastService: ToastService, private router: Router) {
let anyWindow = (window as any)
anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js';
this.settings.updateDarkModeSettings()
constructor(
private settings: SettingsService,
private consumerStatusService: ConsumerStatusService,
private toastService: ToastService,
private router: Router
) {
let anyWindow = window as any
anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js'
this.settings.updateAppearanceSettings()
}
ngOnDestroy(): void {
@@ -36,7 +40,12 @@ export class AppComponent implements OnInit, OnDestroy {
}
private showNotification(key) {
if (this.router.url == '/dashboard' && this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD)) {
if (
this.router.url == '/dashboard' &&
this.settings.get(
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD
)
) {
return false
}
return this.settings.get(key)
@@ -45,26 +54,50 @@ export class AppComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.consumerStatusService.connect()
this.successSubscription = this.consumerStatusService
.onDocumentConsumptionFinished()
.subscribe((status) => {
if (
this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)
) {
this.toastService.show({
title: $localize`Document added`,
delay: 10000,
content: $localize`Document ${status.filename} was added to paperless.`,
actionName: $localize`Open document`,
action: () => {
this.router.navigate(['documents', status.documentId])
},
})
}
})
this.successSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => {
if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)) {
this.toastService.show({title: $localize`Document added`, delay: 10000, content: $localize`Document ${status.filename} was added to paperless.`, actionName: $localize`Open document`, action: () => {
this.router.navigate(['documents', status.documentId])
}})
}
})
this.failedSubscription = this.consumerStatusService
.onDocumentConsumptionFailed()
.subscribe((status) => {
if (
this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED)
) {
this.toastService.showError(
$localize`Could not add ${status.filename}\: ${status.message}`
)
}
})
this.failedSubscription = this.consumerStatusService.onDocumentConsumptionFailed().subscribe(status => {
if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED)) {
this.toastService.showError($localize`Could not add ${status.filename}\: ${status.message}`)
}
})
this.newDocumentSubscription = this.consumerStatusService.onDocumentDetected().subscribe(status => {
if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT)) {
this.toastService.show({title: $localize`New document detected`, delay: 5000, content: $localize`Document ${status.filename} is being processed by paperless.`})
}
})
this.newDocumentSubscription = this.consumerStatusService
.onDocumentDetected()
.subscribe((status) => {
if (
this.showNotification(
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT
)
) {
this.toastService.show({
title: $localize`New document detected`,
delay: 5000,
content: $localize`Document ${status.filename} is being processed by paperless.`,
})
}
})
}
}

View File

@@ -1,86 +1,94 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgbDateAdapter, NgbDateParserFormatter, NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { DocumentListComponent } from './components/document-list/document-list.component';
import { DocumentDetailComponent } from './components/document-detail/document-detail.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { TagListComponent } from './components/manage/tag-list/tag-list.component';
import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component';
import { LogsComponent } from './components/manage/logs/logs.component';
import { SettingsComponent } from './components/manage/settings/settings.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DatePipe, registerLocaleData } from '@angular/common';
import { NotFoundComponent } from './components/not-found/not-found.component';
import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component';
import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component';
import { CorrespondentEditDialogComponent } from './components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component';
import { TagEditDialogComponent } from './components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component';
import { DocumentTypeEditDialogComponent } from './components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component';
import { TagComponent } from './components/common/tag/tag.component';
import { PageHeaderComponent } from './components/common/page-header/page-header.component';
import { AppFrameComponent } from './components/app-frame/app-frame.component';
import { ToastsComponent } from './components/common/toasts/toasts.component';
import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component';
import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component';
import { ToggleableDropdownButtonComponent } from './components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component';
import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component';
import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component';
import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component';
import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component';
import { NgxFileDropModule } from 'ngx-file-drop';
import { TextComponent } from './components/common/input/text/text.component';
import { SelectComponent } from './components/common/input/select/select.component';
import { CheckComponent } from './components/common/input/check/check.component';
import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { TagsComponent } from './components/common/input/tags/tags.component';
import { SortableDirective } from './directives/sortable.directive';
import { CookieService } from 'ngx-cookie-service';
import { CsrfInterceptor } from './interceptors/csrf.interceptor';
import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component';
import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component';
import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component';
import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component';
import { PdfViewerModule } from 'ng2-pdf-viewer';
import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component';
import { YesNoPipe } from './pipes/yes-no.pipe';
import { FileSizePipe } from './pipes/file-size.pipe';
import { FilterPipe } from './pipes/filter.pipe';
import { DocumentTitlePipe } from './pipes/document-title.pipe';
import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component';
import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component';
import { NgSelectModule } from '@ng-select/ng-select';
import { NumberComponent } from './components/common/input/number/number.component';
import { SafePipe } from './pipes/safe.pipe';
import { CustomDatePipe } from './pipes/custom-date.pipe';
import { DateComponent } from './components/common/input/date/date.component';
import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter';
import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter';
import { ApiVersionInterceptor } from './interceptors/api-version.interceptor';
import { ColorSliderModule } from 'ngx-color/slider';
import { ColorComponent } from './components/common/input/color/color.component';
import { DocumentAsnComponent } from './components/document-asn/document-asn.component';
import localeCs from '@angular/common/locales/cs';
import localeDa from '@angular/common/locales/da';
import localeDe from '@angular/common/locales/de';
import localeEnGb from '@angular/common/locales/en-GB';
import localeEs from '@angular/common/locales/es';
import localeFr from '@angular/common/locales/fr';
import localeIt from '@angular/common/locales/it';
import localeLb from '@angular/common/locales/lb';
import localeNl from '@angular/common/locales/nl';
import localePl from '@angular/common/locales/pl';
import localePt from '@angular/common/locales/pt';
import localeSv from '@angular/common/locales/sv';
import localeRo from '@angular/common/locales/ro';
import localeRu from '@angular/common/locales/ru';
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import {
NgbDateAdapter,
NgbDateParserFormatter,
NgbModule,
} from '@ng-bootstrap/ng-bootstrap'
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { DocumentListComponent } from './components/document-list/document-list.component'
import { DocumentDetailComponent } from './components/document-detail/document-detail.component'
import { DashboardComponent } from './components/dashboard/dashboard.component'
import { TagListComponent } from './components/manage/tag-list/tag-list.component'
import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component'
import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'
import { LogsComponent } from './components/manage/logs/logs.component'
import { SettingsComponent } from './components/manage/settings/settings.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { DatePipe, registerLocaleData } from '@angular/common'
import { NotFoundComponent } from './components/not-found/not-found.component'
import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component'
import { CorrespondentEditDialogComponent } from './components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component'
import { TagEditDialogComponent } from './components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
import { DocumentTypeEditDialogComponent } from './components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component'
import { TagComponent } from './components/common/tag/tag.component'
import { PageHeaderComponent } from './components/common/page-header/page-header.component'
import { AppFrameComponent } from './components/app-frame/app-frame.component'
import { ToastsComponent } from './components/common/toasts/toasts.component'
import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component'
import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component'
import { ToggleableDropdownButtonComponent } from './components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'
import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component'
import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component'
import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component'
import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component'
import { NgxFileDropModule } from 'ngx-file-drop'
import { TextComponent } from './components/common/input/text/text.component'
import { SelectComponent } from './components/common/input/select/select.component'
import { CheckComponent } from './components/common/input/check/check.component'
import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component'
import { TagsComponent } from './components/common/input/tags/tags.component'
import { SortableDirective } from './directives/sortable.directive'
import { CookieService } from 'ngx-cookie-service'
import { CsrfInterceptor } from './interceptors/csrf.interceptor'
import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component'
import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component'
import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component'
import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component'
import { PdfViewerModule } from 'ng2-pdf-viewer'
import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component'
import { YesNoPipe } from './pipes/yes-no.pipe'
import { FileSizePipe } from './pipes/file-size.pipe'
import { FilterPipe } from './pipes/filter.pipe'
import { DocumentTitlePipe } from './pipes/document-title.pipe'
import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component'
import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component'
import { NgSelectModule } from '@ng-select/ng-select'
import { NumberComponent } from './components/common/input/number/number.component'
import { SafeUrlPipe } from './pipes/safeurl.pipe'
import { SafeHtmlPipe } from './pipes/safehtml.pipe'
import { CustomDatePipe } from './pipes/custom-date.pipe'
import { DateComponent } from './components/common/input/date/date.component'
import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter'
import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter'
import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'
import { ColorSliderModule } from 'ngx-color/slider'
import { ColorComponent } from './components/common/input/color/color.component'
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
import localeBe from '@angular/common/locales/be'
import localeCs from '@angular/common/locales/cs'
import localeDa from '@angular/common/locales/da'
import localeDe from '@angular/common/locales/de'
import localeEnGb from '@angular/common/locales/en-GB'
import localeEs from '@angular/common/locales/es'
import localeFr from '@angular/common/locales/fr'
import localeIt from '@angular/common/locales/it'
import localeLb from '@angular/common/locales/lb'
import localeNl from '@angular/common/locales/nl'
import localePl from '@angular/common/locales/pl'
import localePt from '@angular/common/locales/pt'
import localeRo from '@angular/common/locales/ro'
import localeRu from '@angular/common/locales/ru'
import localeSl from '@angular/common/locales/sl'
import localeSr from '@angular/common/locales/sr'
import localeSv from '@angular/common/locales/sv'
import localeTr from '@angular/common/locales/tr'
import localeZh from '@angular/common/locales/zh'
registerLocaleData(localeBe)
registerLocaleData(localeCs)
registerLocaleData(localeDa)
registerLocaleData(localeDe)
@@ -91,11 +99,15 @@ registerLocaleData(localeIt)
registerLocaleData(localeLb)
registerLocaleData(localeNl)
registerLocaleData(localePl)
registerLocaleData(localePt, "pt-BR")
registerLocaleData(localePt, "pt-PT")
registerLocaleData(localePt, 'pt-BR')
registerLocaleData(localePt, 'pt-PT')
registerLocaleData(localeRo)
registerLocaleData(localeRu)
registerLocaleData(localeSl)
registerLocaleData(localeSr)
registerLocaleData(localeSv)
registerLocaleData(localeTr)
registerLocaleData(localeZh)
@NgModule({
declarations: [
@@ -104,8 +116,8 @@ registerLocaleData(localeSv)
DocumentDetailComponent,
DashboardComponent,
TagListComponent,
CorrespondentListComponent,
DocumentTypeListComponent,
CorrespondentListComponent,
LogsComponent,
SettingsComponent,
NotFoundComponent,
@@ -142,11 +154,12 @@ registerLocaleData(localeSv)
MetadataCollapseComponent,
SelectDialogComponent,
NumberComponent,
SafePipe,
SafeUrlPipe,
SafeHtmlPipe,
CustomDatePipe,
DateComponent,
ColorComponent,
DocumentAsnComponent
DocumentAsnComponent,
],
imports: [
BrowserModule,
@@ -156,27 +169,28 @@ registerLocaleData(localeSv)
FormsModule,
ReactiveFormsModule,
NgxFileDropModule,
InfiniteScrollModule,
PdfViewerModule,
NgSelectModule,
ColorSliderModule
ColorSliderModule,
],
providers: [
DatePipe,
CookieService, {
CookieService,
{
provide: HTTP_INTERCEPTORS,
useClass: CsrfInterceptor,
multi: true
},{
multi: true,
},
{
provide: HTTP_INTERCEPTORS,
useClass: ApiVersionInterceptor,
multi: true
multi: true,
},
FilterPipe,
DocumentTitlePipe,
{provide: NgbDateAdapter, useClass: ISODateTimeAdapter},
{provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter}
{ provide: NgbDateAdapter, useClass: ISODateTimeAdapter },
{ provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter },
],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
})
export class AppModule { }
export class AppModule {}

View File

@@ -62,7 +62,7 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="documents" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" (click)="closeMenu()">
<a class="nav-link" routerLink="documents" routerLinkActive="active" (click)="closeMenu()">
<svg class="sidebaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#files"/>
</svg>&nbsp;<ng-container i18n>Documents</ng-container>
@@ -92,7 +92,7 @@
<svg class="sidebaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#file-text"/>
</svg>&nbsp;{{d.title | documentTitle}}
<span class="close bg-light" (click)="closeDocument(d); $event.preventDefault()">
<span class="close" (click)="closeDocument(d); $event.preventDefault()">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
<use xlink:href="assets/bootstrap-icons.svg#x"/>
</svg>
@@ -169,7 +169,7 @@
</li>
<li class="nav-item">
<div class="d-flex w-100 flex-wrap">
<a class="nav-link pe-0 pb-0" target="_blank" rel="noopener noreferrer" href="https://github.com/paperless-ngx/paperless-ngx">
<a class="nav-link pe-2 pb-1" target="_blank" rel="noopener noreferrer" href="https://github.com/paperless-ngx/paperless-ngx">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="sidebaricon bi bi-github" viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
</svg>&nbsp;<ng-container i18n>GitHub</ng-container>

View File

@@ -35,16 +35,14 @@
.sidebar .nav-link {
font-weight: 500;
color: #333;
}
.sidebar .nav-link .sidebaricon {
margin-right: 4px;
color: #999;
}
.sidebar .nav-link.active {
color: $primary;
color: var(--bs-primary);
font-weight: bold;
}
@@ -172,8 +170,7 @@
}
&:focus {
background-color: #fff;
color: #212529;
background-color: rgba(0, 0, 0, 0.3);
flex-grow: 1;
padding-left: 0.5rem;
}

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppFrameComponent } from './app-frame.component';
describe('AppFrameComponent', () => {
let component: AppFrameComponent;
let fixture: ComponentFixture<AppFrameComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AppFrameComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AppFrameComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,26 +1,31 @@
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ActivatedRoute, Router, Params } from '@angular/router';
import { from, Observable, Subscription, BehaviorSubject } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, switchMap, first } from 'rxjs/operators';
import { PaperlessDocument } from 'src/app/data/paperless-document';
import { OpenDocumentsService } from 'src/app/services/open-documents.service';
import { SavedViewService } from 'src/app/services/rest/saved-view.service';
import { SearchService } from 'src/app/services/rest/search.service';
import { environment } from 'src/environments/environment';
import { DocumentDetailComponent } from '../document-detail/document-detail.component';
import { Meta } from '@angular/platform-browser';
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type';
import { Component } from '@angular/core'
import { FormControl } from '@angular/forms'
import { ActivatedRoute, Router, Params } from '@angular/router'
import { from, Observable, Subscription, BehaviorSubject } from 'rxjs'
import {
debounceTime,
distinctUntilChanged,
map,
switchMap,
first,
} from 'rxjs/operators'
import { PaperlessDocument } from 'src/app/data/paperless-document'
import { OpenDocumentsService } from 'src/app/services/open-documents.service'
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
import { SearchService } from 'src/app/services/rest/search.service'
import { environment } from 'src/environments/environment'
import { DocumentDetailComponent } from '../document-detail/document-detail.component'
import { Meta } from '@angular/platform-browser'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type'
@Component({
selector: 'app-app-frame',
templateUrl: './app-frame.component.html',
styleUrls: ['./app-frame.component.scss']
styleUrls: ['./app-frame.component.scss'],
})
export class AppFrameComponent {
constructor (
constructor(
public router: Router,
private activatedRoute: ActivatedRoute,
private openDocumentsService: OpenDocumentsService,
@@ -28,7 +33,7 @@ export class AppFrameComponent {
public savedViewService: SavedViewService,
private list: DocumentListViewService,
private meta: Meta
) { }
) {}
versionString = `${environment.appTitle} ${environment.version}`
@@ -48,14 +53,14 @@ export class AppFrameComponent {
text$.pipe(
debounceTime(200),
distinctUntilChanged(),
map(term => {
map((term) => {
if (term.lastIndexOf(' ') != -1) {
return term.substring(term.lastIndexOf(' ') + 1)
} else {
return term
}
}),
switchMap(term =>
switchMap((term) =>
term.length < 2 ? from([[]]) : this.searchService.autocomplete(term)
)
)
@@ -66,49 +71,63 @@ export class AppFrameComponent {
let lastSpaceIndex = currentSearch.lastIndexOf(' ')
if (lastSpaceIndex != -1) {
currentSearch = currentSearch.substring(0, lastSpaceIndex + 1)
currentSearch += event.item + " "
currentSearch += event.item + ' '
} else {
currentSearch = event.item + " "
currentSearch = event.item + ' '
}
this.searchField.patchValue(currentSearch)
}
search() {
this.closeMenu()
this.list.quickFilter([{rule_type: FILTER_FULLTEXT_QUERY, value: this.searchField.value}])
this.list.quickFilter([
{
rule_type: FILTER_FULLTEXT_QUERY,
value: (this.searchField.value as string).trim(),
},
])
}
closeDocument(d: PaperlessDocument) {
this.openDocumentsService.closeDocument(d).pipe(first()).subscribe(confirmed => {
if (confirmed) {
this.closeMenu()
let route = this.activatedRoute.snapshot
while (route.firstChild) {
route = route.firstChild
this.openDocumentsService
.closeDocument(d)
.pipe(first())
.subscribe((confirmed) => {
if (confirmed) {
this.closeMenu()
let route = this.activatedRoute.snapshot
while (route.firstChild) {
route = route.firstChild
}
if (
route.component == DocumentDetailComponent &&
route.params['id'] == d.id
) {
this.router.navigate([''])
}
}
if (route.component == DocumentDetailComponent && route.params['id'] == d.id) {
this.router.navigate([""])
}
}
})
})
}
closeAll() {
// user may need to confirm losing unsaved changes
this.openDocumentsService.closeAll().pipe(first()).subscribe(confirmed => {
if (confirmed) {
this.closeMenu()
this.openDocumentsService
.closeAll()
.pipe(first())
.subscribe((confirmed) => {
if (confirmed) {
this.closeMenu()
// TODO: is there a better way to do this?
let route = this.activatedRoute
while (route.firstChild) {
route = route.firstChild
// TODO: is there a better way to do this?
let route = this.activatedRoute
while (route.firstChild) {
route = route.firstChild
}
if (route.component === DocumentDetailComponent) {
this.router.navigate([''])
}
}
if (route.component === DocumentDetailComponent) {
this.router.navigate([""])
}
}
})
})
}
get displayName() {
@@ -123,5 +142,4 @@ export class AppFrameComponent {
return null
}
}
}

View File

@@ -8,9 +8,12 @@
<p *ngIf="message">{{message}}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancel()" [disabled]="!buttonsEnabled" i18n>Cancel</button>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()" [disabled]="!buttonsEnabled" i18n>
<span class="d-inline-block" style="padding-bottom: 1px;" >Cancel</span>
</button>
<button type="button" class="btn" [class]="btnClass" (click)="confirm()" [disabled]="!confirmButtonEnabled || !buttonsEnabled">
{{btnCaption}}
<span *ngIf="!confirmButtonEnabled"> ({{seconds}})</span>
<ngb-progressbar *ngIf="!confirmButtonEnabled" style="height: 1px;" type="dark" [max]="secondsTotal" [value]="seconds"></ngb-progressbar>
<span class="visually-hidden">{{ seconds | number: '1.0-0' }} seconds</span>
</button>
</div>

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfirmDialogComponent } from './confirm-dialog.component';
describe('ConfirmDialogComponent', () => {
let component: ConfirmDialogComponent;
let fixture: ComponentFixture<ConfirmDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ConfirmDialogComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ConfirmDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,15 +1,14 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { Subject } from 'rxjs';
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { interval, Subject, switchMap, take } from 'rxjs'
@Component({
selector: 'app-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.scss']
styleUrls: ['./confirm-dialog.component.scss'],
})
export class ConfirmDialogComponent {
constructor(public activeModal: NgbActiveModal) { }
constructor(public activeModal: NgbActiveModal) {}
@Output()
public confirmClicked = new EventEmitter()
@@ -24,7 +23,7 @@ export class ConfirmDialogComponent {
message
@Input()
btnClass = "btn-primary"
btnClass = 'btn-primary'
@Input()
btnCaption = $localize`Confirm`
@@ -34,19 +33,28 @@ export class ConfirmDialogComponent {
confirmButtonEnabled = true
seconds = 0
secondsTotal = 0
confirmSubject: Subject<boolean>
delayConfirm(seconds: number) {
this.confirmButtonEnabled = false
const refreshInterval = 0.15 // s
this.secondsTotal = seconds
this.seconds = seconds
setTimeout(() => {
if (this.seconds <= 1) {
this.confirmButtonEnabled = true
} else {
this.delayConfirm(seconds - 1)
}
}, 1000)
interval(refreshInterval * 1000)
.pipe(
take(this.secondsTotal / refreshInterval + 2) // need 2 more for animation to complete after 0
)
.subscribe((count) => {
this.seconds = Math.max(
0,
this.secondsTotal - refreshInterval * (count + 1)
)
this.confirmButtonEnabled =
this.secondsTotal - refreshInterval * count < 0
})
}
cancel() {

View File

@@ -20,8 +20,8 @@
</div>
<div class="input-group input-group-sm">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()"
[(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker">
<button class="btn btn-outline-secondary" (click)="dateAfterPicker.toggle()" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
@@ -43,8 +43,8 @@
</div>
<div class="input-group input-group-sm">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()"
[(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker">
<button class="btn btn-outline-secondary" (click)="dateBeforePicker.toggle()" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DateDropdownComponent } from './date-dropdown.component';
describe('DateDropdownComponent', () => {
let component: DateDropdownComponent;
let fixture: ComponentFixture<DateDropdownComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DateDropdownComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DateDropdownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,10 +1,17 @@
import { formatDate } from '@angular/common';
import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core';
import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { Subject, Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { SettingsService } from 'src/app/services/settings.service';
import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter';
import { formatDate } from '@angular/common'
import {
Component,
EventEmitter,
Input,
Output,
OnInit,
OnDestroy,
} from '@angular/core'
import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'
import { Subject, Subscription } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
import { SettingsService } from 'src/app/services/settings.service'
import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'
export interface DateSelection {
before?: string
@@ -20,21 +27,18 @@ const LAST_YEAR = 3
selector: 'app-date-dropdown',
templateUrl: './date-dropdown.component.html',
styleUrls: ['./date-dropdown.component.scss'],
providers: [
{provide: NgbDateAdapter, useClass: ISODateAdapter},
]
providers: [{ provide: NgbDateAdapter, useClass: ISODateAdapter }],
})
export class DateDropdownComponent implements OnInit, OnDestroy {
constructor(settings: SettingsService) {
this.datePlaceHolder = settings.getLocalizedDateInputFormat()
}
quickFilters = [
{id: LAST_7_DAYS, name: $localize`Last 7 days`},
{id: LAST_MONTH, name: $localize`Last month`},
{id: LAST_3_MONTHS, name: $localize`Last 3 months`},
{id: LAST_YEAR, name: $localize`Last year`}
{ id: LAST_7_DAYS, name: $localize`Last 7 days` },
{ id: LAST_MONTH, name: $localize`Last month` },
{ id: LAST_3_MONTHS, name: $localize`Last 3 months` },
{ id: LAST_YEAR, name: $localize`Last year` },
]
datePlaceHolder: string
@@ -62,9 +66,7 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
private sub: Subscription
ngOnInit() {
this.sub = this.datesSetDebounce$.pipe(
debounceTime(400)
).subscribe(() => {
this.sub = this.datesSetDebounce$.pipe(debounceTime(400)).subscribe(() => {
this.onChange()
})
}
@@ -81,11 +83,11 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
switch (qf) {
case LAST_7_DAYS:
date.setDate(date.getDate() - 7)
break;
break
case LAST_MONTH:
date.setMonth(date.getMonth() - 1)
break;
break
case LAST_3_MONTHS:
date.setMonth(date.getMonth() - 3)
@@ -94,20 +96,22 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
case LAST_YEAR:
date.setFullYear(date.getFullYear() - 1)
break
}
this.dateAfter = formatDate(date, 'yyyy-MM-dd', "en-us", "UTC")
}
this.dateAfter = formatDate(date, 'yyyy-MM-dd', 'en-us', 'UTC')
this.onChange()
}
onChange() {
this.dateAfterChange.emit(this.dateAfter)
this.dateBeforeChange.emit(this.dateBefore)
this.datesSet.emit({after: this.dateAfter, before: this.dateBefore})
this.datesSet.emit({ after: this.dateAfter, before: this.dateBefore })
}
onChangeDebounce() {
this.datesSetDebounce$.next({after: this.dateAfter, before: this.dateBefore})
this.datesSetDebounce$.next({
after: this.dateAfter,
before: this.dateBefore,
})
}
clearBefore() {
@@ -120,4 +124,10 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
this.onChange()
}
// prevent chars other than numbers and separators
onKeyPress(event: KeyboardEvent) {
if ('Enter' !== event.key && !/[0-9,\.\/-]+/.test(event.key)) {
event.preventDefault()
}
}
}

View File

@@ -11,7 +11,7 @@
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></app-input-check>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
<button type="submit" class="btn btn-primary" i18n [disabled]="networkActive">Save</button>
</div>
</form>

View File

@@ -1,19 +1,22 @@
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component';
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
import { CorrespondentService } from 'src/app/services/rest/correspondent.service';
import { ToastService } from 'src/app/services/toast.service';
import { Component } from '@angular/core'
import { FormControl, FormGroup } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
import { ToastService } from 'src/app/services/toast.service'
@Component({
selector: 'app-correspondent-edit-dialog',
templateUrl: './correspondent-edit-dialog.component.html',
styleUrls: ['./correspondent-edit-dialog.component.scss']
styleUrls: ['./correspondent-edit-dialog.component.scss'],
})
export class CorrespondentEditDialogComponent extends EditDialogComponent<PaperlessCorrespondent> {
constructor(service: CorrespondentService, activeModal: NgbActiveModal, toastService: ToastService) {
constructor(
service: CorrespondentService,
activeModal: NgbActiveModal,
toastService: ToastService
) {
super(service, activeModal, toastService)
}
@@ -29,9 +32,8 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl
return new FormGroup({
name: new FormControl(''),
matching_algorithm: new FormControl(1),
match: new FormControl(""),
is_insensitive: new FormControl(true)
match: new FormControl(''),
is_insensitive: new FormControl(true),
})
}
}

View File

@@ -13,7 +13,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
<button type="submit" class="btn btn-primary" i18n [disabled]="networkActive">Save</button>
</div>
</form>

View File

@@ -1,19 +1,22 @@
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component';
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
import { DocumentTypeService } from 'src/app/services/rest/document-type.service';
import { ToastService } from 'src/app/services/toast.service';
import { Component } from '@angular/core'
import { FormControl, FormGroup } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { ToastService } from 'src/app/services/toast.service'
@Component({
selector: 'app-document-type-edit-dialog',
templateUrl: './document-type-edit-dialog.component.html',
styleUrls: ['./document-type-edit-dialog.component.scss']
styleUrls: ['./document-type-edit-dialog.component.scss'],
})
export class DocumentTypeEditDialogComponent extends EditDialogComponent<PaperlessDocumentType> {
constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) {
constructor(
service: DocumentTypeService,
activeModal: NgbActiveModal,
toastService: ToastService
) {
super(service, activeModal, toastService)
}
@@ -29,9 +32,8 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent<Paperle
return new FormGroup({
name: new FormControl(''),
matching_algorithm: new FormControl(1),
match: new FormControl(""),
is_insensitive: new FormControl(true)
match: new FormControl(''),
is_insensitive: new FormControl(true),
})
}
}

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EditDialogComponent } from './edit-dialog.component';
describe('EditDialogComponent', () => {
let component: EditDialogComponent;
let fixture: ComponentFixture<EditDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ EditDialogComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(EditDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,20 +1,22 @@
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model';
import { ObjectWithId } from 'src/app/data/object-with-id';
import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service';
import { ToastService } from 'src/app/services/toast.service';
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { FormGroup } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'
import { ObjectWithId } from 'src/app/data/object-with-id'
import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'
import { ToastService } from 'src/app/services/toast.service'
@Directive()
export abstract class EditDialogComponent<T extends ObjectWithId> implements OnInit {
export abstract class EditDialogComponent<T extends ObjectWithId>
implements OnInit
{
constructor(
private service: AbstractPaperlessService<T>,
private activeModal: NgbActiveModal,
private toastService: ToastService) { }
private toastService: ToastService
) {}
@Input()
dialogMode: string = 'create'
@@ -43,7 +45,7 @@ export abstract class EditDialogComponent<T extends ObjectWithId> implements OnI
// wait to enable close button so it doesnt steal focus from input since its the first clickable element in the DOM
setTimeout(() => {
this.closeEnabled = true
});
})
}
getCreateTitle() {
@@ -65,7 +67,7 @@ export abstract class EditDialogComponent<T extends ObjectWithId> implements OnI
case 'edit':
return this.getEditTitle()
default:
break;
break
}
}
@@ -78,25 +80,31 @@ export abstract class EditDialogComponent<T extends ObjectWithId> implements OnI
}
save() {
var newObject = Object.assign(Object.assign({}, this.object), this.objectForm.value)
var newObject = Object.assign(
Object.assign({}, this.object),
this.objectForm.value
)
var serverResponse: Observable<T>
switch (this.dialogMode) {
case 'create':
serverResponse = this.service.create(newObject)
break;
break
case 'edit':
serverResponse = this.service.update(newObject)
default:
break;
break
}
this.networkActive = true
serverResponse.subscribe(result => {
this.activeModal.close()
this.success.emit(result)
}, error => {
this.error = error.error
this.networkActive = false
})
serverResponse.subscribe(
(result) => {
this.activeModal.close()
this.success.emit(result)
},
(error) => {
this.error = error.error
this.networkActive = false
}
)
}
cancel() {

View File

@@ -15,7 +15,7 @@
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
<button type="submit" class="btn btn-primary" i18n [disabled]="networkActive">Save</button>
</div>
</form>

View File

@@ -0,0 +1,42 @@
import { Component } from '@angular/core'
import { FormControl, FormGroup } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { PaperlessTag } from 'src/app/data/paperless-tag'
import { TagService } from 'src/app/services/rest/tag.service'
import { ToastService } from 'src/app/services/toast.service'
import { randomColor } from 'src/app/utils/color'
@Component({
selector: 'app-tag-edit-dialog',
templateUrl: './tag-edit-dialog.component.html',
styleUrls: ['./tag-edit-dialog.component.scss'],
})
export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> {
constructor(
service: TagService,
activeModal: NgbActiveModal,
toastService: ToastService
) {
super(service, activeModal, toastService)
}
getCreateTitle() {
return $localize`Create new tag`
}
getEditTitle() {
return $localize`Edit tag`
}
getForm(): FormGroup {
return new FormGroup({
name: new FormControl(''),
color: new FormControl(randomColor()),
is_inbox_tag: new FormControl(false),
matching_algorithm: new FormControl(1),
match: new FormControl(''),
is_insensitive: new FormControl(true),
})
}
}

View File

@@ -6,7 +6,7 @@
<div class="d-none d-sm-inline">&nbsp;{{title}}</div>
<ng-container *ngIf="!editing && selectionModel.selectionSize() > 0">
<div *ngIf="multiple" class="position-absolute top-0 start-100 translate-middle badge bg-secondary border border-light text-light rounded-pill">
{{selectionModel.selectionSize()}}<span class="visually-hidden">selected</span>
{{selectionModel.totalCount}}<span class="visually-hidden">selected</span>
</div>
<div *ngIf="!multiple" class="position-absolute top-0 start-100 p-2 translate-middle badge bg-secondary border border-light rounded-circle">
<span class="visually-hidden">selected</span>
@@ -18,10 +18,10 @@
<div *ngIf="!editing && multiple" class="list-group-item d-flex">
<div class="btn-group btn-group-xs btn-group-toggle flex-fill" ngbRadioGroup [(ngModel)]="selectionModel.logicalOperator" (change)="selectionModel.toggleOperator()" [disabled]="!operatorToggleEnabled">
<label ngbButtonLabel class="btn btn-outline-primary">
<input ngbButton type="radio" class="btn-check" name="logicalOperator" value="and"> All
<input ngbButton type="radio" class="btn-check" name="logicalOperator" value="and" i18n> All
</label>
<label ngbButtonLabel class="btn btn-outline-primary">
<input ngbButton type="radio" class="btn-check" name="logicalOperator" value="or"> Any
<input ngbButton type="radio" class="btn-check" name="logicalOperator" value="or" i18n> Any
</label>
</div>
</div>

View File

@@ -42,7 +42,7 @@
filter: brightness(0.5);
&.active {
background-color: lighten($primary, 30%);
background-color: var(--ngx-primary-lighten-30);
}
}
@@ -60,4 +60,4 @@ small > svg {
.show .btn-outline-primary {
color: #fff;
}
}

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FilterableDropodownComponent } from './filterable-dropdown.component';
describe('FilterableDropodownComponent', () => {
let component: FilterableDropodownComponent;
let fixture: ComponentFixture<FilterableDropodownComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterableDropodownComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterableDropodownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,17 +1,23 @@
import { Component, EventEmitter, Input, Output, ElementRef, ViewChild } from '@angular/core';
import { FilterPipe } from 'src/app/pipes/filter.pipe';
import {
Component,
EventEmitter,
Input,
Output,
ElementRef,
ViewChild,
} from '@angular/core'
import { FilterPipe } from 'src/app/pipes/filter.pipe'
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
import { ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component';
import { MatchingModel } from 'src/app/data/matching-model';
import { Subject } from 'rxjs';
import { ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component'
import { MatchingModel } from 'src/app/data/matching-model'
import { Subject } from 'rxjs'
export interface ChangedItems {
itemsToAdd: MatchingModel[],
itemsToAdd: MatchingModel[]
itemsToRemove: MatchingModel[]
}
export class FilterableDropdownSelectionModel {
changed = new Subject<FilterableDropdownSelectionModel>()
multiple = false
@@ -22,14 +28,20 @@ export class FilterableDropdownSelectionModel {
get itemsSorted(): MatchingModel[] {
// TODO: this is getting called very often
return this.items.sort((a,b) => {
return this.items.sort((a, b) => {
if (a.id == null && b.id != null) {
return -1
} else if (a.id != null && b.id == null) {
return 1
} else if (this.getNonTemporary(a.id) == ToggleableItemState.NotSelected && this.getNonTemporary(b.id) != ToggleableItemState.NotSelected) {
} else if (
this.getNonTemporary(a.id) == ToggleableItemState.NotSelected &&
this.getNonTemporary(b.id) != ToggleableItemState.NotSelected
) {
return 1
} else if (this.getNonTemporary(a.id) != ToggleableItemState.NotSelected && this.getNonTemporary(b.id) == ToggleableItemState.NotSelected) {
} else if (
this.getNonTemporary(a.id) != ToggleableItemState.NotSelected &&
this.getNonTemporary(b.id) == ToggleableItemState.NotSelected
) {
return -1
} else {
return a.name.localeCompare(b.name)
@@ -42,11 +54,17 @@ export class FilterableDropdownSelectionModel {
private temporarySelectionStates = new Map<number, ToggleableItemState>()
getSelectedItems() {
return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected)
return this.items.filter(
(i) =>
this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected
)
}
getExcludedItems() {
return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded)
return this.items.filter(
(i) =>
this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded
)
}
set(id: number, state: ToggleableItemState, fireEvent = true) {
@@ -62,9 +80,16 @@ export class FilterableDropdownSelectionModel {
toggle(id: number, fireEvent = true) {
let state = this.temporarySelectionStates.get(id)
if (state == null || (state != ToggleableItemState.Selected && state != ToggleableItemState.Excluded)) {
if (
state == null ||
(state != ToggleableItemState.Selected &&
state != ToggleableItemState.Excluded)
) {
this.temporarySelectionStates.set(id, ToggleableItemState.Selected)
} else if (state == ToggleableItemState.Selected || state == ToggleableItemState.Excluded) {
} else if (
state == ToggleableItemState.Selected ||
state == ToggleableItemState.Excluded
) {
this.temporarySelectionStates.delete(id)
}
@@ -91,7 +116,7 @@ export class FilterableDropdownSelectionModel {
}
}
exclude(id: number, fireEvent:boolean = true) {
exclude(id: number, fireEvent: boolean = true) {
let state = this.temporarySelectionStates.get(id)
if (state == null || state != ToggleableItemState.Excluded) {
this.temporarySelectionStates.set(id, ToggleableItemState.Excluded)
@@ -130,13 +155,19 @@ export class FilterableDropdownSelectionModel {
}
get(id: number) {
return this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected
return (
this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected
)
}
selectionSize() {
return this.getSelectedItems().length
}
get totalCount() {
return this.getSelectedItems().length + this.getExcludedItems().length
}
clear(fireEvent = true) {
this.temporarySelectionStates.clear()
this.temporaryLogicalOperator = this._logicalOperator = 'and'
@@ -146,9 +177,19 @@ export class FilterableDropdownSelectionModel {
}
isDirty() {
if (!Array.from(this.temporarySelectionStates.keys()).every(id => this.temporarySelectionStates.get(id) == this.selectionStates.get(id))) {
if (
!Array.from(this.temporarySelectionStates.keys()).every(
(id) =>
this.temporarySelectionStates.get(id) == this.selectionStates.get(id)
)
) {
return true
} else if (!Array.from(this.selectionStates.keys()).every(id => this.selectionStates.get(id) == this.temporarySelectionStates.get(id))) {
} else if (
!Array.from(this.selectionStates.keys()).every(
(id) =>
this.selectionStates.get(id) == this.temporarySelectionStates.get(id)
)
) {
return true
} else if (this.temporaryLogicalOperator !== this._logicalOperator) {
return true
@@ -158,7 +199,10 @@ export class FilterableDropdownSelectionModel {
}
isNoneSelected() {
return this.selectionSize() == 1 && this.get(null) == ToggleableItemState.Selected
return (
this.selectionSize() == 1 &&
this.get(null) == ToggleableItemState.Selected
)
}
init(map) {
@@ -183,8 +227,17 @@ export class FilterableDropdownSelectionModel {
diff(): ChangedItems {
return {
itemsToAdd: this.items.filter(item => this.temporarySelectionStates.get(item.id) == ToggleableItemState.Selected && this.selectionStates.get(item.id) != ToggleableItemState.Selected),
itemsToRemove: this.items.filter(item => !this.temporarySelectionStates.has(item.id) && this.selectionStates.has(item.id)),
itemsToAdd: this.items.filter(
(item) =>
this.temporarySelectionStates.get(item.id) ==
ToggleableItemState.Selected &&
this.selectionStates.get(item.id) != ToggleableItemState.Selected
),
itemsToRemove: this.items.filter(
(item) =>
!this.temporarySelectionStates.has(item.id) &&
this.selectionStates.has(item.id)
),
}
}
}
@@ -192,10 +245,9 @@ export class FilterableDropdownSelectionModel {
@Component({
selector: 'app-filterable-dropdown',
templateUrl: './filterable-dropdown.component.html',
styleUrls: ['./filterable-dropdown.component.scss']
styleUrls: ['./filterable-dropdown.component.scss'],
})
export class FilterableDropdownComponent {
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
@ViewChild('dropdown') dropdown: NgbDropdown
@@ -207,7 +259,7 @@ export class FilterableDropdownComponent {
this._selectionModel.items = Array.from(items)
this._selectionModel.items.unshift({
name: $localize`:Filter drop down element to filter for documents with no correspondent/type/tag assigned:Not assigned`,
id: null
id: null,
})
}
}
@@ -225,7 +277,7 @@ export class FilterableDropdownComponent {
model.items = this.selectionModel.items
model.multiple = this.selectionModel.multiple
}
model.changed.subscribe(updatedModel => {
model.changed.subscribe((updatedModel) => {
this.selectionModelChange.next(updatedModel)
})
this._selectionModel = model
@@ -251,7 +303,7 @@ export class FilterableDropdownComponent {
title: string
@Input()
filterPlaceholder: string = ""
filterPlaceholder: string = ''
@Input()
icon: string
@@ -272,14 +324,17 @@ export class FilterableDropdownComponent {
open = new EventEmitter()
get operatorToggleEnabled(): boolean {
return this.selectionModel.selectionSize() > 1 && this.selectionModel.getExcludedItems().length == 0
return (
this.selectionModel.selectionSize() > 1 &&
this.selectionModel.getExcludedItems().length == 0
)
}
modelIsDirty: boolean = false
constructor(private filterPipe: FilterPipe) {
this.selectionModel = new FilterableDropdownSelectionModel()
this.selectionModelChange.subscribe(updatedModel => {
this.selectionModelChange.subscribe((updatedModel) => {
this.modelIsDirty = updatedModel.isDirty()
})
}
@@ -296,12 +351,12 @@ export class FilterableDropdownComponent {
dropdownOpenChange(open: boolean): void {
if (open) {
setTimeout(() => {
this.listFilterTextInput.nativeElement.focus();
this.listFilterTextInput.nativeElement.focus()
}, 0)
if (this.editing) {
this.selectionModel.reset()
}
this.open.next()
this.open.next(this)
} else {
this.filterText = ''
if (this.applyOnClose && this.selectionModel.isDirty()) {

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ToggleableDropdownButtonComponent } from './toggleable-dropdown-button.component';
describe('ToggleableDropdownButtonComponent', () => {
let component: ToggleableDropdownButtonComponent;
let fixture: ComponentFixture<ToggleableDropdownButtonComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ToggleableDropdownButtonComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ToggleableDropdownButtonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,20 +1,19 @@
import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
import { MatchingModel } from 'src/app/data/matching-model';
import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core'
import { MatchingModel } from 'src/app/data/matching-model'
export enum ToggleableItemState {
NotSelected = 0,
Selected = 1,
PartiallySelected = 2,
Excluded = 3
Excluded = 3,
}
@Component({
selector: 'app-toggleable-dropdown-button',
templateUrl: './toggleable-dropdown-button.component.html',
styleUrls: ['./toggleable-dropdown-button.component.scss']
styleUrls: ['./toggleable-dropdown-button.component.scss'],
})
export class ToggleableDropdownButtonComponent {
@Input()
item: MatchingModel

Some files were not shown because too many files have changed in this diff Show More