diff --git a/Pipfile b/Pipfile index 48759307c..f6301b98f 100644 --- a/Pipfile +++ b/Pipfile @@ -42,6 +42,7 @@ whoosh="~=2.7.4" inotifyrecursive = "~=0.3.4" ocrmypdf = "*" tqdm = "*" +tika = "*" [dev-packages] coveralls = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 1cfccb8ff..c6621b543 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3d576f289958226a7583e4c471c7f8c11bff6933bf093185f623cfb381a92412" + "sha256": "993e362c31af6b8094693075f614270a820cf0b557369d66d674e1a107b7bd31" }, "pipfile-spec": 6, "requires": { @@ -44,6 +44,13 @@ ], "version": "==1.17.12" }, + "certifi": { + "hashes": [ + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" + ], + "version": "==2020.12.5" + }, "cffi": { "hashes": [ "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", @@ -229,6 +236,15 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==9.0" }, + "idna": { + "hashes": [ + "sha256:4a57a6379512ade94fa99e2fa46d3cd0f2f553040548d0e2958c6ed90ee48226", + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, "imap-tools": { "hashes": [ "sha256:72bf46dc135b039a5d5b59f4e079242ac15eac02a30038e8cb2dec7b153cab65", @@ -683,6 +699,14 @@ ], "version": "==3.5.56" }, + "requests": { + "hashes": [ + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.25.1" + }, "scikit-learn": { "hashes": [ "sha256:090bbf144fd5823c1f2efa3e1a9bf180295b24294ca8f478e75b40ed54f8036e", @@ -769,6 +793,14 @@ "markers": "python_version >= '3.5'", "version": "==2.1.0" }, + "tika": { + "hashes": [ + "sha256:c2c50f405622f74531841104f9e85c17511aede11de8e5385eab1a29a31f191b", + "sha256:d1f2eddb93caa9a2857569486aa2bc0320d0bf1796cdbe03066954cbc4b4bf62" + ], + "index": "pypi", + "version": "==1.24" + }, "tqdm": { "hashes": [ "sha256:38b658a3e4ecf9b4f6f8ff75ca16221ae3378b2e175d846b6b33ea3a20852cf5", @@ -777,6 +809,15 @@ "index": "pypi", "version": "==4.54.1" }, + "typing-extensions": { + "hashes": [ + "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", + "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", + "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" + ], + "markers": "python_version < '3.8'", + "version": "==3.7.4.3" + }, "tzlocal": { "hashes": [ "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44", @@ -784,6 +825,14 @@ ], "version": "==2.1" }, + "urllib3": { + "hashes": [ + "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", + "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.2" + }, "watchdog": { "hashes": [ "sha256:3caefdcc8f06a57fdc5ef2d22aa7c0bfda4f55e71a0bee74cbf3176d97536ef3", @@ -1197,11 +1246,11 @@ }, "requests": { "hashes": [ - "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8", - "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998" + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.25.0" + "version": "==2.25.1" }, "six": { "hashes": [ diff --git a/docker/hub/docker-compose.tika.yml b/docker/hub/docker-compose.tika.yml new file mode 100644 index 000000000..af8f575a0 --- /dev/null +++ b/docker/hub/docker-compose.tika.yml @@ -0,0 +1,43 @@ +version: "3.4" +services: + broker: + image: redis:6.0 + restart: always + + webserver: + image: jonaswinkler/paperless-ng:0.9.9 + restart: always + depends_on: + - broker + 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: apache/tika + restart: unless-stopped + +volumes: + data: + media: diff --git a/docker/local/docker-compose.tika.yml b/docker/local/docker-compose.tika.yml new file mode 100644 index 000000000..889713908 --- /dev/null +++ b/docker/local/docker-compose.tika.yml @@ -0,0 +1,43 @@ +version: "3.4" +services: + broker: + image: redis:6.0 + restart: always + + webserver: + build: . + restart: always + depends_on: + - broker + 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: apache/tika + restart: unless-stopped + +volumes: + data: + media: diff --git a/docs/configuration.rst b/docs/configuration.rst index 5ccb80b3a..49c95bff1 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -277,6 +277,35 @@ PAPERLESS_OCR_USER_ARG= {"deskew": true, "optimize": 3, "unpaper_args": "--pre-rotate 90"} +.. _configuration-tika: + +Tika settings +############# + +Paperless can make use of `Tika `_ and +`Gotenberg `_ for parsing and +converting "Office" documents (such as ".doc", ".xlsx" and ".odt"). If you +wish to use this, you must provide a Tika server and a Gotenberg server, +configure their endpoints, and enable the feature. + +If you run paperless on docker, you can add those services to the docker-compose +file (see the examples provided). + +PAPERLESS_TIKA_ENABLED= + Enable (or disable) the Tika parser. + + Defaults to false. + +PAPERLESS_TIKA_ENDPOINT= + Set the endpoint URL were Paperless can reach your Tika server. + + Defaults to "http://localhost:9998". + +PAPERLESS_TIKA_GOTENBERG_ENDPOINT= + Set the endpoint URL were Paperless can reach your Gotenberg server. + + Defaults to "http://localhost:3000". + Software tweaks ############### diff --git a/scripts/start_services.sh b/scripts/start_services.sh index e566f59b3..cbab7ac9e 100755 --- a/scripts/start_services.sh +++ b/scripts/start_services.sh @@ -1,2 +1,4 @@ docker run -p 5432:5432 -v paperless_pgdata:/var/lib/postgresql/data -d postgres:13 docker run -d -p 6379:6379 redis:latest +docker run -p 3000:3000 -d thecodingmachine/gotenberg +docker run -p 9998:9998 -d apache/tika diff --git a/src-ui/angular.json b/src-ui/angular.json index 66bd81779..3c2dfcc38 100644 --- a/src-ui/angular.json +++ b/src-ui/angular.json @@ -34,7 +34,11 @@ "assets": [ "src/favicon.ico", "src/assets", - "src/manifest.webmanifest" + "src/manifest.webmanifest", { + "glob": "pdf.worker.min.js", + "input": "node_modules/pdfjs-dist/build/", + "output": "/assets/js/" + } ], "styles": [ "src/styles.scss" diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf index 5f12c504c..a0c94de3e 100644 --- a/src-ui/messages.xlf +++ b/src-ui/messages.xlf @@ -377,7 +377,7 @@ Do you really want to delete the tag ""? src/app/components/manage/tag-list/tag-list.component.ts - 31 + 28 @@ -440,7 +440,7 @@ Do you really want to delete the document type ""? src/app/components/manage/document-type-list/document-type-list.component.ts - 26 + 24 @@ -468,21 +468,21 @@ Saved view " deleted. src/app/components/manage/settings/settings.component.ts - 52 + 54 Settings saved successfully. src/app/components/manage/settings/settings.component.ts - 61 + 74 Error while storing settings on server: src/app/components/manage/settings/settings.component.ts - 73 + 86 @@ -496,11 +496,11 @@ Saved views src/app/components/manage/settings/settings.component.html - 41 + 56 - - Document list + + Appearance src/app/components/manage/settings/settings.component.html 13 @@ -513,60 +513,74 @@ 17 + + Dark mode + + src/app/components/manage/settings/settings.component.html + 33 + + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 36 + + Bulk editing src/app/components/manage/settings/settings.component.html - 33 + 44 Show confirmation dialogs src/app/components/manage/settings/settings.component.html - 35 + 48 Deleting documents will always ask for confirmation. src/app/components/manage/settings/settings.component.html - 35 + 48 Apply on close src/app/components/manage/settings/settings.component.html - 36 + 49 Appears on src/app/components/manage/settings/settings.component.html - 53 + 68 Show on dashboard src/app/components/manage/settings/settings.component.html - 56 + 71 Show in sidebar src/app/components/manage/settings/settings.component.html - 60 + 75 No saved views defined. src/app/components/manage/settings/settings.component.html - 70 + 85 @@ -580,7 +594,7 @@ Do you really want to delete the correspondent ""? src/app/components/manage/correspondent-list/correspondent-list.component.ts - 26 + 24 @@ -639,8 +653,8 @@ 11 - - Match + + Matching pattern src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html 12 @@ -776,26 +790,33 @@ Paperless-ng src/app/components/app-frame/app-frame.component.html - 4 + 11 app title - - Search for documents + + Search documents src/app/components/app-frame/app-frame.component.html - 12 - - - - Manage - - src/app/components/app-frame/app-frame.component.html - 77 + 15 Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + + + Manage src/app/components/app-frame/app-frame.component.html 112 @@ -805,70 +826,91 @@ Admin src/app/components/app-frame/app-frame.component.html - 119 + 147 Misc src/app/components/app-frame/app-frame.component.html - 125 + 153 Documentation src/app/components/app-frame/app-frame.component.html - 132 + 160 GitHub src/app/components/app-frame/app-frame.component.html - 139 + 167 - - Logout + + Logged in as src/app/components/app-frame/app-frame.component.html - 146 + 34 Open documents src/app/components/app-frame/app-frame.component.html - 57 + 92 Close all src/app/components/app-frame/app-frame.component.html - 71 + 106 Correspondent: src/app/components/document-list/filter-editor/filter-editor.component.ts - 28 + 29 + + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 31 Type: src/app/components/document-list/filter-editor/filter-editor.component.ts - 31 + 36 + + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 38 Tag: src/app/components/document-list/filter-editor/filter-editor.component.ts - 34 + 42 + + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 @@ -910,7 +952,7 @@ Not assigned src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts - 145 + 161 Filter drop down element to filter for documents with no correspondent/type/tag assigned @@ -1561,22 +1603,43 @@ 97 - - Any + + Any word src/app/data/matching-model.ts 12 - - All + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + + + All words src/app/data/matching-model.ts 13 - - Literal + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + + + Exact match + + src/app/data/matching-model.ts + 14 + + + + Exact: Document contains this string src/app/data/matching-model.ts 14 @@ -1589,15 +1652,29 @@ 15 - - Fuzzy match + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + + + Fuzzy word src/app/data/matching-model.ts 16 - - Auto + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + + + Auto: Learn matching automatically src/app/data/matching-model.ts 17 diff --git a/src-ui/src/app/app.component.ts b/src-ui/src/app/app.component.ts index 84c173a18..73c5fc861 100644 --- a/src-ui/src/app/app.component.ts +++ b/src-ui/src/app/app.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { SettingsService } from './services/settings.service'; @Component({ selector: 'app-root', @@ -6,9 +7,11 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.scss'] }) export class AppComponent { - - constructor () { + + constructor (private settings: SettingsService) { + let anyWindow = (window as any) + anyWindow.pdfWorkerSrc = '/assets/js/pdf.worker.min.js'; + this.settings.updateDarkModeSettings() } - } diff --git a/src-ui/src/app/components/app-frame/app-frame.component.html b/src-ui/src/app/components/app-frame/app-frame.component.html index d191ec0de..42273ca3a 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.html +++ b/src-ui/src/app/components/app-frame/app-frame.component.html @@ -1,17 +1,52 @@ diff --git a/src-ui/src/app/components/app-frame/app-frame.component.scss b/src-ui/src/app/components/app-frame/app-frame.component.scss index 5ace8a2ff..6809875eb 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.scss +++ b/src-ui/src/app/components/app-frame/app-frame.component.scss @@ -1,36 +1,30 @@ - @import "/src/theme"; - - /* +/* * Sidebar */ - - .sidebar { +.sidebar { position: fixed; top: 0; bottom: 0; left: 0; z-index: 100; /* Behind the navbar */ - padding: 48px 0 0; /* Height of navbar */ + padding: 50px 0 0; /* Height of navbar */ box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); } - @media (max-width: 767.98px) { .sidebar { - top: 3rem; + top: 3.5rem; } } .sidebar-sticky { position: relative; top: 0; - /* height: calc(100vh - 48px); */ height: 100%; - padding-top: .5rem; + padding-top: 0.5rem; overflow-x: hidden; overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ } - @supports ((position: -webkit-sticky) or (position: sticky)) { .sidebar-sticky { position: -webkit-sticky; @@ -53,36 +47,85 @@ font-weight: bold; } -.sidebar .nav-link:hover .sidebaricon, -.sidebar .nav-link.active .sidebaricon { +.sidebar .nav-link.active .sidebaricon, +.sidebar .nav-link:hover .sidebaricon { color: inherit; } .sidebar-heading { - font-size: .75rem; + font-size: 0.75rem; text-transform: uppercase; } - /* * Navbar */ - .navbar-brand { - padding-top: .75rem; - padding-bottom: .75rem; +.navbar-brand { + padding-top: 0.75rem; + padding-bottom: 0.75rem; font-size: 1rem; - background-color: rgba(0, 0, 0, .25); - box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); } -.navbar .navbar-toggler { - top: .25rem; - right: 1rem; +.dropdown.show .dropdown-toggle, +.dropdown-toggle:hover { + opacity: 0.7; } -.navbar .form-control { - padding: .75rem 1rem; - border-width: 0; - border-radius: 0; +.dropdown-toggle::after { + margin-left: 0.4em; + vertical-align: 0.155em; +} + +.navbar .dropdown-menu { + font-size: 0.875rem; // body size + + a svg { + opacity: 0.6; + } +} + +.navbar .search-form-container { + max-width: 550px; + + form { + position: relative; + } + + svg { + position: absolute; + left: 0.6rem; + color: rgba(255, 255, 255, 0.6); + } + + &:focus-within { + svg { + display: none; + } + + .form-control::placeholder { + color: rgba(255, 255, 255, 0); + } + } + + .form-control { + color: rgba(255, 255, 255, 0.3); + background-color: rgba(0, 0, 0, 0.15); + padding-left: 1.8rem; + border-color: rgba(255, 255, 255, 0.2); + transition: flex 0.3s ease; + max-width: 600px; + min-width: 300px; // 1/2 max + + &::placeholder { + color: rgba(255, 255, 255, 0.4); + } + + &:focus { + background-color: #fff; + color: #212529; + flex-grow: 1; + padding-left: 0.5rem; + } + } } diff --git a/src-ui/src/app/components/app-frame/app-frame.component.ts b/src-ui/src/app/components/app-frame/app-frame.component.ts index c4c00843d..ad4460f16 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.ts +++ b/src-ui/src/app/components/app-frame/app-frame.component.ts @@ -9,7 +9,8 @@ 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'; + @Component({ selector: 'app-app-frame', templateUrl: './app-frame.component.html', @@ -22,8 +23,10 @@ export class AppFrameComponent implements OnInit, OnDestroy { private activatedRoute: ActivatedRoute, private openDocumentsService: OpenDocumentsService, private searchService: SearchService, - public savedViewService: SavedViewService + public savedViewService: SavedViewService, + private meta: Meta ) { + } versionString = `${environment.appTitle} ${environment.version}` @@ -55,7 +58,7 @@ export class AppFrameComponent implements OnInit, OnDestroy { term.length < 2 ? from([[]]) : this.searchService.autocomplete(term) ) ) - + itemSelected(event) { event.preventDefault() let currentSearch: string = this.searchField.value @@ -98,4 +101,17 @@ export class AppFrameComponent implements OnInit, OnDestroy { } } + get displayName() { + // TODO: taken from dashboard component, is this the best way to pass around username? + let tagFullName = this.meta.getTag('name=full_name') + let tagUsername = this.meta.getTag('name=username') + if (tagFullName && tagFullName.content) { + return tagFullName.content + } else if (tagUsername && tagUsername.content) { + return tagUsername.content + } else { + return null + } + } + } diff --git a/src-ui/src/app/components/dashboard/dashboard.component.html b/src-ui/src/app/components/dashboard/dashboard.component.html index 5b76dd242..50bd44a4e 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.html +++ b/src-ui/src/app/components/dashboard/dashboard.component.html @@ -1,5 +1,8 @@ - +
diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.scss b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.scss index e69de29bb..40d1c836b 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.scss +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.scss @@ -0,0 +1,7 @@ +table { + overflow-wrap: anywhere; +} + +th:first-child { + min-width: 5rem; +} diff --git a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.html b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.html index e8fda1d0b..ac42860c9 100644 --- a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.html +++ b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.html @@ -16,7 +16,7 @@ {{m.prefix}}:{{m.key}} - {{m.value}} + {{m.value}} diff --git a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.scss b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.scss index e69de29bb..b946da146 100644 --- a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.scss +++ b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.scss @@ -0,0 +1,3 @@ +.metadata-column { + overflow-wrap: anywhere; +} \ No newline at end of file diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html index c1757eb35..56047fc1e 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html @@ -1,7 +1,7 @@ -
+
-
- +
+
@@ -12,7 +12,7 @@
-
+
@@ -55,16 +55,16 @@  Download - +
Score: - + Created: {{document.created | date}}
- +
diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss index eb744d2af..0b1604d90 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss @@ -30,10 +30,6 @@ border-color: $primary; } -.doc-img-background { - background-color: white; -} - .doc-img-background-selected { background-color: $primaryFaded; -} \ No newline at end of file +} diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html index f6128e077..83ba8c274 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html @@ -1,7 +1,7 @@
-
- +
+
diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts index 4b62d6a51..b160ae073 100644 --- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts +++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts @@ -25,13 +25,26 @@ export class FilterEditorComponent implements OnInit, OnDestroy { switch(this.filterRules[0].rule_type) { case FILTER_CORRESPONDENT: - return $localize`Correspondent: ${this.correspondents.find(c => c.id == +rule.value)?.name}` + if (rule.value) { + return $localize`Correspondent: ${this.correspondents.find(c => c.id == +rule.value)?.name}` + } else { + return $localize`Without correspondent` + } case FILTER_DOCUMENT_TYPE: - return $localize`Type: ${this.documentTypes.find(dt => dt.id == +rule.value)?.name}` + if (rule.value) { + return $localize`Type: ${this.documentTypes.find(dt => dt.id == +rule.value)?.name}` + } else { + return $localize`Without document type` + } case FILTER_HAS_TAG: return $localize`Tag: ${this.tags.find(t => t.id == +rule.value)?.name}` + + case FILTER_HAS_ANY_TAG: + if (rule.value == "false") { + return $localize`Without any tag` + } } } diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html b/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html index e35c57e26..fd6b01de9 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html +++ b/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html @@ -9,7 +9,7 @@ - +
diff --git a/src-ui/src/app/components/manage/generic-list/generic-list.component.ts b/src-ui/src/app/components/manage/generic-list/generic-list.component.ts index 1f9cc65f9..b31231bc8 100644 --- a/src-ui/src/app/components/manage/generic-list/generic-list.component.ts +++ b/src-ui/src/app/components/manage/generic-list/generic-list.component.ts @@ -30,7 +30,7 @@ export abstract class GenericListComponent implements On if (o.matching_algorithm == MATCH_AUTO) { return $localize`Automatic` } else if (o.match && o.match.length > 0) { - return `${o.match} (${MATCHING_ALGORITHMS.find(a => a.id == o.matching_algorithm).name})` + return `${MATCHING_ALGORITHMS.find(a => a.id == o.matching_algorithm).shortName}: ${o.match}` } else { return "-" } diff --git a/src-ui/src/app/components/manage/settings/settings.component.html b/src-ui/src/app/components/manage/settings/settings.component.html index 1f5374dba..93c7c98b4 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.html +++ b/src-ui/src/app/components/manage/settings/settings.component.html @@ -10,30 +10,45 @@ General settings -

Document list

- +

Appearance

+
Items per page
- + - -
- +
-

Bulk editing

+
+
+ Dark mode +
+
+ +
+ + +
+
+
- - +

Bulk editing

+ +
+
+ + +
+
@@ -42,7 +57,7 @@
- +
@@ -68,7 +83,7 @@
No saved views defined.
- +
@@ -78,4 +93,4 @@
- \ No newline at end of file + diff --git a/src-ui/src/app/components/manage/settings/settings.component.ts b/src-ui/src/app/components/manage/settings/settings.component.ts index c26c63384..0b0646157 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.ts +++ b/src-ui/src/app/components/manage/settings/settings.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Renderer2 } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; import { DocumentListViewService } from 'src/app/services/document-list-view.service'; @@ -19,9 +19,13 @@ export class SettingsComponent implements OnInit { 'bulkEditConfirmationDialogs': new FormControl(this.settings.get(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS)), 'bulkEditApplyOnClose': new FormControl(this.settings.get(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE)), 'documentListItemPerPage': new FormControl(this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)), + 'darkModeUseSystem': new FormControl(this.settings.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM)), + 'darkModeEnabled': new FormControl(this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED)), 'savedViews': this.savedViewGroup }) + savedViews: PaperlessSavedView[] + constructor( public savedViewService: SavedViewService, private documentListViewService: DocumentListViewService, @@ -29,8 +33,6 @@ export class SettingsComponent implements OnInit { private settings: SettingsService ) { } - savedViews: PaperlessSavedView[] - ngOnInit() { this.savedViewService.listAll().subscribe(r => { this.savedViews = r.results @@ -53,11 +55,22 @@ export class SettingsComponent implements OnInit { }) } + toggleDarkModeSetting() { + if (this.settingsForm.value.darkModeUseSystem) { + (this.settingsForm.controls.darkModeEnabled as FormControl).disable() + } else { + (this.settingsForm.controls.darkModeEnabled as FormControl).enable() + } + } + private saveLocalSettings() { this.settings.set(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, this.settingsForm.value.bulkEditApplyOnClose) this.settings.set(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, this.settingsForm.value.bulkEditConfirmationDialogs) this.settings.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, this.settingsForm.value.documentListItemPerPage) + this.settings.set(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem) + this.settings.set(SETTINGS_KEYS.DARK_MODE_ENABLED, (this.settingsForm.value.darkModeEnabled == true).toString()) this.documentListViewService.updatePageSize() + this.settings.updateDarkModeSettings() this.toastService.showInfo($localize`Settings saved successfully.`) } diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html index bbb96fb6b..7efaac4b9 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html +++ b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html @@ -20,7 +20,7 @@ - +