diff --git a/.travis.yml b/.travis.yml index 10f2a4d73..248eebb64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,39 @@ language: python -python: - - "3.6" - - "3.7" - - "3.8" +jobs: + include: + - name: "Paperless on Python 3.6" + python: "3.6" + + - name: "Paperless on Python 3.7" + python: "3.7" + + - name: "Paperless on Python 3.8" + python: "3.8" + + - name: "Documentation" + script: + - cd docs/ + - make html + after_success: true + + - name: "Front end" + language: node_js + node_js: + - 15 + before_install: true + install: + - cd src-ui/ + - npm install -g @angular/cli + - npm install + script: + - ng build --prod + after_success: true + before_install: - sudo apt-get update -qq - - sudo apt-get install -qq libpoppler-cpp-dev unpaper tesseract-ocr + - sudo apt-get install -qq libpoppler-cpp-dev unpaper tesseract-ocr imagemagick ghostscript install: - pip install --upgrade pipenv diff --git a/Pipfile b/Pipfile index 66d60845b..ad60e0905 100644 --- a/Pipfile +++ b/Pipfile @@ -9,43 +9,43 @@ verify_ssl = true name = "piwheels" [packages] -django = "~=3.1" -pillow = "*" -dateparser = "~=0.7" +dateparser = "~=0.7.6" +django = "~=3.1.3" django-cors-headers = "*" -djangorestframework = "~=3.12" -python-gnupg = "*" -python-dotenv = "*" -filemagic = "*" -pyocr = "~=0.7" +django-extensions = "*" +django-filter = "~=2.4.0" +django-q = "~=1.3.4" +djangorestframework = "~=3.12.2" +fuzzywuzzy = "*" +gunicorn = "*" +imap-tools = "*" langdetect = "*" pdftotext = "*" -django-filter = "~=2.4" -python-dateutil = "*" -psycopg2-binary = "*" -scikit-learn="~=0.23" -whoosh="~=2.7" -gunicorn = "*" -whitenoise = "~=5.2" -fuzzywuzzy = "*" -python-Levenshtein = "*" -django-extensions = "*" -watchdog = "*" pathvalidate = "*" -django-q = "*" +pillow = "*" +pyocr = "~=0.7.2" +python-gnupg = "*" +python-dotenv = "*" +python-dateutil = "*" +python-Levenshtein = "*" +python-magic = "*" +psycopg2-binary = "*" redis = "*" -imap-tools = "*" +scikit-learn="~=0.23.2" +whitenoise = "~=5.2.0" +watchdog = "*" +whoosh="~=2.7.4" [dev-packages] coveralls = "*" factory-boy = "*" -sphinx = "~=3.3" -tox = "*" pycodestyle = "*" pytest = "*" pytest-cov = "*" pytest-django = "*" -pytest-sugar = "*" pytest-env = "*" +pytest-sugar = "*" pytest-xdist = "*" +sphinx = "~=3.3" sphinx_rtd_theme = "*" +tox = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 15a30e1c0..6ecca3c34 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "abc7e5f5a8d075d4b013ceafd06ca07f57e597f053d670f73449ba210511b114" + "sha256": "ae2643b9cf0cf5741ae149fb6bc0c480de41329ce48e773eb4b5d760bc5e2244" }, "pipfile-spec": 6, "requires": {}, @@ -105,14 +105,6 @@ "index": "pypi", "version": "==3.12.2" }, - "filemagic": { - "hashes": [ - "sha256:b2fd77411975510e28673220c4b8868ed81b5eb5906339b6f4c233b32122d7d3", - "sha256:e684359ef40820fe406f0ebc5bf8a78f89717bdb7fed688af68082d991d6dbf3" - ], - "index": "pypi", - "version": "==1.6" - }, "fuzzywuzzy": { "hashes": [ "sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8", @@ -131,11 +123,11 @@ }, "imap-tools": { "hashes": [ - "sha256:070929b8ec429c0aad94588a37a2962eed656a119ab61dcf91489f20fe983f5d", - "sha256:6232cd43748741496446871e889eb137351fc7a7e7f4c7888cd8c0fa28e20cda" + "sha256:96e9a4ff6483462635737730a1df28e739faa71967b12a84f4363fb386542246", + "sha256:a3ee1827dc4ff185b259b33d0238b091a87d489f63ee59959fcc81716456c602" ], "index": "pypi", - "version": "==0.31.0" + "version": "==0.32.0" }, "joblib": { "hashes": [ @@ -337,6 +329,14 @@ "index": "pypi", "version": "==0.12.0" }, + "python-magic": { + "hashes": [ + "sha256:356efa93c8899047d1eb7d3eb91e871ba2f5b1376edbaf4cc305e3c872207355", + "sha256:b757db2a5289ea3f1ced9e60f072965243ea43a2221430048fd8cacab17be0ce" + ], + "index": "pypi", + "version": "==0.4.18" + }, "pytz": { "hashes": [ "sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268", @@ -617,11 +617,11 @@ }, "coveralls": { "hashes": [ - "sha256:4430b862baabb3cf090d36d84d331966615e4288d8a8c5957e0fd456d0dd8bd6", - "sha256:b3b60c17b03a0dee61952a91aed6f131e0b2ac8bd5da909389c53137811409e1" + "sha256:2301a19500b06649d2ec4f2858f9c69638d7699a4c63027c5d53daba666147cc", + "sha256:b990ba1f7bc4288e63340be0433698c1efe8217f78c689d254c2540af3d38617" ], "index": "pypi", - "version": "==2.1.2" + "version": "==2.2.0" }, "distlib": { "hashes": [ @@ -663,11 +663,11 @@ }, "faker": { "hashes": [ - "sha256:4d038ba51ae5e0a956d79cadd684d856e5750bfd608b61dad1807f8f08b1da49", - "sha256:f260f0375a44cd1e1a735c9b8c9b914304f607b5eef431d20e098c7c2f5b50a6" + "sha256:3f5d379e4b5ce92a8afe3c2ce59d7c43886370dd3bf9495a936b91888debfc81", + "sha256:8c0e8a06acef4b9312902e2ce18becabe62badd3a6632180bd0680c6ee111473" ], "markers": "python_version >= '3.5'", - "version": "==4.16.0" + "version": "==4.17.0" }, "filelock": { "hashes": [ diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index c6e0d1cab..dfa7cfc65 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -15,8 +15,42 @@ map_uidgid() { fi } + +wait_for_postgres() { + attempt_num=1 + max_attempts=5 + + echo "Waiting for PostgreSQL to start..." + + host="${PAPERLESS_DBHOST}" + + while !` - This features will most likely be removed in future versions. - +* Moved documentation of the settings VG271UP * **Added:** New frontend. Features: * Single page application: It's much more responsive than the django admin pages. diff --git a/docs/configuration.rst b/docs/configuration.rst index 1ddd7ca0e..afb0b5f90 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -184,6 +184,16 @@ PAPERLESS_TIME_ZONE= +PAPERLESS_OCR_PAGES= + Tells paperless to use only the specified amount of pages for OCR. Documents + with less than the specified amount of pages get OCR'ed completely. + + Specifying 1 here will only use the first page. + + Defaults to 0, which disables this feature and always uses all pages. + + + PAPERLESS_OCR_LANGUAGE= Customize the default language that tesseract will attempt to use when parsing documents. The default language is used whenever diff --git a/docs/faq.rst b/docs/faq.rst index 747ffaf53..ea05544a6 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -21,6 +21,17 @@ is files around manually. This folder is meant to be entirely managed by docker and paperless. +**Q:** *What file types does paperless-ng support?* + +**A:** Currently, the following files are supported: + +* PDF documents, PNG images and JPEG images are processed with OCR. +* Plain text documents are supported as well and are added verbatim + to paperless. + +Paperless determines the type of a file by inspecting its content. The +file extensions do not matter. + **Q:** *Will paperless-ng run on Raspberry Pi?* **A:** The short answer is yes. I've tested it on a Raspberry Pi 3 B. @@ -32,21 +43,8 @@ in your browser and paperless has to do much less work to serve the data. .. note:: - Consider setting ``PAPERLESS_OPTIMIZE_THUMBNAILS`` to false to speed up - the consumption process. This takes quite a bit of time on Raspberry Pi. - -.. note:: - - Updating the :ref:`automatic matching algorithm ` - takes quite a bit of time. However, the update mechanism checks if your - data has changed before doing the heavy lifting. If you experience the - algorithm taking too much cpu time, consider changing the schedule in the - admin interface to daily or weekly. You can also manually invoke the task - by changing the date and time of the next run to today/now. - - The actual matching of the algorithm is fast and works on Raspberry Pi as - well as on any other device. - + You can adjust some of the settings so that paperless uses less processing + power. See :ref:`setup-less_powerful_devices` for details. **Q:** *How do I install paperless-ng on Raspberry Pi?* diff --git a/docs/index.rst b/docs/index.rst index 756fee3b1..a9142a682 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -44,6 +44,9 @@ resources in the documentation: that's fully tested and production ready. * See :ref:`this note ` about GnuPG encryption in paperless-ng. +* Paperless is now integrated with a + :ref:`task processing queue ` that tells you + at a glance when and why something is not working. * The :ref:`changelog ` contains a detailed list of all changes in paperless-ng. diff --git a/docs/screenshots.rst b/docs/screenshots.rst index 9fbd55634..2dcb2b601 100644 --- a/docs/screenshots.rst +++ b/docs/screenshots.rst @@ -42,7 +42,8 @@ Fancy mail filters! .. image:: _static/paperless-11-mail-filters.png -Mobile support in the future? This doesn't really work yet. +Mobile support in the future? This kinda works, however some layouts are still +too wide. .. image:: _static/paperless-10-mobile.png diff --git a/docs/setup.rst b/docs/setup.rst index 71acfba42..a43b03aaa 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -10,10 +10,10 @@ Go to the project page on GitHub and download the `latest release `_. There are multiple options available. -* Download the docker-compose files if you want to pull paperless from +* Download the dockerfiles archive if you want to pull paperless from Docker Hub. -* Download the archive and extract it if you want to build the docker image +* Download the dist archive and extract it if you want to build the docker image yourself or want to install paperless without docker. .. hint:: @@ -22,6 +22,15 @@ There are multiple options available. is not to pull the entire git repository. Paperless-ng includes artifacts that need to be compiled, and that's already done for you in the release. +.. admonition:: Want to try out paperless-ng before migrating? + + The release contains a file ``.env`` which sets the docker-compose project + name to "paperless", which is the same as before and instructs docker-compose + to reuse and upgrade your paperless volumes. + + Just rename the project name in that file to anything else and docker-compose + will create fresh volumes for you! + Overview of Paperless-ng ######################## @@ -57,6 +66,8 @@ Paperless consists of the following components: $ cd /path/to/paperless/src/ $ pipenv run python3 manage.py document_consumer + .. _setup-task_processor: + * **The task processor:** Paperless relies on `Django Q `_ for doing much of the heavy lifting. This is a task queue that accepts tasks from multiple sources and processes tasks in parallel. It also comes with a scheduler that executes @@ -77,7 +88,8 @@ Paperless consists of the following components: a modern multicore system, consumption with full ocr is blazing fast. The task processor comes with a built-in admin interface that you can use to see whenever any of the - tasks fail and inspect the errors. + tasks fail and inspect the errors (i.e., wrong email credentials, errors during consuming a specific + file, etc). You may start the task processor by executing: @@ -240,15 +252,21 @@ Migration to paperless-ng is then performed in a few simple steps: .. caution:: - Make sure you also download the ``.env`` file. This will set the - project name for docker compose to ``paperless`` and then it will - automatically reuse your existing paperless volumes. + The release include a ``.env`` file. This will set the + project name for docker compose to ``paperless`` so that paperless-ng will + automatically reuse your existing paperless volumes. When you start it, it + will migrate your existing data. After that, your old paperless installation + will be incompatible with the migrated volumes. -4. Adjust ``docker-compose.yml`` and +4. Copy the ``docker-compose.sqlite.yml`` file to ``docker-compose.yml``. + If you want to migrate to PostgreSQL, do that after you migrated your existing + SQLite database. + +5. Adjust ``docker-compose.yml`` and ``docker-compose.env`` to your needs. - See `docker route`_ for details on which edits are required. + See `docker route`_ for details on which edits are advised. -5. Start paperless-ng. +6. Start paperless-ng. .. code:: bash @@ -264,19 +282,122 @@ Migration to paperless-ng is then performed in a few simple steps: This will run paperless in the background and automatically start it on system boot. -6. Paperless installed a permanent redirect to ``admin/`` in your browser. This +7. Paperless installed a permanent redirect to ``admin/`` in your browser. This redirect is still in place and prevents access to the new UI. Clear - everything related to paperless in your browsers data in order to fix - this issue. + browsing cache in order to fix this. + +8. Optionally, follow the instructions below to migrate your existing data to PostgreSQL. .. _setup-sqlite_to_psql: -Moving data from sqlite to postgresql +Moving data from SQLite to PostgreSQL ===================================== -.. warning:: +Moving your data from SQLite to PostgreSQL is done via executing a series of django +management commands as below. + +.. caution:: + + Make sure that your sqlite database is migrated to the latest version. + Starting paperless will make sure that this is the case. If your try to + load data from an old database schema in SQLite into a newer database + schema in PostgreSQL, you will run into trouble. + +1. Stop paperless, if it is running. +2. Tell paperless to use PostgreSQL: + + a) With docker, copy the provided ``docker-compose.postgres.yml`` file to + ``docker-compose.yml``. Remember to adjust the consumption directory, + if necessary. + b) Without docker, configure the database in your ``paperless.conf`` file. + See :ref:`configuration` for details. + +3. Open a shell and initialize the database: + + a) With docker, run the following command to open a shell within the paperless + container: + + .. code:: shell-session + + $ cd /path/to/paperless + $ docker-compose run --rm webserver /bin/bash + + This will lauch the container and initialize the PostgreSQL database. + + b) Without docker, open a shell in your virtual environment, switch to + the ``src`` directory and create the database schema: + + .. code:: shell-session + + $ cd /path/to/paperless + $ pipenv shell + $ cd src + $ python3 manage.py migrate + + This will not copy any data yet. + +4. Dump your data from SQLite: + + .. code:: shell-session + + $ python3 manage.py dumpdata --database=sqlite --exclude=contenttypes --exclude=auth.Permission > data.json + +5. Load your data into PostgreSQL: + + .. code:: shell-session + + $ python3 manage.py loaddata data.json + +6. Exit the shell. + + .. code:: shell-session + + $ exit + +7. Start paperless. + + +.. _setup-less_powerful_devices: + + +Considerations for less powerful devices +######################################## + +Paperless runs on Raspberry Pi. However, some things are rather slow on the Pi and +configuring some options in paperless can help improve performance immensely: + +* Consider setting ``PAPERLESS_OCR_PAGES`` to 1, so that paperless will only OCR + the first page of your documents. +* ``PAPERLESS_TASK_WORKERS`` and ``PAPERLESS_THREADS_PER_WORKER`` are configured + to use all cores. The Raspberry Pi models 3 and up have 4 cores, meaning that + paperless will use 2 workers and 2 threads per worker. This may result in + slugish response times during consumption, so you might want to lower these + settings (example: 2 workers and 1 thread to always have some computing power + left for other tasks). +* Keep ``PAPERLESS_OCR_ALWAYS`` at its default value 'false' and consider OCR'ing + your documents before feeding them into paperless. Some scanners are able to + do this! +* Lower ``PAPERLESS_CONVERT_DENSITY`` from its default value 300 to 200. This + will still result in rather accurate OCR, but will decrease consumption time + by quite a bit. +* Set ``PAPERLESS_OPTIMIZE_THUMBNAILS`` to 'false' if you want faster consumption + times. Thumbnails will be about 20% larger. + +For details, refer to :ref:`configuration`. + +.. note:: + + Updating the :ref:`automatic matching algorithm ` + takes quite a bit of time. However, the update mechanism checks if your + data has changed before doing the heavy lifting. If you experience the + algorithm taking too much cpu time, consider changing the schedule in the + admin interface to daily. You can also manually invoke the task + by changing the date and time of the next run to today/now. + + The actual matching of the algorithm is fast and works on Raspberry Pi as + well as on any other device. + - TBD. .. _redis: https://redis.io/ diff --git a/paperless.conf.example b/paperless.conf.example index e1fd17a77..4749151e7 100644 --- a/paperless.conf.example +++ b/paperless.conf.example @@ -35,6 +35,7 @@ #PAPERLESS_TASK_WORKERS=1 #PAPERLESS_THREADS_PER_WORKER=1 #PAPERLESS_TIME_ZONE=UTC +#PAPERLESS_OCR_PAGES=1 #PAPERLESS_OCR_LANGUAGE=eng #PAPERLESS_OCR_ALWAYS=false #PAPERLESS_CONSUMER_POLLING=10 diff --git a/scripts/make-release.sh b/scripts/make-release.sh index ef3e5769b..06548748b 100755 --- a/scripts/make-release.sh +++ b/scripts/make-release.sh @@ -17,6 +17,7 @@ PAPERLESS_ROOT=$(git rev-parse --show-toplevel) # output directory PAPERLESS_DIST="$PAPERLESS_ROOT/dist" PAPERLESS_DIST_APP="$PAPERLESS_DIST/paperless-ng" +PAPERLESS_DIST_DOCKERFILES="$PAPERLESS_DIST/paperless-ng-dockerfiles" if [ -d "$PAPERLESS_DIST" ] then @@ -27,6 +28,7 @@ fi mkdir "$PAPERLESS_DIST" mkdir "$PAPERLESS_DIST_APP" mkdir "$PAPERLESS_DIST_APP/docker" +mkdir "$PAPERLESS_DIST_DOCKERFILES" # setup dependencies. @@ -78,9 +80,9 @@ cp "$PAPERLESS_ROOT/docker/local/"* "$PAPERLESS_DIST_APP" cp "$PAPERLESS_ROOT/docker/docker-compose.env" "$PAPERLESS_DIST_APP" # docker files for pulling from docker hub -cp "$PAPERLESS_ROOT/docker/hub/"* "$PAPERLESS_DIST" -cp "$PAPERLESS_ROOT/.env" "$PAPERLESS_DIST" -cp "$PAPERLESS_ROOT/docker/docker-compose.env" "$PAPERLESS_DIST" +cp "$PAPERLESS_ROOT/docker/hub/"* "$PAPERLESS_DIST_DOCKERFILES" +cp "$PAPERLESS_ROOT/.env" "$PAPERLESS_DIST_DOCKERFILES" +cp "$PAPERLESS_ROOT/docker/docker-compose.env" "$PAPERLESS_DIST_DOCKERFILES" # auxiliary files required for the docker image cp "$PAPERLESS_ROOT/docker/docker-entrypoint.sh" "$PAPERLESS_DIST_APP/docker/" @@ -99,3 +101,4 @@ docker build . -t "jonaswinkler/paperless-ng:$VERSION" cd "$PAPERLESS_DIST" tar -cJf "paperless-ng-$VERSION.tar.xz" paperless-ng/ +tar -cJf "paperless-ng-$VERSION-dockerfiles.tar.xz" paperless-ng-dockerfiles/ diff --git a/src-ui/angular.json b/src-ui/angular.json index aca54b8e0..2ff1bb3b0 100644 --- a/src-ui/angular.json +++ b/src-ui/angular.json @@ -1,126 +1,130 @@ { - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "paperless-ui": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/paperless-ui", - "outputHashing": "none", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": true, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "node_modules/bootstrap/dist/css/bootstrap.min.css", - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "none", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "paperless-ui:build" - }, - "configurations": { - "production": { - "browserTarget": "paperless-ui:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "paperless-ui:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "paperless-ui:serve" - }, - "configurations": { - "production": { - "devServerTarget": "paperless-ui:serve:production" - } - } - } - } - }}, - "defaultProject": "paperless-ui" -} + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "paperless-ui": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/paperless-ui", + "outputHashing": "none", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "aot": true, + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "none", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb", + "maximumError": "10kb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "paperless-ui:build" + }, + "configurations": { + "production": { + "browserTarget": "paperless-ui:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "paperless-ui:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.scss" + ], + "scripts": [] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "tsconfig.app.json", + "tsconfig.spec.json", + "e2e/tsconfig.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "paperless-ui:serve" + }, + "configurations": { + "production": { + "devServerTarget": "paperless-ui:serve:production" + } + } + } + } + } + }, + "defaultProject": "paperless-ui" +} \ No newline at end of file diff --git a/data/.keep b/src-ui/src/app/app.component.scss similarity index 100% rename from data/.keep rename to src-ui/src/app/app.component.scss diff --git a/src-ui/src/app/app.component.ts b/src-ui/src/app/app.component.ts index a6cd8bebe..84c173a18 100644 --- a/src-ui/src/app/app.component.ts +++ b/src-ui/src/app/app.component.ts @@ -3,7 +3,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] + styleUrls: ['./app.component.scss'] }) export class AppComponent { diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts index 014279cc5..3ccb1c5f1 100644 --- a/src-ui/src/app/app.module.ts +++ b/src-ui/src/app/app.module.ts @@ -41,6 +41,10 @@ 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'; @NgModule({ declarations: [ @@ -74,7 +78,11 @@ import { CsrfInterceptor } from './interceptors/csrf.interceptor'; SaveViewConfigDialogComponent, DateTimeComponent, TagsComponent, - SortableDirective + SortableDirective, + SavedViewWidgetComponent, + StatisticsWidgetComponent, + UploadFileWidgetComponent, + WidgetFrameComponent ], imports: [ BrowserModule, 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 519b69bf0..3f326afdd 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,32 +1,26 @@ -