Merge pull request #1341 from eikek/docs/website-update
Docs/website update
							
								
								
									
										2
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,6 +1,8 @@ | |||||||
| name: CI | name: CI | ||||||
| on: | on: | ||||||
|   pull_request: |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - master | ||||||
| jobs: | jobs: | ||||||
|   ci-matrix: |   ci-matrix: | ||||||
|     runs-on: ubuntu-20.04 |     runs-on: ubuntu-20.04 | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/website.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -17,7 +17,7 @@ jobs: | |||||||
|           elm-version: 0.19.1 |           elm-version: 0.19.1 | ||||||
|       - uses: cachix/install-nix-action@v16 |       - uses: cachix/install-nix-action@v16 | ||||||
|         with: |         with: | ||||||
|           nix_path: nixpkgs=channel:nixos-20.09 |           nix_path: nixpkgs=channel:nixos-21.11 | ||||||
|       - name: Print nixpkgs version |       - name: Print nixpkgs version | ||||||
|         run: nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version' |         run: nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version' | ||||||
|       - name: Build website (${{ env.DOCSPELL_VERSION }}) |       - name: Build website (${{ env.DOCSPELL_VERSION }}) | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -7,10 +7,14 @@ elm-stuff | |||||||
| result | result | ||||||
| _site/ | _site/ | ||||||
| *.qcow2 | *.qcow2 | ||||||
| /website/site/content/docs/changelog/ | /website/site/content/docs/install/changelog.md | ||||||
| /website/site/public/ | /website/site/public/ | ||||||
| /website/site/static/openapi/ | /website/site/static/openapi/ | ||||||
| /website/site/static/js/bundle.js | /website/site/static/js/bundle.js | ||||||
|  | /website/site/static/styles.css | ||||||
|  | /website/site/static/syntax-*.css | ||||||
|  | /website/site/static/webfonts/ | ||||||
|  | /website/site/static/files/*.woff* | ||||||
| /website/site/templates/shortcodes/server.conf | /website/site/templates/shortcodes/server.conf | ||||||
| /website/site/templates/shortcodes/sample-exim.conf | /website/site/templates/shortcodes/sample-exim.conf | ||||||
| /website/site/templates/shortcodes/joex.conf | /website/site/templates/shortcodes/joex.conf | ||||||
|   | |||||||
| @@ -840,19 +840,17 @@ val website = project | |||||||
|     }.taskValue, |     }.taskValue, | ||||||
|     Compile / resourceGenerators += Def.task { |     Compile / resourceGenerators += Def.task { | ||||||
|       val changelog = (LocalRootProject / baseDirectory).value / "Changelog.md" |       val changelog = (LocalRootProject / baseDirectory).value / "Changelog.md" | ||||||
|       val targetDir = baseDirectory.value / "site" / "content" / "docs" / "changelog" |       val targetDir = baseDirectory.value / "site" / "content" / "docs" / "install" | ||||||
|       IO.createDirectory(targetDir) |       IO.createDirectory(targetDir) | ||||||
|       val target = targetDir / "_index.md" |       val target = targetDir / "changelog.md" | ||||||
|  |  | ||||||
|       IO.write( |       IO.write( | ||||||
|         target, |         target, | ||||||
|         """|+++ |         """|+++ | ||||||
|            |title = "Changelog" |            |title = "Changelog" | ||||||
|            |description = "See what changed between releases." |            |description = "See what changed between releases." | ||||||
|            |weight = 10 |            |weight = 10000 | ||||||
|            |insert_anchor_links = "right" |            |insert_anchor_links = "right" | ||||||
|            |[extra] |  | ||||||
|            |maketoc = false |  | ||||||
|            |+++ |            |+++ | ||||||
|            |""".stripMargin |            |""".stripMargin | ||||||
|       ) |       ) | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ object Cmd { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   def run(cmd: Seq[String], wd: File, logger: Logger): Unit = { |   def run(cmd: Seq[String], wd: File, logger: Logger): Unit = { | ||||||
|  |     logger.info(s"Running ${cmd.mkString(" ")}") | ||||||
|     val res = Cmd.exec(cmd, Some(wd)) |     val res = Cmd.exec(cmd, Some(wd)) | ||||||
|     logger.info(res.out) |     logger.info(res.out) | ||||||
|     logger.error(res.err) |     logger.error(res.err) | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package docspell.build | |||||||
|  |  | ||||||
| import sbt._ | import sbt._ | ||||||
| import sbt.Keys._ | import sbt.Keys._ | ||||||
|  | import sbt.nio.file.FileTreeView | ||||||
| import scala.sys.process._ | import scala.sys.process._ | ||||||
|  |  | ||||||
| object ZolaPlugin extends AutoPlugin { | object ZolaPlugin extends AutoPlugin { | ||||||
| @@ -74,10 +75,12 @@ object ZolaPlugin extends AutoPlugin { | |||||||
|       case Some(url) => |       case Some(url) => | ||||||
|         Seq("--base-url", url) |         Seq("--base-url", url) | ||||||
|       case None => |       case None => | ||||||
|         runYarnInstall("yarn", inDir.getParentFile, logger) |  | ||||||
|         runElmCompile("elm", inDir.getParentFile, inDir, logger) |  | ||||||
|         Seq.empty |         Seq.empty | ||||||
|     } |     } | ||||||
|  |     runYarnInstall("yarn", inDir.getParentFile, logger) | ||||||
|  |     runElmCompile("elm", inDir.getParentFile, inDir, logger) | ||||||
|  |     runTailwind("npx", inDir.getParentFile, inDir, logger) | ||||||
|  |  | ||||||
|     Cmd.run( |     Cmd.run( | ||||||
|       Seq(zolaCmd, "build", "-o", outDir.absolutePath.toString) ++ baseUrl, |       Seq(zolaCmd, "build", "-o", outDir.absolutePath.toString) ++ baseUrl, | ||||||
|       inDir, |       inDir, | ||||||
| @@ -106,4 +109,39 @@ object ZolaPlugin extends AutoPlugin { | |||||||
|       logger |       logger | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |   def runTailwind(npx: String, inDir: File, zolaRoot: File, logger: Logger): Unit = { | ||||||
|  |     val fontTarget = zolaRoot / "static" / "files" | ||||||
|  |     val iconTarget = zolaRoot / "static" / "webfonts" | ||||||
|  |     IO.createDirectories(Seq(fontTarget, iconTarget)) | ||||||
|  |  | ||||||
|  |     val fontIn = Glob(inDir / "node_modules" / "@fontsource") / * / "files" / * | ||||||
|  |     val fontInFiles = FileTreeView.default.list(fontIn).map(_._1.toFile()) | ||||||
|  |     logger.info(s"Copy ${fontInFiles.size} webfonts from node_modules to ${fontTarget}…") | ||||||
|  |     IO.copy(fontInFiles.pair(Path.flat(fontTarget))) | ||||||
|  |  | ||||||
|  |     val iconIn = | ||||||
|  |       Glob(inDir / "node_modules" / "@fortawesome" / "fontawesome-free" / "webfonts") / * | ||||||
|  |     val iconInFiles = FileTreeView.default.list(iconIn).map(_._1.toFile()) | ||||||
|  |     logger.info(s"Copy ${iconInFiles.size} icons from node_modules to ${iconTarget}…") | ||||||
|  |     IO.copy(iconInFiles.pair(Path.flat(iconTarget))) | ||||||
|  |  | ||||||
|  |     logger.info("Running tailwind…") | ||||||
|  |     Cmd.run( | ||||||
|  |       Seq( | ||||||
|  |         npx, | ||||||
|  |         "tailwindcss", | ||||||
|  |         "-i", | ||||||
|  |         (inDir / "styles" / "input.css").toString, | ||||||
|  |         "-o", | ||||||
|  |         (zolaRoot / "static" / "styles.css").toString, | ||||||
|  |         "--config", | ||||||
|  |         (inDir / "tailwind.config.js").toString, | ||||||
|  |         "--postcss", | ||||||
|  |         (inDir / "postcss.config.js").toString, | ||||||
|  |         "--minify" | ||||||
|  |       ), | ||||||
|  |       inDir, | ||||||
|  |       logger | ||||||
|  |     ) | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,61 +8,61 @@ The website is created using [zola](https://github.com/getzola/zola) | |||||||
| static site generator. The (very minimal) dynamic parts are written in | static site generator. The (very minimal) dynamic parts are written in | ||||||
| Elm. | Elm. | ||||||
|  |  | ||||||
| The `build.sh` script builds the site. | Sbt is used to build the site. | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Development | ## Development | ||||||
|  |  | ||||||
| Install things by running `yarn install`. | Install things by running `yarn install`. | ||||||
|  |  | ||||||
| Open two terminals. In first run: | Open terminal for each script below: | ||||||
|  |  | ||||||
| ``` shell | 1. Starting the server | ||||||
| nix-shell --run ./run-elm.sh |    ``` shell | ||||||
| ``` |    nix-shell --run "cd site && zola serve" | ||||||
|  |    ``` | ||||||
| and in the second | 2. Building the stylesheet | ||||||
|  |    ``` shell | ||||||
| ``` shell |    nix-shell --run ./scripts/run-styles.sh | ||||||
| nix-shell --run "cd site && zola serve" |    ``` | ||||||
| ``` | 3. Building some javascript files | ||||||
|  |    ``` shell | ||||||
|  |    nix-shell --run ./scripts/run-elm.sh | ||||||
|  |    ``` | ||||||
|  |  | ||||||
| Open browser at `localhost:1111`. | Open browser at `localhost:1111`. | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Publishing | ## Publishing | ||||||
|  |  | ||||||
|  | The above is great when editing, but doesn't fully reflect what will | ||||||
|  | be finally deployed. To see this, start sbt and change into the | ||||||
|  | website project. | ||||||
|  |  | ||||||
| ``` shell | ``` shell | ||||||
| nix-shell website/shell.nix --run sbt | nix-shell website/shell.nix --run sbt | ||||||
| sbt> project website | sbt> project website | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Check Links | Build everything and check for dead links: | ||||||
|  |  | ||||||
| ``` scala | ``` scala | ||||||
| sbt> zolaBuild | sbt> zolaBuildTest | ||||||
| sbt> zolaCheck | sbt> zolaCheck | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Testing | ### Testing | ||||||
|  |  | ||||||
| ``` scala | ``` scala | ||||||
| sbt> zolaBuildTest |  | ||||||
| sbt> ghpagesSynchLocal | sbt> ghpagesSynchLocal | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Other terminal: | The final site is now generated and a simple http server can be used | ||||||
|  | to see how it will look when deployed. | ||||||
|  |  | ||||||
| ``` shell | ``` shell | ||||||
| cd ~/.sbt/ghpages/<some-hash>/com.github.eikek/docspell-website | cd ~/.sbt/ghpages/<some-hash>/com.github.eikek/docspell-website | ||||||
| python -m SimpleHTTPServer 1234 | python -m http.server 1234 | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Open http://localhost:1234 in a browser. | Open http://localhost:1234 in a browser. | ||||||
|  |  | ||||||
| ### Publish |  | ||||||
|  |  | ||||||
| ``` scala |  | ||||||
| sbt> zolaBuild |  | ||||||
| sbt> ghpagesPushSite |  | ||||||
| ``` |  | ||||||
|   | |||||||
| @@ -14,19 +14,16 @@ type alias Demo = | |||||||
|  |  | ||||||
| demo : Demo -> Html msg | demo : Demo -> Html msg | ||||||
| demo data = | demo data = | ||||||
|     div [ class "columns is-vcentered box mb-5" ] |     div [ class "px-4 py-4 mx-2 sm:mx-8 rounded border shadow-lg flex flex-col" ] | ||||||
|         [ div [ class "column" ] |         [ h2 [ class "text-3xl font-bold py-2 font-serif" ] | ||||||
|             [ h2 [ class "title" ] |  | ||||||
|             [ text data.title |             [ text data.title | ||||||
|             ] |             ] | ||||||
|         , if data.info == "" then |         , if data.info == "" then | ||||||
|             span [] [] |             span [] [] | ||||||
|  |  | ||||||
|           else |           else | ||||||
|                 p [] |             Markdown.toHtml [ class "text-lg" ] data.info | ||||||
|                     [ Markdown.toHtml [] data.info |         , div [ class "mt-6 self-center" ] | ||||||
|                     ] |  | ||||||
|             , div [ class "mt-5 columns is-centered" ] |  | ||||||
|             [ video |             [ video | ||||||
|                 [ src data.url |                 [ src data.url | ||||||
|                 , controls True |                 , controls True | ||||||
| @@ -34,7 +31,6 @@ demo data = | |||||||
|                 [] |                 [] | ||||||
|             ] |             ] | ||||||
|         ] |         ] | ||||||
|         ] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| navigateDemo = | navigateDemo = | ||||||
|   | |||||||
| @@ -14,16 +14,36 @@ type alias Feature = | |||||||
|  |  | ||||||
| featureBox : Int -> Feature -> Html msg | featureBox : Int -> Feature -> Html msg | ||||||
| featureBox index f = | featureBox index f = | ||||||
|     case isOdd index of |     let | ||||||
|         False -> |         titleCss = | ||||||
|             div [ class "columns is-vcentered box mb-5" ] |             "text-3xl font-bold font-serif mb-3" | ||||||
|                 [ div [ class "column is-three-quarter" ] |  | ||||||
|                     [ figure [ class "image is-2by1 feature-image" ] |         boxCss = | ||||||
|                         [ img [ src f.image ] [] |             [ class "flex-col space-y-2" | ||||||
|  |             , class "sm:flex-row sm:space-y-0 sm-space-x-4" | ||||||
|  |             , class "flex px-8 py-8 border rounded mb-5 shadow-lg mx-2 sm:mx-8" | ||||||
|  |             ] | ||||||
|  |  | ||||||
|  |         descrCss = | ||||||
|  |             "flex flex-col text-xl " | ||||||
|  |     in | ||||||
|  |     if isOdd index then | ||||||
|  |         div boxCss | ||||||
|  |             [ div [ class "sm:w-1/2" ] | ||||||
|  |                 [ figure [ class "block my-auto" ] | ||||||
|  |                     [ img | ||||||
|  |                         [ src f.image | ||||||
|  |                         , class "w-full" | ||||||
|  |                         , style "min-width" "4rem" | ||||||
|  |                         ] | ||||||
|  |                         [] | ||||||
|                     ] |                     ] | ||||||
|                 ] |                 ] | ||||||
|                 , div [ class "column" ] |             , div | ||||||
|                     [ h2 [ class "title" ] |                 [ class descrCss | ||||||
|  |                 , class "pl-4 sm:w-1/2" | ||||||
|  |                 ] | ||||||
|  |                 [ h2 [ class titleCss ] | ||||||
|                     [ text f.header |                     [ text f.header | ||||||
|                     ] |                     ] | ||||||
|                 , Markdown.toHtml [] |                 , Markdown.toHtml [] | ||||||
| @@ -31,18 +51,26 @@ featureBox index f = | |||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|  |  | ||||||
|         True -> |     else | ||||||
|             div [ class "columns is-vcentered box mb-5" ] |         div | ||||||
|                 [ div [ class "column is-three-quarter" ] |             boxCss | ||||||
|                     [ h2 [ class "title" ] |             [ div | ||||||
|  |                 [ class descrCss | ||||||
|  |                 , class "pr-4 sm:w-1/2" | ||||||
|  |                 ] | ||||||
|  |                 [ h2 [ class titleCss ] | ||||||
|                     [ text f.header |                     [ text f.header | ||||||
|                     ] |                     ] | ||||||
|                 , Markdown.toHtml [] |                 , Markdown.toHtml [] | ||||||
|                     f.description |                     f.description | ||||||
|                 ] |                 ] | ||||||
|                 , div [ class "column" ] |             , div [ class "sm:w-1/2" ] | ||||||
|                     [ figure [ class "image is-2by1 feature-image" ] |                 [ figure [ class "block my-auto " ] | ||||||
|                         [ img [ src f.image ] [] |                     [ img | ||||||
|  |                         [ src f.image | ||||||
|  |                         , class "w-full" | ||||||
|  |                         ] | ||||||
|  |                         [] | ||||||
|                     ] |                     ] | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
| @@ -105,7 +133,7 @@ Users can define IMAP settings so that docspell can import their e-mails. This c | |||||||
|     , { image = "img/notify-feature.png" |     , { image = "img/notify-feature.png" | ||||||
|       , header = "Notifications" |       , header = "Notifications" | ||||||
|       , description = """ |       , description = """ | ||||||
| Users can be notified by e-mail for documents whose due-date comes closer. | Users can be notified by e-mail, Matrix or Gotify with documents resulting from a query that is executed periodically. Notifications can also be configured for specific events. | ||||||
| """ | """ | ||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -2,35 +2,32 @@ module GetStarted exposing (..) | |||||||
|  |  | ||||||
| import Html exposing (..) | import Html exposing (..) | ||||||
| import Html.Attributes exposing (..) | import Html.Attributes exposing (..) | ||||||
| import Icons |  | ||||||
| import Markdown | import Markdown | ||||||
|  |  | ||||||
|  |  | ||||||
| getStarted : String -> List (Html msg) | getStarted : String -> Html msg | ||||||
| getStarted version = | getStarted _ = | ||||||
|     [ div [ class "content container" ] |     div [ class "container max-w-screen-lg mx-auto text-xl px-10 lg:px-0 leading-relaxed min-h-screen" ] | ||||||
|         [ Markdown.toHtml [] |         [ Markdown.toHtml [ class "my-4 markdown-view" ] | ||||||
|             """Docspell consists of several components. The easiest way to get started is probably to use docker and |             """Docspell consists of several components. The easiest way to get started is probably to use docker and | ||||||
| [docker-compose](https://docs.docker.com/compose/).""" | [docker-compose](https://docs.docker.com/compose/).""" | ||||||
|         , Markdown.toHtml [] |         , Markdown.toHtml [ class "my-4 markdown-view " ] | ||||||
|             """1. Clone the github repository |             """1. Clone the github repository | ||||||
|    ```bash |    ```bash | ||||||
|    $ git clone https://github.com/eikek/docspell |    $ git clone https://github.com/eikek/docspell | ||||||
|    ``` |    ``` | ||||||
|    Alternatively, [download](https://github.com/eikek/docspell/archive/master.zip) the sources and extract the zip file. |    Alternatively, [download](https://github.com/eikek/docspell/archive/master.zip) the sources and extract the zip file. | ||||||
| 2. Change into the `docker` directory: | 2. Change into the `docker-compose` directory: | ||||||
|    ```bash |    ```bash | ||||||
|    $ cd docspell/docker/docker-compose |    $ cd docspell/docker/docker-compose | ||||||
|    ``` |    ``` | ||||||
| 3. Run `docker-compose up`: | 3. Run `docker-compose up`: | ||||||
|  |  | ||||||
|    ```bash |    ```bash | ||||||
|    $ docker-compose up -d |    $ docker-compose up -d | ||||||
|    ``` |    ``` | ||||||
| 4. Goto <http://localhost:7880>, signup and login. When signing up, | 4. Goto <http://localhost:7880>, signup and login. When signing up, | ||||||
|    choose the same name for collective and user. Then login |    choose the same name for collective and user. Then login | ||||||
|    with this name and the password. |    with this name and the password. | ||||||
|  |  | ||||||
| 5. (Optional) Create a folder `./docs/<collective-name>` (the name you | 5. (Optional) Create a folder `./docs/<collective-name>` (the name you | ||||||
|    chose for the collective at registration) and place files in there |    chose for the collective at registration) and place files in there | ||||||
|    for importing them. |    for importing them. | ||||||
| @@ -38,23 +35,18 @@ getStarted version = | |||||||
| The `docker-compose.yml` file defines some environment variables to | The `docker-compose.yml` file defines some environment variables to | ||||||
| configure docspell. You can [modify](docs/configure) them as needed. | configure docspell. You can [modify](docs/configure) them as needed. | ||||||
|     """ |     """ | ||||||
|         ] |         , div [ class "blue-message" ] | ||||||
|     , div [ class "content container" ] |  | ||||||
|         [ div [ class "notification is-info is-light" ] |  | ||||||
|             [ text "If you don't use docker, there are other ways that are " |             [ text "If you don't use docker, there are other ways that are " | ||||||
|             , text "described in the relevant " |             , text "described in the relevant " | ||||||
|             , a [ href "/docs/install" ] |             , a [ href "/docs/install", class "link" ] | ||||||
|                 [ text "documentation page" |                 [ text "documentation page" | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|         ] |         , div [ class "green-message mt-4 " ] | ||||||
|     , div [ class "content container" ] |             [ h3 [ class "text-4xl font-bold font-serif py-2 mb-2" ] | ||||||
|         [ div [ class "notification is-success is-light" ] |  | ||||||
|             [ div [ class "content is-medium" ] |  | ||||||
|                 [ h3 [ class "title" ] |  | ||||||
|                 [ text "Where to go from here?" |                 [ text "Where to go from here?" | ||||||
|                 ] |                 ] | ||||||
|                 , ul [] |             , ul [ class "list-disc list-inside " ] | ||||||
|                 [ li [] |                 [ li [] | ||||||
|                     [ text "Find out " |                     [ text "Find out " | ||||||
|                     , a [ href "/docs/feed" ] |                     , a [ href "/docs/feed" ] | ||||||
| @@ -91,5 +83,3 @@ configure docspell. You can [modify](docs/configure) them as needed. | |||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|         ] |         ] | ||||||
|         ] |  | ||||||
|     ] |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import Html.Attributes exposing (..) | |||||||
|  |  | ||||||
| copyright : Html msg | copyright : Html msg | ||||||
| copyright = | copyright = | ||||||
|     img [ src "icons/copyright-40.svg" ] [] |     i [ class "fa fa-copyright font-thin" ] [] | ||||||
|  |  | ||||||
|  |  | ||||||
| infoSquared : Html msg | infoSquared : Html msg | ||||||
| @@ -36,19 +36,24 @@ logoWidth w = | |||||||
|  |  | ||||||
| home : Html msg | home : Html msg | ||||||
| home = | home = | ||||||
|     img [ src "icons/home-40.svg" ] [] |     i [ class "fa fa-home" ] [] | ||||||
|  |  | ||||||
|  |  | ||||||
| docs : Html msg | docs : Html msg | ||||||
| docs = | docs = | ||||||
|     img [ src "icons/notes-40.svg" ] [] |     i [ class "fa fa-book" ] [] | ||||||
|  |  | ||||||
|  |  | ||||||
| github : Html msg | github : Html msg | ||||||
| github = | github = | ||||||
|     img [ src "/icons/github-40.svg" ] [] |     i [ class "fab fa-github-alt" ] [] | ||||||
|  |  | ||||||
|  |  | ||||||
| githubGreen : Html msg | githubGreen : Html msg | ||||||
| githubGreen = | githubGreen = | ||||||
|     img [ src "/icons/github-40-green.svg" ] [] |     img [ src "/icons/github-40-green.svg" ] [] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | blog : Html msg | ||||||
|  | blog = | ||||||
|  |     i [ class "fa fa-blog" ] [] | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| module Main exposing (..) | module Main exposing (..) | ||||||
|  |  | ||||||
| import Browser exposing (Document) | import Browser | ||||||
| import Browser.Navigation exposing (Key) |  | ||||||
| import Demo | import Demo | ||||||
| import ExtraAttr exposing (..) | import ExtraAttr exposing (..) | ||||||
| import Feature exposing (Feature) | import Feature exposing (Feature) | ||||||
| @@ -109,34 +108,33 @@ subscriptions _ = | |||||||
| view : Model -> Html Msg | view : Model -> Html Msg | ||||||
| view model = | view model = | ||||||
|     node "body" |     node "body" | ||||||
|         [] |         [ class "text-gray-700" ] | ||||||
|         [ mainHero model |         [ mainHero model | ||||||
|         , demoHero |         , demoHeader | ||||||
|         , section [ class "section" ] |         , section [ class "container max-w-screen-xl mx-auto mb-2" ] | ||||||
|             [ div [ class "container" ] |             [ div [ class "mt-3 flex flex-col space-y-4" ] | ||||||
|                 [ Demo.demo Demo.processDemo |                 [ Demo.demo Demo.processDemo | ||||||
|                 , Demo.demo Demo.navigateDemo |                 , Demo.demo Demo.navigateDemo | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|         , featureHero model |         , featureHeader model | ||||||
|         , section [ class "section" ] |         , section [ class "mx-auto max-w-screen-xl  mb-2 mt-4" ] | ||||||
|             [ div [ class "container" ] |  | ||||||
|             (List.indexedMap Feature.featureBox model.features |             (List.indexedMap Feature.featureBox model.features | ||||||
|                     ++ [ div [ class "columns box" ] |                 ++ [ div | ||||||
|                             [ div [ class "column is-full" ] |                         [ class "flex px-8 py-8 border rounded mb-5 shadow-lg text-2xl" | ||||||
|                                 [ div [ class "content has-text-centered is-medium" ] |                         , class "sm:flex-row sm:space-y-0 sm-space-x-4" | ||||||
|  |                         , class "mx-2 sm:mx-8" | ||||||
|  |                         ] | ||||||
|  |                         [ div [ class "text-center w-full" ] | ||||||
|                             [ text "A more complete list can be found in " |                             [ text "A more complete list can be found in " | ||||||
|                                     , a [ href "/docs/features" ] [ text "here" ] |                             , a [ href "/docs/features", class "link" ] [ text "here" ] | ||||||
|                             , text "." |                             , text "." | ||||||
|                             ] |                             ] | ||||||
|                         ] |                         ] | ||||||
|                    ] |                    ] | ||||||
|                        ] |  | ||||||
|             ) |             ) | ||||||
|             ] |         , getStartedHeader model | ||||||
|         , getStartedHero model |         , GetStarted.getStarted model.flags.version | ||||||
|         , div [ class "section" ] |  | ||||||
|             (GetStarted.getStarted model.flags.version) |  | ||||||
|         , footHero model |         , footHero model | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
| @@ -147,7 +145,7 @@ footHero model = | |||||||
|         [ id "footer" |         [ id "footer" | ||||||
|         , class "footer" |         , class "footer" | ||||||
|         ] |         ] | ||||||
|         [ div [ class "has-text-centered" ] |         [ div [ class "text-center" ] | ||||||
|             [ span [] |             [ span [] | ||||||
|                 [ text ("Docspell, " ++ model.flags.version) |                 [ text ("Docspell, " ++ model.flags.version) | ||||||
|                 ] |                 ] | ||||||
| @@ -157,6 +155,7 @@ footHero model = | |||||||
|             , a |             , a | ||||||
|                 [ href "https://spdx.org/licenses/AGPL-3.0-or-later.html" |                 [ href "https://spdx.org/licenses/AGPL-3.0-or-later.html" | ||||||
|                 , target "_blank" |                 , target "_blank" | ||||||
|  |                 , class "link" | ||||||
|                 ] |                 ] | ||||||
|                 [ text "AGPLv3+" |                 [ text "AGPLv3+" | ||||||
|                 ] |                 ] | ||||||
| @@ -166,6 +165,7 @@ footHero model = | |||||||
|             , a |             , a | ||||||
|                 [ href "https://github.com/eikek/docspell" |                 [ href "https://github.com/eikek/docspell" | ||||||
|                 , target "_blank" |                 , target "_blank" | ||||||
|  |                 , class "link" | ||||||
|                 ] |                 ] | ||||||
|                 [ text "Source Code" |                 [ text "Source Code" | ||||||
|                 ] |                 ] | ||||||
| @@ -176,6 +176,7 @@ footHero model = | |||||||
|                 [ a |                 [ a | ||||||
|                     [ href "https://gitter.im/eikek/docspell" |                     [ href "https://gitter.im/eikek/docspell" | ||||||
|                     , target "_blank" |                     , target "_blank" | ||||||
|  |                     , class "link" | ||||||
|                     ] |                     ] | ||||||
|                     [ text "Chat on Gitter" |                     [ text "Chat on Gitter" | ||||||
|                     ] |                     ] | ||||||
| @@ -184,166 +185,142 @@ footHero model = | |||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| getStartedHero : Model -> Html Msg | getStartedHeader : Model -> Html Msg | ||||||
| getStartedHero _ = | getStartedHeader _ = | ||||||
|     section |     section | ||||||
|         [ id "get-started" |         [ id "get-started" | ||||||
|         , class "hero is-primary is-bold" |         , class "hero-header" | ||||||
|         ] |         ] | ||||||
|         [ div [ class "hero-body" ] |  | ||||||
|             [ div [ class "container" ] |  | ||||||
|                 [ h2 [ class "title" ] |  | ||||||
|         [ text "Get Started" |         [ text "Get Started" | ||||||
|         ] |         ] | ||||||
|                 ] |  | ||||||
|             ] |  | ||||||
|         ] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| demoHero : Html msg | demoHeader : Html msg | ||||||
| demoHero = | demoHeader = | ||||||
|     section |     h2 | ||||||
|         [ id "demos" |         [ class "hero-header" | ||||||
|         , class "hero is-info is-bold" |         , id "demos" | ||||||
|         ] |         ] | ||||||
|         [ div |  | ||||||
|             [ class "hero-body" |  | ||||||
|             ] |  | ||||||
|             [ div [ class "container" ] |  | ||||||
|                 [ h2 [ class "title" ] |  | ||||||
|         [ text "Screencasts" |         [ text "Screencasts" | ||||||
|         ] |         ] | ||||||
|                 ] |  | ||||||
|             ] |  | ||||||
|         ] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| featureHero : Model -> Html Msg | featureHeader : Model -> Html Msg | ||||||
| featureHero model = | featureHeader _ = | ||||||
|     section |     h2 | ||||||
|         [ id "feature-selection" |         [ id "feature-selection" | ||||||
|         , class "hero is-info is-bold" |         , class "hero-header" | ||||||
|         ] |         ] | ||||||
|         [ div |  | ||||||
|             [ class "hero-body" |  | ||||||
|             ] |  | ||||||
|             [ div [ class "container" ] |  | ||||||
|                 [ h2 [ class "title" ] |  | ||||||
|         [ text "Feature Selection" |         [ text "Feature Selection" | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | navBar : String -> Html Msg | ||||||
|  | navBar classes = | ||||||
|  |     nav | ||||||
|  |         [ id "top-nav" | ||||||
|  |         , class "top-0 z-50 w-full flex flex-row justify-start shadow-sm h-14 antialiased " | ||||||
|  |         , class classes | ||||||
|  |         ] | ||||||
|  |         [ a | ||||||
|  |             [ onClick ToggleNavbarMenu | ||||||
|  |             , href "#" | ||||||
|  |             , class "font-bold inline-flex items-center px-4 w-10 sm:hidden " | ||||||
|  |             ] | ||||||
|  |             [ i [ class "fa fa-bars" ] [] | ||||||
|  |             ] | ||||||
|  |         , a | ||||||
|  |             [ class "inline-flex px-4 items-center hover:bg-gray-50 hover:bg-opacity-20" | ||||||
|  |             , href "/" | ||||||
|  |             ] | ||||||
|  |             [ div [ class "" ] | ||||||
|  |                 [ Icons.logo | ||||||
|  |                 ] | ||||||
|  |             , span [ class "ml-1 text-2xl font-semibold font-serif" ] | ||||||
|  |                 [ text "Docspell" ] | ||||||
|  |             ] | ||||||
|  |         , a | ||||||
|  |             [ href "docs/" | ||||||
|  |             , class "px-4 flex items-center hover:bg-gray-50 hover:bg-opacity-20" | ||||||
|  |             , class " text-xl" | ||||||
|  |             ] | ||||||
|  |             [ Icons.docs | ||||||
|  |             , span [ class "ml-2 tracking-wide" ] | ||||||
|  |                 [ text "Documentation" | ||||||
|  |                 ] | ||||||
|  |             ] | ||||||
|  |         , a | ||||||
|  |             [ href "blog/" | ||||||
|  |             , class "px-4 flex items-center hover:bg-gray-50 hover:bg-opacity-20" | ||||||
|  |             , class " text-xl" | ||||||
|  |             ] | ||||||
|  |             [ Icons.blog | ||||||
|  |             , span [ class "ml-2 tracking-wide" ] | ||||||
|  |                 [ text "Blog" | ||||||
|  |                 ] | ||||||
|  |             ] | ||||||
|  |         , a | ||||||
|  |             [ target "_blank" | ||||||
|  |             , href "https://github.com/eikek/docspell" | ||||||
|  |             , class "px-4 flex items-center hover:bg-gray-50 hover:bg-opacity-20" | ||||||
|  |             , class " text-xl" | ||||||
|  |             ] | ||||||
|  |             [ Icons.github | ||||||
|  |             , span [ class "ml-2 tracking-wide" ] | ||||||
|  |                 [ text "Github" | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| mainHero : Model -> Html Msg | mainHero : Model -> Html Msg | ||||||
| mainHero model = | mainHero _ = | ||||||
|     section |     section | ||||||
|         [ id "hero-main" |         [ id "hero-main" | ||||||
|         , class "hero is-fullheight is-primary" |         , class "min-h-screen text-white flex flex-col items-center main-background" | ||||||
|         ] |  | ||||||
|         [ div [ class "hero-head" ] |  | ||||||
|             [ nav [ class "navbar" ] |  | ||||||
|                 [ div [ class "navbar-brand" ] |  | ||||||
|                     [ a |  | ||||||
|                         [ class "navbar-item" |  | ||||||
|                         , href "/" |  | ||||||
|                         ] |  | ||||||
|                         [ span [ class "icon is-large" ] |  | ||||||
|                             [ Icons.logo |  | ||||||
|                             ] |  | ||||||
|                         , text "Docspell" |  | ||||||
|                         ] |  | ||||||
|                     , a |  | ||||||
|                         [ role "button" |  | ||||||
|                         , onClick ToggleNavbarMenu |  | ||||||
|                         , classList |  | ||||||
|                             [ ( "navbar-burger", True ) |  | ||||||
|                             , ( "is-active", model.navbarOpen ) |  | ||||||
|                             ] |  | ||||||
|                         , ariaLabel "menu" |  | ||||||
|                         , ariaExpanded False |  | ||||||
|                         ] |  | ||||||
|                         [ span [ ariaHidden True ] [] |  | ||||||
|                         , span [ ariaHidden True ] [] |  | ||||||
|                         , span [ ariaHidden True ] [] |  | ||||||
|                         ] |  | ||||||
|                     ] |  | ||||||
|                 , div |  | ||||||
|                     [ classList |  | ||||||
|                         [ ( "navbar-menu", True ) |  | ||||||
|                         , ( "is-active", model.navbarOpen ) |  | ||||||
|                         ] |  | ||||||
|                     ] |  | ||||||
|                     [ div [ class "navbar-start" ] |  | ||||||
|                         [ a |  | ||||||
|                             [ href "docs/" |  | ||||||
|                             , class "navbar-item" |  | ||||||
|                             ] |  | ||||||
|                             [ span [ class "icon" ] |  | ||||||
|                                 [ Icons.docs |  | ||||||
|                                 ] |  | ||||||
|                             , span [] |  | ||||||
|                                 [ text "Documentation" |  | ||||||
|                                 ] |  | ||||||
|                             ] |  | ||||||
|                         , a |  | ||||||
|                             [ target "_blank" |  | ||||||
|                             , href "https://github.com/eikek/docspell" |  | ||||||
|                             , class "navbar-item" |  | ||||||
|                             ] |  | ||||||
|                             [ span [ class "icon" ] |  | ||||||
|                                 [ Icons.github |  | ||||||
|                                 ] |  | ||||||
|                             , span [] |  | ||||||
|                                 [ text "Github" |  | ||||||
|                                 ] |  | ||||||
|                             ] |  | ||||||
|                         ] |  | ||||||
|                     ] |  | ||||||
|                 ] |  | ||||||
|             ] |  | ||||||
|         , div [ class "hero-body" ] |  | ||||||
|             [ div |  | ||||||
|                 [ class "container has-text-centered" |  | ||||||
|         ] |         ] | ||||||
|  |         [ navBar " text-white" | ||||||
|  |         , div [ class "flex-grow flex flex-col items-center justify-center w-full" ] | ||||||
|             [ Icons.logoWidth 112 |             [ Icons.logoWidth 112 | ||||||
|                 , h1 [ class "title main-title is-2" ] |             , h1 [ class "text-6xl font-semibold shadow font-serif" ] | ||||||
|                 [ text "Docspell" |                 [ text "Docspell" | ||||||
|                 ] |                 ] | ||||||
|                 , h2 [ class "subtitle is-3" ] |             , h2 [ class "text-3xl font-madium tracking-wide mt-2 mb-4 " ] | ||||||
|                 [ text "Simple document organizer" |                 [ text "Simple document organizer" | ||||||
|                 ] |                 ] | ||||||
|                 , p [ class "content is-medium narrow-center" ] |             , p [ class "px-2 text-center text-xl font-light shadow max-w-prose font-sans" ] | ||||||
|                 [ text "Docspell assists in organizing your piles of " |                 [ text "Docspell assists in organizing your piles of " | ||||||
|                 , text "digital documents, resulting from scanners, e-mails " |                 , text "digital documents, resulting from scanners, e-mails " | ||||||
|                 , text "and other sources with miminal effort." |                 , text "and other sources with miminal effort." | ||||||
|                 ] |                 ] | ||||||
|                 , div [ class " buttons is-centered" ] |             , div | ||||||
|  |                 [ class "mt-4 flex flex-col space-y-2 text-2xl" | ||||||
|  |                 , class "sm:items-center sm:flex-row sm:space-y-0 sm:space-x-4" | ||||||
|  |                 ] | ||||||
|                 [ a |                 [ a | ||||||
|                         [ class "button is-info is-medium" |                     [ class "button info" | ||||||
|                     , href "#demos" |                     , href "#demos" | ||||||
|                     ] |                     ] | ||||||
|                     [ text "Screencasts" |                     [ text "Screencasts" | ||||||
|                     ] |                     ] | ||||||
|                 , a |                 , a | ||||||
|                         [ class "button is-info is-medium" |                     [ class "button info" | ||||||
|                     , href "#feature-selection" |                     , href "#feature-selection" | ||||||
|                     ] |                     ] | ||||||
|                     [ text "Features" |                     [ text "Features" | ||||||
|                     ] |                     ] | ||||||
|                 , a |                 , a | ||||||
|                         [ class "button is-primary is-medium" |                     [ class "button primary" | ||||||
|                     , href "#get-started" |                     , href "#get-started" | ||||||
|                     ] |                     ] | ||||||
|                     [ text "Get Started" |                     [ text "Get Started" | ||||||
|                     ] |                     ] | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|             ] |         , div [ class "text-right w-full" ] | ||||||
|         , div [ class "hero-foot" ] |             [ span [ class "opacity-40 text-xs" ] | ||||||
|             [ span [ class "unsplash-credit" ] |                 [ i [ class "fab fa-unsplash mr-1" ] [] | ||||||
|                 [ text "Photo by " |                 , text "Photo by " | ||||||
|                 , a |                 , a | ||||||
|                     [ href "https://unsplash.com/@numericcitizen" |                     [ href "https://unsplash.com/@numericcitizen" | ||||||
|                     , target "_blank" |                     , target "_blank" | ||||||
|   | |||||||
| @@ -1,11 +1,9 @@ | |||||||
| port module Search exposing (..) | port module Search exposing (..) | ||||||
|  |  | ||||||
| import Browser exposing (Document) | import Browser | ||||||
| import Browser.Navigation exposing (Key) |  | ||||||
| import Html as H exposing (..) | import Html as H exposing (..) | ||||||
| import Html.Attributes exposing (..) | import Html.Attributes exposing (..) | ||||||
| import Html.Events exposing (onClick, onInput, onSubmit) | import Html.Events exposing (onClick, onInput, onSubmit) | ||||||
| import Json.Decode as D |  | ||||||
| import Markdown | import Markdown | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -45,14 +43,21 @@ type alias SearchEntry = | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | type SearchState | ||||||
|  |     = Initial | ||||||
|  |     | Found (List SearchEntry) | ||||||
|  |  | ||||||
|  |  | ||||||
| type alias Model = | type alias Model = | ||||||
|     { searchInput : String |     { searchInput : String | ||||||
|     , results : List SearchEntry |     , results : SearchState | ||||||
|  |     , searchVisible : Bool | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| type Msg | type Msg | ||||||
|     = SetSearch String |     = SetSearch String | ||||||
|  |     | ToggleBar | ||||||
|     | SubmitSearch |     | SubmitSearch | ||||||
|     | GetSearchResults (List SearchEntry) |     | GetSearchResults (List SearchEntry) | ||||||
|  |  | ||||||
| @@ -64,7 +69,8 @@ type Msg | |||||||
| init : Flags -> ( Model, Cmd Msg ) | init : Flags -> ( Model, Cmd Msg ) | ||||||
| init flags = | init flags = | ||||||
|     ( { searchInput = "" |     ( { searchInput = "" | ||||||
|       , results = [] |       , results = Initial | ||||||
|  |       , searchVisible = False | ||||||
|       } |       } | ||||||
|     , Cmd.none |     , Cmd.none | ||||||
|     ) |     ) | ||||||
| @@ -77,6 +83,11 @@ init flags = | |||||||
| update : Msg -> Model -> ( Model, Cmd Msg ) | update : Msg -> Model -> ( Model, Cmd Msg ) | ||||||
| update msg model = | update msg model = | ||||||
|     case msg of |     case msg of | ||||||
|  |         ToggleBar -> | ||||||
|  |             ( { model | searchVisible = not model.searchVisible } | ||||||
|  |             , Cmd.none | ||||||
|  |             ) | ||||||
|  |  | ||||||
|         SetSearch str -> |         SetSearch str -> | ||||||
|             ( { model | searchInput = str } |             ( { model | searchInput = str } | ||||||
|             , Cmd.none |             , Cmd.none | ||||||
| @@ -86,7 +97,7 @@ update msg model = | |||||||
|             ( model, doSearch model.searchInput ) |             ( model, doSearch model.searchInput ) | ||||||
|  |  | ||||||
|         GetSearchResults list -> |         GetSearchResults list -> | ||||||
|             ( { model | results = List.take 8 list }, Cmd.none ) |             ( { model | results = Found <| List.take 20 list }, Cmd.none ) | ||||||
|  |  | ||||||
|  |  | ||||||
| subscriptions : Model -> Sub Msg | subscriptions : Model -> Sub Msg | ||||||
| @@ -100,56 +111,67 @@ subscriptions _ = | |||||||
|  |  | ||||||
| view : Model -> Html Msg | view : Model -> Html Msg | ||||||
| view model = | view model = | ||||||
|     H.form |     div | ||||||
|         [ class "form" |         [ class " inline-flex px-4 items-center hover:bg-amber-600 hover:bg-opacity-10  dark:hover:bg-stone-800" | ||||||
|         , onSubmit SubmitSearch |  | ||||||
|         ] |         ] | ||||||
|         [ div [ class "dropdown field is-active is-fullwidth has-addons" ] |         [ a | ||||||
|             [ div [ class "control is-fullwidth" ] |             [ href "#" | ||||||
|  |             , class "h-full w-full inline-flex items-center" | ||||||
|  |             , onClick ToggleBar | ||||||
|  |             ] | ||||||
|  |             [ i [ class "fa fa-search" ] [] | ||||||
|  |             ] | ||||||
|  |         , div | ||||||
|  |             [ class "absolute px-2 mx-2 right-0 max-w-screen-md rounded top-12 w-full border-l border-r border-b bg-white h-12 dark:bg-stone-800 dark:border-stone-700" | ||||||
|  |             , classList [ ( "hidden", not model.searchVisible ) ] | ||||||
|  |             ] | ||||||
|  |             [ H.form [ onSubmit SubmitSearch ] | ||||||
|                 [ input |                 [ input | ||||||
|                     [ class "input" |                     [ type_ "text" | ||||||
|                     , type_ "text" |  | ||||||
|                     , placeholder "Search docs…" |  | ||||||
|                     , onInput SetSearch |  | ||||||
|                     , value model.searchInput |                     , value model.searchInput | ||||||
|  |                     , autofocus True | ||||||
|  |                     , placeholder "Search …" | ||||||
|  |                     , class "w-full block h-8 border-0 border-b border-stone-400 mt-2 focus:ring-0 focus:border-indigo-500 dark:bg-stone-800 dark:focus:border-cyan-400" | ||||||
|  |                     , onInput SetSearch | ||||||
|                     ] |                     ] | ||||||
|                     [] |                     [] | ||||||
|                 ] |                 ] | ||||||
|             , div [ class "control" ] |  | ||||||
|                 [ button |  | ||||||
|                     [ class "button is-primary" |  | ||||||
|                     , href "#" |  | ||||||
|                     , onClick SubmitSearch |  | ||||||
|                     ] |  | ||||||
|                     [ img [ src "/icons/search-white-20.svg" ] [] |  | ||||||
|                     ] |  | ||||||
|                 ] |  | ||||||
|             , viewResults model.results |             , viewResults model.results | ||||||
|             ] |             ] | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| viewResults : List SearchEntry -> Html Msg | viewResults : SearchState -> Html Msg | ||||||
| viewResults entries = | viewResults state = | ||||||
|  |     case state of | ||||||
|  |         Initial -> | ||||||
|  |             span [ class "hidden" ] [] | ||||||
|  |  | ||||||
|  |         Found [] -> | ||||||
|             div |             div | ||||||
|         [ classList |                 [ class "bg-white dark:bg-stone-800 mt-2 w-full" | ||||||
|             [ ( "dropdown-menu", True ) |                 ] | ||||||
|             , ( "is-hidden", entries == [] ) |                 [ div [ class "flex flex-row items-center h-14 justify-center text-xl" ] | ||||||
|  |                     [ i [ class "fa fa-meh font-thin mr-2" ] | ||||||
|  |                         [] | ||||||
|  |                     , text "No results." | ||||||
|                     ] |                     ] | ||||||
|                 ] |                 ] | ||||||
|         [ div [ class "dropdown-content" ] |  | ||||||
|             (List.intersperse |         Found entries -> | ||||||
|                 (div [ class "dropdown-divider" ] []) |             div | ||||||
|  |                 [ class "bg-white dark:bg-stone-800 mt-2 w-screen sm:w-full h-screen-12 md:h-fit md:max-h-96 overflow-auto shadow-lg border-l border-r border-b dark:border-stone-700" | ||||||
|  |                 ] | ||||||
|  |                 [ div [ class "px-2 pt-2 pb-1 flex flex-col divide-y dark:divide-stone-700 " ] | ||||||
|                     (List.map viewResult entries) |                     (List.map viewResult entries) | ||||||
|             ) |  | ||||||
|                 ] |                 ] | ||||||
|  |  | ||||||
|  |  | ||||||
| viewResult : SearchEntry -> Html Msg | viewResult : SearchEntry -> Html Msg | ||||||
| viewResult result = | viewResult result = | ||||||
|     div [ class "dropdown-item" ] |     div [ class "py-2 content" ] | ||||||
|         [ a |         [ a | ||||||
|             [ class "is-size-5" |             [ class "text-lg font-semibold" | ||||||
|             , href result.ref |             , href result.ref | ||||||
|             ] |             ] | ||||||
|             [ text result.doc.title |             [ text result.doc.title | ||||||
| @@ -158,6 +180,16 @@ viewResult result = | |||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | textInput : String | ||||||
|  | textInput = | ||||||
|  |     " placeholder-gray-400 w-full dark:text-slate-200 dark:bg-slate-800 dark:border-slate-500 border-gray-400 rounded " ++ formFocusRing | ||||||
|  |  | ||||||
|  |  | ||||||
|  | formFocusRing : String | ||||||
|  | formFocusRing = | ||||||
|  |     " focus:ring focus:ring-black focus:ring-opacity-50 focus:ring-offset-0 dark:focus:ring-slate-400 " | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| --- Ports | --- Ports | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,17 @@ | |||||||
| { | { | ||||||
|     "license": "GPL-3.0-or-later", |     "license": "GPL-3.0-or-later", | ||||||
|     "dependencies": { |     "dependencies": { | ||||||
|         "bulma": "^0.9.0" |         "@fontsource/montserrat": "^4.5.3", | ||||||
|  |         "@fontsource/source-code-pro": "^4.5.2", | ||||||
|  |         "@fontsource/spectral": "^4.5.1", | ||||||
|  |         "@fortawesome/fontawesome-free": "^5.15", | ||||||
|  |         "@tailwindcss/forms": "^0.4.0", | ||||||
|  |         "autoprefixer": "^10.4", | ||||||
|  |         "cssnano": "^5.0", | ||||||
|  |         "postcss": "^8.4.5", | ||||||
|  |         "postcss-cli": "^9.1.0", | ||||||
|  |         "postcss-import": "^14.0.2", | ||||||
|  |         "postcss-purgecss": "^2.0.3", | ||||||
|  |         "tailwindcss": "^3.0" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								website/postcss.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,10 @@ | |||||||
|  | //postcss.config.js | ||||||
|  |  | ||||||
|  | module.exports = (ctx) => ({ | ||||||
|  |     plugins: [ | ||||||
|  |         require('postcss-import'), | ||||||
|  |         require('tailwindcss'), | ||||||
|  |         require('autoprefixer'), | ||||||
|  |         require('cssnano'), | ||||||
|  |     ] | ||||||
|  | }) | ||||||
| @@ -3,6 +3,7 @@ | |||||||
| set -e | set -e | ||||||
| 
 | 
 | ||||||
| yarn install | yarn install | ||||||
|  | npx tailwindcss -i ./styles/input.css -o ./site/public/styles.css  --config ./tailwind.config.js --postcss ./postcss.config.js | ||||||
| elm make --output site/static/js/bundle.js --optimize elm/Main.elm | elm make --output site/static/js/bundle.js --optimize elm/Main.elm | ||||||
| cd site && zola build | cd site && zola build | ||||||
| cd .. | cd .. | ||||||
							
								
								
									
										11
									
								
								website/scripts/run-styles.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  |  | ||||||
|  | mkdir -p ./site/public/files | ||||||
|  | mkdir -p ./site/public/webfonts | ||||||
|  |  | ||||||
|  | echo "Copy webfonts…" | ||||||
|  | cp node_modules/@fontsource/*/files/* ./site/public/files/ | ||||||
|  | cp node_modules/@fortawesome/fontawesome-free/webfonts/* ./site/public/webfonts/ | ||||||
|  |  | ||||||
|  | echo "Running tailwind…" | ||||||
|  | npx tailwindcss -i ./styles/input.css -o ./site/public/styles.css  --config ./tailwind.config.js --postcss ./postcss.config.js "$1" | ||||||
							
								
								
									
										74
									
								
								website/scripts/screenshot.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,74 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  | # | ||||||
|  | # Little tool to help with doing screenshots. | ||||||
|  | # | ||||||
|  | # Run: ./screenshot.sh output.png | ||||||
|  | # | ||||||
|  | # Then select a window. It will create a screenshot from that window, | ||||||
|  | # cut (optionally) some pixels (removes the browser bar) and then | ||||||
|  | # resizes it to some maximum width. | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | # input file | ||||||
|  | file=/tmp/screenshot.png | ||||||
|  |  | ||||||
|  | # final output file | ||||||
|  | out=/tmp/screenshot-out.png | ||||||
|  |  | ||||||
|  | # image dimension ratio w:h | ||||||
|  | ratio=${RATIO:-"16:9"} | ||||||
|  | # cut that much from the top to remove browser bar (my firefox settings) | ||||||
|  | top_cut=${TOP_CUT:-85} | ||||||
|  | # maximum width of final image | ||||||
|  | maxw=${MAXW:-1200} | ||||||
|  | # time to wait in secs | ||||||
|  | waitsec=${WAIT_SEC:-3} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #### Main ############ | ||||||
|  | work=/tmp/screenshot-work.png | ||||||
|  |  | ||||||
|  | debug() { | ||||||
|  |     (1>&2 echo "$@") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | scrot -s -c -d $waitsec "$file" 1>&2 | ||||||
|  | cp "$file" "$work" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | read -r w h < <(identify -verbose $file |\ | ||||||
|  |                     grep "Geometry:" | \ | ||||||
|  |                     cut -d':' -f2 | \ | ||||||
|  |                     cut -d'+' -f1 | \ | ||||||
|  |                     tr 'x' ' ' | xargs) | ||||||
|  | debug "Original size: ${w}x${h}" | ||||||
|  |  | ||||||
|  | read nw nh < <(echo $ratio | tr ':' ' ') | ||||||
|  |  | ||||||
|  | # remove browser bar from top | ||||||
|  | ((h=$h - $top_cut)) | ||||||
|  |  | ||||||
|  | # create height to match ratio | ||||||
|  | ((newH=($w * $nh) / $nw)) | ||||||
|  |  | ||||||
|  | if [ $newH -gt $h ]; then | ||||||
|  |     debug "Cropping to $w x $h" | ||||||
|  |     debug "Cannot crop to ratio without reducing width" | ||||||
|  |     convert -crop ${w}x${h}+0+${top_cut} "$work" "$out" | ||||||
|  | else | ||||||
|  |     debug "Cropping to $w x $h" | ||||||
|  |     convert -crop ${w}x${newH}+0+${top_cut} "$work" "$out" | ||||||
|  | fi | ||||||
|  | cp "$out" "$work" | ||||||
|  |  | ||||||
|  | debug "Resize to max width $maxw" | ||||||
|  | convert -resize $maxw "$work" "$out" | ||||||
|  | rm -f "$work" "$file" | ||||||
|  |  | ||||||
|  | if [ -z "$1" ]; then | ||||||
|  |     echo "$out" | ||||||
|  | else | ||||||
|  |     mv "$out" "$1" | ||||||
|  |     echo "$1" | ||||||
|  | fi | ||||||
							
								
								
									
										40
									
								
								website/scripts/screenshot2.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  | # | ||||||
|  | # Uses the `screenshot.sh` script to create one screenshot per theme. | ||||||
|  | # | ||||||
|  | # First sets light theme and takes a screenshot, then sets dark theme | ||||||
|  | # and calls screenshot.sh again | ||||||
|  | # | ||||||
|  | # Might need to fiddle with the xdotool command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | docspell_url=http://localhost:7880 | ||||||
|  | docspell_user=demo | ||||||
|  | docspell_pass=test | ||||||
|  |  | ||||||
|  | screenshot="$(dirname $0)/screenshot.sh" | ||||||
|  |  | ||||||
|  | out_base="$1" | ||||||
|  |  | ||||||
|  | work_dir=$(mktemp -dt screenshot2-script.XXXXXX) | ||||||
|  | export HOME=$work_dir | ||||||
|  | export RATIO="16:9" | ||||||
|  | export WAIT_SEC=4 | ||||||
|  | #export TOP_CUT=400 | ||||||
|  |  | ||||||
|  | dsc write-default-config | ||||||
|  | sed -i "s,http://localhost:7880,$docspell_url,g" $HOME/.config/dsc/config.toml | ||||||
|  |  | ||||||
|  | set_theme() { | ||||||
|  |     dsc login -u $docspell_user --password $docspell_pass 2>&1 > /dev/null | ||||||
|  |     local token=$(cat $HOME/.config/dsc/dsc-token.json | jq -r '.token') | ||||||
|  |     data=$(curl -sSL -H "X-Docspell-Auth: $token" $docspell_url/api/v1/sec/clientSettings/webClient | jq ".uiTheme=\"$1\"") | ||||||
|  |  | ||||||
|  |     curl -sSL -H "X-Docspell-Auth: $token" -XPUT --data "$data" $docspell_url/api/v1/sec/clientSettings/user/webClient | ||||||
|  |     xdotool search --name "Mozilla Firefox" | xargs xdotool windowactivate && xdotool key F5 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | set_theme "Light" | ||||||
|  | $screenshot "${out_base}.png" | ||||||
|  | set_theme "dark" | ||||||
|  | $screenshot "${out_base}_dark.png" | ||||||
| @@ -1,7 +1,8 @@ | |||||||
| let | let | ||||||
|   nixpkgs = builtins.fetchTarball { |   nixpkgs = builtins.fetchTarball { | ||||||
|     #url = "channel:nixos-21.05"; |     #url = "channel:nixos-21.11"; | ||||||
|     url = "https://github.com/NixOS/nixpkgs/archive/e6badb26fc0d238fda2432c45b7dd4e782eb8200.tar.gz"; |     #url = "https://github.com/NixOS/nixpkgs/archive/e6badb26fc0d238fda2432c45b7dd4e782eb8200.tar.gz"; | ||||||
|  |     url = "https://github.com/NixOs/nixpkgs/archive/0f316e4d72daed659233817ffe52bf08e081b5de.tar.gz"; #21.11 | ||||||
|   }; |   }; | ||||||
|   pkgs = import nixpkgs { }; |   pkgs = import nixpkgs { }; | ||||||
| in | in | ||||||
| @@ -11,6 +12,9 @@ with pkgs; | |||||||
|    buildInputs = [ |    buildInputs = [ | ||||||
|      zola |      zola | ||||||
|      yarn |      yarn | ||||||
|  |      sbt | ||||||
|  |      elmPackages.elm | ||||||
|  |      nodejs | ||||||
|      inotifyTools |      inotifyTools | ||||||
|   ]; |   ]; | ||||||
|  } |  } | ||||||
|   | |||||||
| @@ -11,7 +11,13 @@ default_language = "en" | |||||||
|  |  | ||||||
| [markdown] | [markdown] | ||||||
| highlight_code = true | highlight_code = true | ||||||
| highlight_theme = "gruvbox-dark" | #light: ayu-light, OneHalfLight, base16-ocean-light | ||||||
|  | highlight_theme = "css" | ||||||
|  |  | ||||||
|  | highlight_themes_css = [ | ||||||
|  |   { theme = "gruvbox-dark", filename = "syntax-dark.css" }, | ||||||
|  |   { theme = "base16-ocean-light", filename = "syntax-light.css" } | ||||||
|  | ] | ||||||
|  |  | ||||||
| [link_checker] | [link_checker] | ||||||
| skip_prefixes = [ | skip_prefixes = [ | ||||||
|   | |||||||
| @@ -0,0 +1,24 @@ | |||||||
|  | +++ | ||||||
|  | title = "Preproces Scans before upload" | ||||||
|  | [extra] | ||||||
|  | author = "@eresturo" | ||||||
|  | authorLink = "https://github.com/eresturo" | ||||||
|  | +++ | ||||||
|  |  | ||||||
|  | # Preproces Scans before upload | ||||||
|  |  | ||||||
|  | This script scans from the ADF (Automatic Document Feeder), | ||||||
|  | preprocesses it and uploads it to Docspell: | ||||||
|  | [scanadf2docspell](https://github.com/eresturo/scanadf2docspell) | ||||||
|  |  | ||||||
|  | <!-- more --> | ||||||
|  | <figure> | ||||||
|  | <img src="https://github.com/eresturo/scanadf2docspell/raw/main/overview.png"> | ||||||
|  | </figure> | ||||||
|  |  | ||||||
|  | I don't know if this is helpful to other Docspell users, but feel free | ||||||
|  | to link to it in the Docspell documentation. | ||||||
|  |  | ||||||
|  | Any suggestions or missing features? | ||||||
|  |  | ||||||
|  | Sheers eresturo | ||||||
| @@ -0,0 +1,51 @@ | |||||||
|  | +++ | ||||||
|  | title = "Upload directly from the browser or email client" | ||||||
|  | [extra] | ||||||
|  | author = "gandy92" | ||||||
|  | +++ | ||||||
|  |  | ||||||
|  | # Uploading from browser or email client | ||||||
|  |  | ||||||
|  | An alternative approach came to mind to directly upload from a browser | ||||||
|  | or email client that at least works on a Linux system. In case this is | ||||||
|  | interesting for others, I'd like to share it here. | ||||||
|  |  | ||||||
|  | <!-- more --> | ||||||
|  | 1. Create and activate a source in your collective (in this example | ||||||
|  |    MYCOLL); note that path to the file upload (the one with | ||||||
|  |    `/api/v1/open/upload/item/`) | ||||||
|  | 2. Create a file `docspell-upload-MYCOLL` with the following content (replace `UPLOAD_PATH` with the actual path): | ||||||
|  |    ``` | ||||||
|  |    #!/bin/bash | ||||||
|  |    logger -t docspell_upload -- Docspell upload to MYCOLL: "$*" $( | ||||||
|  |    curl -s -XPOST -F file=@"$1" UPLOAD_PATH | ||||||
|  |    ) | ||||||
|  |    ``` | ||||||
|  | 3. Make it executable: `chmod 755 docspell-upload-MYCOLL` | ||||||
|  | 4. Create a file named `docspell-MYCOLL.desktop` with the following | ||||||
|  |    content (note that you need the full path to | ||||||
|  |    `docspell-upload-MYCOLL`): | ||||||
|  |  | ||||||
|  |    ``` | ||||||
|  |    [Desktop Entry] | ||||||
|  |    Exec=PATH_TO_docspell-upload-MYCOLL %F | ||||||
|  |    MimeType=application/pdf;application/x-zip;application/x-zip-compressed;application/zip | ||||||
|  |    Name=Docspell Upload (MYCOLL) | ||||||
|  |    NoDisplay=true | ||||||
|  |    Type=Application | ||||||
|  |    ``` | ||||||
|  | 5. Place the file `docspell-MYCOLL.desktop` in | ||||||
|  |    `$HOME/.local/share/applications/` | ||||||
|  | 6. Configure your browser or mail-reader actions for pdf and zip: They | ||||||
|  |    should always ask what to do rather than opening a link or | ||||||
|  |    attachment with the standard application or save it to disk by | ||||||
|  |    default. Actually, always opening a pdf in the browser is fine, if | ||||||
|  |    this allows to later save the viewed file. | ||||||
|  |  | ||||||
|  | Now, when clicking on a file link or attachment, the browser or email | ||||||
|  | client should ask what to do. You then should be able to choose | ||||||
|  | "Docspell Upload (MYCOLL)" from the list, which will upload the file | ||||||
|  | to your collection. | ||||||
|  |  | ||||||
|  | If anything goes wrong, you can monitor the server response with the | ||||||
|  | command `journalctl -f -t docspell_upload` | ||||||
							
								
								
									
										249
									
								
								website/site/content/blog/2022-01-31_create_post.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,249 @@ | |||||||
|  | +++ | ||||||
|  | title = "Create a new post" | ||||||
|  | [extra] | ||||||
|  | author = "eikek" | ||||||
|  | +++ | ||||||
|  |  | ||||||
|  | # Create a new post | ||||||
|  |  | ||||||
|  | Sharing ideas and tips is very much welcome, if you like you can | ||||||
|  | create a small (or large) post here. You'll need `git` and potentially | ||||||
|  | a `github` account to make this convenient. | ||||||
|  |  | ||||||
|  | <!-- more --> | ||||||
|  |  | ||||||
|  | The contents of this website is maintained in the [<i class="fab fa-github ml-1"></i> git | ||||||
|  | repository](https://github.com/eikek/docspell) in the `website/site` | ||||||
|  | folder. It is build by the static site generator | ||||||
|  | [zola](https://getzola.org) from a set of | ||||||
|  | [markdown](https://www.markdownguide.org/basic-syntax) files. | ||||||
|  |  | ||||||
|  | It is not necessary to know how everything is connected, you only need | ||||||
|  | to edit or create markdown files at some specific location. Here are | ||||||
|  | some proposals how to add or edit pages and getting them published to | ||||||
|  | docspell.org. | ||||||
|  |  | ||||||
|  | ## Where to create the files | ||||||
|  |  | ||||||
|  | The contents of the published website is in the branch `current-docs`. | ||||||
|  | You should base your changes on this branch. | ||||||
|  |  | ||||||
|  | All blog pages go into this directory: `website/site/content/blog/`. | ||||||
|  | In this directory each post is a markdown file named by this pattern: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | <year>-<month>-<day>_title_with_underscores.md | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | For example, this page here is named `2022-01-31_create_post.md`. | ||||||
|  |  | ||||||
|  | ## Write on Github | ||||||
|  |  | ||||||
|  | A very convenient way is to edit and create posts directly on github | ||||||
|  | in the browser. All pages contain a small `Edit` link at the bottom | ||||||
|  | that takes you directly into edit model of the corresponding file on | ||||||
|  | github. | ||||||
|  |  | ||||||
|  | To create a new file on github, you can use this link: | ||||||
|  |  | ||||||
|  | <https://github.com/eikek/docspell/new/current-docs/website/site/content/blog> | ||||||
|  |  | ||||||
|  | It will present a form that lets you create a new file with content. | ||||||
|  | Once you commit this change, the project will be forked into your | ||||||
|  | account and the change is applied to this new fork. Then you can | ||||||
|  | create a pull request into this repository in order to publish it. | ||||||
|  |  | ||||||
|  | Plase see [below](#content) for how to start writing content. | ||||||
|  |  | ||||||
|  | ## Writing locally | ||||||
|  |  | ||||||
|  | The preferred approach is to explicitely fork the repository and clone | ||||||
|  | it to your machine to do the modification. The big advantage is, that | ||||||
|  | you can look at the results while writing. | ||||||
|  |  | ||||||
|  | If you want to see a live view of the page while editing, some tools | ||||||
|  | are required. The easiest way to get these is to install | ||||||
|  | [nix](https://nixos.org/) and run `nix-shell website/shell.nix` to get | ||||||
|  | an environment with all these tools installed. Otherwise install the | ||||||
|  | programs mentioned in `website/shell.nix`, which are: | ||||||
|  | [yarn](https://yarnpkg.com/), [zola](https://getzola.org), | ||||||
|  | [elm](https://elm-lang.org) and [sbt](https://scala-sbt.org). | ||||||
|  |  | ||||||
|  | Then clone the sources to your machine and build the complete site | ||||||
|  | once, so that all assets and required stuff is present: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | sbt website/zolaBuildTest | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Now you can use zola to start the page and watch for changes. The | ||||||
|  | changes are visible immediately without reloading the page in the | ||||||
|  | browser. | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | cd website/site && zola serve | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | This starts a web server on some port (usually `1111`); point your | ||||||
|  | browser to it and navigate to your new page. Whenever changes are | ||||||
|  | saved to the markdown file, the page refreshes automatically. | ||||||
|  |  | ||||||
|  | If styling is changed (in the css files or also sometimes when adding | ||||||
|  | new classes to HTML elements), a rebuild of the site css is necessary. | ||||||
|  | This can be done by running `scripts/run-styles.sh`. Via | ||||||
|  | `scripts/run-styles.sh --watch` it is possible to watch for these | ||||||
|  | changes as well. But it shouldn't be necessary to do large edits to | ||||||
|  | the css. | ||||||
|  |  | ||||||
|  | # Content | ||||||
|  |  | ||||||
|  | ## Front matter | ||||||
|  |  | ||||||
|  | The very beginning of such a markdown file contains some metadata. | ||||||
|  | Start each page with these lines: | ||||||
|  |  | ||||||
|  | ```markdown | ||||||
|  | +++ | ||||||
|  | title = "Title of the post" | ||||||
|  | [extra] | ||||||
|  | author = "<your name>" | ||||||
|  | authorLink = "https://some-url" | ||||||
|  | +++ | ||||||
|  |  | ||||||
|  | # First heading… | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | The front matter is the first part enclosed in `+++`. See | ||||||
|  | [zola](https://www.getzola.org/documentation/content/page/) | ||||||
|  | documentation for more details. | ||||||
|  |  | ||||||
|  | The `author` and `authorLink` setting is optional. You can leave out | ||||||
|  | the complete `[extra]` section. If `authorLink`is defined, the author | ||||||
|  | is rendered as a link to that URL. If `author` is missing, it defaults | ||||||
|  | to "_Unknown_". | ||||||
|  |  | ||||||
|  | ## Elements | ||||||
|  |  | ||||||
|  | The content is styled automatically and the post is added to the list | ||||||
|  | on the main blog page. Additional to the standard markdown formatting, | ||||||
|  | there are some more usefull elements. | ||||||
|  |  | ||||||
|  | ### Linking | ||||||
|  |  | ||||||
|  | If you want to link to an internal page, use markdown links where the | ||||||
|  | path is formatted like this: | ||||||
|  |  | ||||||
|  | ```markdown | ||||||
|  | [link title](@/path/to/markdown_file.md) | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Using the `@/path` style, zola generates the correct final link (and | ||||||
|  | checks for dead links). | ||||||
|  |  | ||||||
|  | ### Info and warning boxes | ||||||
|  |  | ||||||
|  | There are small templates available to format a basic info or warning | ||||||
|  | box message. | ||||||
|  |  | ||||||
|  | ```markdown | ||||||
|  | {%/* infobubble(title="My Title") */%} | ||||||
|  | Your content here …. | ||||||
|  | {%/* end */%} | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | For a box more styled like a warning, replace `info` with `warning`. | ||||||
|  |  | ||||||
|  | ```markdown | ||||||
|  | {%/* warningbubble(title="My Title") */%} | ||||||
|  | Your content here …. | ||||||
|  | {%/* end */%} | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | This will render into: | ||||||
|  |  | ||||||
|  | {% infobubble(title="My Title") %} | ||||||
|  | Your content here …. | ||||||
|  | {% end %} | ||||||
|  |  | ||||||
|  | {% warningbubble(title="My Title") %} | ||||||
|  | Your content here …. | ||||||
|  | {% end %} | ||||||
|  |  | ||||||
|  | ### Summary | ||||||
|  |  | ||||||
|  | In order to get a decent summary in the list of posts, you need to set | ||||||
|  | a marker in your file. Place a line containing only | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | <!-- more --> | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | into your file and everything before it will be rendered as a summary | ||||||
|  | on the blog listing. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### Buttons | ||||||
|  |  | ||||||
|  | Styled buttons can be created using HTML inside the markdown file: | ||||||
|  |  | ||||||
|  | ```markdown | ||||||
|  | <a class="no-default button1" href="#">Click!</a> | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Turns into: | ||||||
|  |  | ||||||
|  | <a class="no-default button1" href="#">Click!</a> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### Images | ||||||
|  |  | ||||||
|  | In image to appear on the whole page, use HTML with a `figure` tag: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | <figure> | ||||||
|  |   <img src="image-url.jpg"> | ||||||
|  | </figure> | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | <figure> | ||||||
|  |   <img src="/img/jesse-gardner-EqdpXeemf58-unsplash.jpg" > | ||||||
|  | </figure> | ||||||
|  |  | ||||||
|  | The site has a light and dark mode and sometimes it's nice to provide | ||||||
|  | images for both variants. You can use HTML for this and a specific | ||||||
|  | class per theme: | ||||||
|  |  | ||||||
|  | ```html | ||||||
|  | <figure class="dark-block"> | ||||||
|  |     <img src="dark-image.jpg" > | ||||||
|  | </figure> | ||||||
|  | <figure class="light-block"> | ||||||
|  |     <img src="light-image.jpg" > | ||||||
|  | </figure> | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | See the effect when changing the theme: | ||||||
|  |  | ||||||
|  | <figure class="dark-block"> | ||||||
|  |     <img src="/img/tersius-van-rhyn-xcQWMPm9fG8-unsplash.jpg" > | ||||||
|  | </figure> | ||||||
|  | <figure class="light-block"> | ||||||
|  |     <img src="/img/cassie-boca-x-tbVqkfQCU-unsplash.jpg" > | ||||||
|  | </figure> | ||||||
|  |  | ||||||
|  | This can be done via a template if the file is next to the markdown | ||||||
|  | file in the same directory: | ||||||
|  |  | ||||||
|  | ```markdown | ||||||
|  | {{/* figure2(light="light-image.jpg", dark="dark-image.jpg") */}} | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | <div class="text-sm text-right opacity-80"> | ||||||
|  | Pictures are from <a href="https://unsplash.com" target="_blank">Unsplash</a>. | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | # Publish | ||||||
|  |  | ||||||
|  | Open a pull request against the `current-docs` branch. When the pull | ||||||
|  | request is merged, the publishing process starts automatically and the | ||||||
|  | content is available minutes after. | ||||||
							
								
								
									
										15
									
								
								website/site/content/blog/_index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | |||||||
|  | +++ | ||||||
|  | title = "Main" | ||||||
|  | description = "Random collection of stuff around Docspell" | ||||||
|  | template = "blog.html" | ||||||
|  | page_template = "blog_page.html" | ||||||
|  | sort_by = "date" | ||||||
|  | insert_anchor_links = "right" | ||||||
|  | +++ | ||||||
|  |  | ||||||
|  | # Blog | ||||||
|  |  | ||||||
|  | This is a place to collect random tips and knowledge around Docspell. | ||||||
|  | This is organized as a log, where entries can be added by whoever | ||||||
|  | likes to share something. Check [this | ||||||
|  | page](@/blog/2022-01-31_create_post.md) for creating content here. | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| +++ |  | ||||||
| redirect_to = "/docs" |  | ||||||
| +++ |  | ||||||
| @@ -1,9 +1,150 @@ | |||||||
| +++ | +++ | ||||||
| title = "Overview" | title = "Documentation" | ||||||
| template = "overview.html" | template = "docs.html" | ||||||
|  | page_template = "docs.html" | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Note |  | ||||||
|  |  | ||||||
| This content is not rendered. Everything is in the template. | # Introduction | ||||||
|  |  | ||||||
|  | Docspell aims to be a simple yet effective document organizer that | ||||||
|  | makes stowing documents away very quick and finding them later | ||||||
|  | reliable (and also fast). It is a bit opinionated and more targeted | ||||||
|  | for home use and small/medium organizations. | ||||||
|  |  | ||||||
|  | In contrast to many DMS, the main focus is not so much to provide all | ||||||
|  | kinds of features to manually create organizational structures, like | ||||||
|  | folder hierarchies, where you place the documents yourself. The | ||||||
|  | approach is to leave it as a big pile of documents, but extract and | ||||||
|  | attach metadata from each document. These are mainly properties that | ||||||
|  | emerge from the document itself. The reason is that this is possible | ||||||
|  | to automate. This makes it very simple to *add* documents, because | ||||||
|  | there is no time spent to think about where to put it. And it is | ||||||
|  | possible to apply different structures on top later, like show first | ||||||
|  | all documents of a specific correspondent, then all with tag | ||||||
|  | 'invoice', etc. If these properties are attached to all documents, it | ||||||
|  | is really easy to find a document. It even can be combined with | ||||||
|  | fulltext search for the, hopefully rare, desperate cases. | ||||||
|  |  | ||||||
|  | Of course, it is also possible to add custom properties and arbitrary | ||||||
|  | tags. | ||||||
|  |  | ||||||
|  | Docspell analyzes the text to find metadata automatically. It can | ||||||
|  | learn from existing data and can apply | ||||||
|  | [NLP](https://en.wikipedia.org/wiki/Natural_language_processing) | ||||||
|  | techniques to support this. This metadata must be maintained manually | ||||||
|  | in the application. Docspell looks for candidates for: | ||||||
|  |  | ||||||
|  | - Correspondents | ||||||
|  | - Concerned person or things | ||||||
|  | - A date and due date | ||||||
|  | - Tags | ||||||
|  |  | ||||||
|  | For tags, it sets all that it thinks do apply. For the others, it will | ||||||
|  | propose a few candidates and sets the most likely one to your item. | ||||||
|  |  | ||||||
|  | This might be wrong, so it is recommended to curate the results. | ||||||
|  | However, very often the correct one is either set or within the | ||||||
|  | proposals where you fix it by a single click. | ||||||
|  |  | ||||||
|  | Besides these properties, there are more metadata you can use to | ||||||
|  | organize your files, for example custom fields, folders and notes. | ||||||
|  |  | ||||||
|  | Docspell is also for programmers. Everything is available via a REST | ||||||
|  | or HTTP api and can be easily used within your own scripts and tools, | ||||||
|  | for example using `curl`. There are also features for "advanced use" | ||||||
|  | and many configuration options. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Components | ||||||
|  |  | ||||||
|  | Docspell consists of multiple components that run in separate | ||||||
|  | processes: | ||||||
|  |  | ||||||
|  | - REST server | ||||||
|  | - JOEX, short for *job executor* | ||||||
|  | - Fulltext Search Index (optional, currently Apache SOLR) | ||||||
|  |  | ||||||
|  | The REST server provides the Api and the web application. The web | ||||||
|  | application is a | ||||||
|  | [SPA](https://en.wikipedia.org/wiki/Single-page_application) written | ||||||
|  | in [Elm](https://elm-lang.org) and is a client to the REST api. All | ||||||
|  | features are available via a http/rest api. | ||||||
|  |  | ||||||
|  | The *joex* is the component that does the “heavy work”, executing | ||||||
|  | long-running tasks, like processing files or importing your mails | ||||||
|  | periodically. While the joex component also exposes a small REST api | ||||||
|  | for controlling it, the main user interface is all inside the rest | ||||||
|  | server api. | ||||||
|  |  | ||||||
|  | The rest server and the job executor can be started multiple times in | ||||||
|  | order to scale out. It must be ensured, that all connect to the same | ||||||
|  | database. And it is also recommended (though not strictly required), | ||||||
|  | that all components can reach each other. | ||||||
|  |  | ||||||
|  | The fulltext search index is another separate component, where | ||||||
|  | currently only [SOLR](https://solr.apache.org) is supported. | ||||||
|  | Fulltext search is optional, so the SOLR component is not required if | ||||||
|  | docspell is run without fulltext search support. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Terms | ||||||
|  |  | ||||||
|  | In order to better understand the following pages, some terms are | ||||||
|  | explained. | ||||||
|  |  | ||||||
|  | ## Item | ||||||
|  |  | ||||||
|  | An *item* is roughly your document, only that an item may span | ||||||
|  | multiple files, which are called *attachments*. An item has *meta | ||||||
|  | data* associated: | ||||||
|  |  | ||||||
|  | - a *correspondent*: the other side of the communication. It can be | ||||||
|  |   an organization or a person. | ||||||
|  | - a *concerning person* or *equipment*: a person or thing that | ||||||
|  |   this item is about. Maybe it is an insurance contract about your | ||||||
|  |   car. | ||||||
|  | - *tag*: an item can be tagged with one or more tags (or labels). A | ||||||
|  |   tag can have a *category*. This is intended for grouping tags, for | ||||||
|  |   example a category `doctype` could be used to group tags like | ||||||
|  |   `bill`, `contract`, `receipt` etc. Usually an item is not tagged | ||||||
|  |   with more than one tag of a category. | ||||||
|  | - a *folder*: a folder is similiar to a tag, but an item can only be | ||||||
|  |   in exactly one folder (or none). Furthermore folders allow to | ||||||
|  |   associate users, so that items are only visible to the users who are | ||||||
|  |   members of a folder. | ||||||
|  | - an *item date*: this is the date of the document – if this is not | ||||||
|  |   set, the created date of the item is used. | ||||||
|  | - a *due date*: an optional date indicating that something has to be | ||||||
|  |   done (e.g. paying a bill, submitting it) about this item until this | ||||||
|  |   date | ||||||
|  | - a *direction*: one of "incoming" or "outgoing" | ||||||
|  | - a *name*: some item name, defaults to the file name of the | ||||||
|  |   attachments | ||||||
|  | - some *notes*: arbitrary descriptive text. You can use markdown | ||||||
|  |   here, which is properly formatted in the web application. | ||||||
|  |  | ||||||
|  | ## Collective | ||||||
|  |  | ||||||
|  | The users of the application are part of a *collective*. A | ||||||
|  | *collective* is a group of users that share access to the same | ||||||
|  | items. The account name is therefore comprised of a *collective name* | ||||||
|  | and a *user name*. | ||||||
|  |  | ||||||
|  | All users of a collective are equal; they have same permissions to | ||||||
|  | access all items. The items don't belong to a user, but to the | ||||||
|  | collective. | ||||||
|  |  | ||||||
|  | That means, to identify yourself when signing in, you have to give the | ||||||
|  | collective name and your user name. By default it is separated by a | ||||||
|  | slash `/`, for example `smith/john`. If your user name is the same as | ||||||
|  | the collective name, you can omit one; so `smith/smith` can be | ||||||
|  | abbreviated to just `smith`. | ||||||
|  |  | ||||||
|  | By default, all users can see all items of their collective. A | ||||||
|  | *folder* can be used to implement other visibilities: Every user can | ||||||
|  | create a folder and associate members. It is possible to put items in | ||||||
|  | these folders and docspell shows only items that are either in no | ||||||
|  | specific folder or in a folder where the current user is owner or | ||||||
|  | member. | ||||||
|   | |||||||
| @@ -3,9 +3,6 @@ title = "Api" | |||||||
| description = "Contains documentation about the REST API." | description = "Contains documentation about the REST API." | ||||||
| weight = 70 | weight = 70 | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| template = "pages.html" | template = "docs.html" | ||||||
| sort_by = "weight" | sort_by = "weight" | ||||||
| redirect_to = "docs/api/intro" |  | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| No Content |  | ||||||
|   | |||||||
| @@ -3,10 +3,10 @@ title = "Api Introduction" | |||||||
| description = "Api Basics" | description = "Api Basics" | ||||||
| weight = 10 | weight = 10 | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| [extra] |  | ||||||
| mktoc = true |  | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Api | ||||||
|  |  | ||||||
| Docspell is designed as a REST server that uses JSON to exchange | Docspell is designed as a REST server that uses JSON to exchange | ||||||
| data. The REST api can be used to integrate docspell into your | data. The REST api can be used to integrate docspell into your | ||||||
| workflow. | workflow. | ||||||
|   | |||||||
| @@ -3,10 +3,10 @@ title = "Upload Request" | |||||||
| description = "Describes the upload request" | description = "Describes the upload request" | ||||||
| weight = 20 | weight = 20 | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| [extra] |  | ||||||
| mktoc = true |  | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Upload Request | ||||||
|  |  | ||||||
| Uploads of files to docspell are always processed the same way, no | Uploads of files to docspell are always processed the same way, no | ||||||
| matter if coming from a source, the integration endpoint or from the | matter if coming from a source, the integration endpoint or from the | ||||||
| webapp. | webapp. | ||||||
|   | |||||||
| @@ -3,10 +3,11 @@ title = "Configuration" | |||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| description = "Describes the configuration file and shows all default settings." | description = "Describes the configuration file and shows all default settings." | ||||||
| weight = 40 | weight = 40 | ||||||
| [extra] | template = "docs.html" | ||||||
| mktoc = true |  | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Configuration | ||||||
|  |  | ||||||
| Docspell's executables (restserver and joex) can take one argument – a | Docspell's executables (restserver and joex) can take one argument – a | ||||||
| configuration file. If that is not given, the defaults are used, | configuration file. If that is not given, the defaults are used, | ||||||
| overriden by environment variables. A config file overrides default | overriden by environment variables. A config file overrides default | ||||||
|   | |||||||
| @@ -4,11 +4,14 @@ description = "Contains some ADRs, which are internal notes on decisions made." | |||||||
| weight = 300 | weight = 300 | ||||||
| sort_by = "weight" | sort_by = "weight" | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| template = "pages.html" | template = "docs.html" | ||||||
|  | page_template = "docs.html" | ||||||
| [extra] | [extra] | ||||||
| mktoc = true | page_list = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # ADR | ||||||
|  |  | ||||||
| This contains a list of ADRs, most of them are from very early. It | This contains a list of ADRs, most of them are from very early. It | ||||||
| often just contains notes that could go nowhere else, but still should | often just contains notes that could go nowhere else, but still should | ||||||
| be captured. | be captured. | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ title = "Building Docspell" | |||||||
| weight = 0 | weight = 0 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Building | ||||||
|  |  | ||||||
| You must install [sbt](https://scala-sbt.org), | You must install [sbt](https://scala-sbt.org), | ||||||
| [nodejs](https://www.npmjs.com/get-npm) (for the `npm` command) and | [nodejs](https://www.npmjs.com/get-npm) (for the `npm` command) and | ||||||
|   | |||||||
| @@ -3,7 +3,9 @@ title = "Tips & Setup" | |||||||
| weight = 20 | weight = 20 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Starting Servers with `reStart` | # Setup / Tips | ||||||
|  |  | ||||||
|  | ## Starting Servers with `reStart` | ||||||
|  |  | ||||||
| When developing, it's very convenient to use the [revolver sbt | When developing, it's very convenient to use the [revolver sbt | ||||||
| plugin](https://github.com/spray/sbt-revolver). Start the sbt console | plugin](https://github.com/spray/sbt-revolver). Start the sbt console | ||||||
| @@ -29,7 +31,7 @@ sbt:docspell-root> reStart | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
| # Custom config file | ## Custom config file | ||||||
|  |  | ||||||
| The sbt build is setup such that a file `dev.conf` in the directory | The sbt build is setup such that a file `dev.conf` in the directory | ||||||
| `local` (at root of the source tree) is picked up as config file, if | `local` (at root of the source tree) is picked up as config file, if | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ title = "Translating Web-UI" | |||||||
| weight = 10 | weight = 10 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # UI Translation | ||||||
|  |  | ||||||
| Help with translating the web-ui is greatly appreciated. I can only | Help with translating the web-ui is greatly appreciated. I can only | ||||||
| provide translations for English and German, and these may be wrong - | provide translations for English and German, and these may be wrong - | ||||||
| @@ -16,7 +17,7 @@ messages. | |||||||
|  |  | ||||||
| This guide assumes no knowledge about Elm at all. | This guide assumes no knowledge about Elm at all. | ||||||
|  |  | ||||||
| # TL;DR | ## TL;DR | ||||||
|  |  | ||||||
| If you are already familiar with Elm, here is the TL;DR: | If you are already familiar with Elm, here is the TL;DR: | ||||||
|  |  | ||||||
| @@ -92,7 +93,7 @@ sbt:docspell-root> make | |||||||
| This will take a while, you need to wait until this is finished. | This will take a while, you need to wait until this is finished. | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Start the application | ### Start the application | ||||||
|  |  | ||||||
| If sbt is not started, start sbt from within the source root. Also | If sbt is not started, start sbt from within the source root. Also | ||||||
| export the `DOCSPELL_ENV` variable *before* starting sbt: | export the `DOCSPELL_ENV` variable *before* starting sbt: | ||||||
|   | |||||||
| @@ -3,8 +3,8 @@ title = "FAQ" | |||||||
| weight = 100 | weight = 100 | ||||||
| description = "Frequently asked questions." | description = "Frequently asked questions." | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
|  | template = "docs.html" | ||||||
| [extra] | [extra] | ||||||
| mktoc = true |  | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # FAQ | # FAQ | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| +++ | +++ | ||||||
| title = "Features and Limitations" | title = "Features and Limitations" | ||||||
| weight = 10 | weight = 9 | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| description = "A list of features and limitations." | description = "A list of features and limitations." | ||||||
|  | template = "docs.html" | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Features | # Features | ||||||
| @@ -20,7 +21,7 @@ description = "A list of features and limitations." | |||||||
| - A powerful [query language](@/docs/query/_index.md) to find | - A powerful [query language](@/docs/query/_index.md) to find | ||||||
|   documents |   documents | ||||||
| - use [bookmarks](@/docs/webapp/bookmarks.md) to save more complex queries | - use [bookmarks](@/docs/webapp/bookmarks.md) to save more complex queries | ||||||
| - customizable [dashboads](@/docs/webapp/dashboards.md) as the main page | - customizable [dashboards](@/docs/webapp/dashboards.md) as the main page | ||||||
| - Non-destructive: all your uploaded files are never modified and can | - Non-destructive: all your uploaded files are never modified and can | ||||||
|   always be downloaded untouched |   always be downloaded untouched | ||||||
| - Organize files using tags, folders, [Custom | - Organize files using tags, folders, [Custom | ||||||
| @@ -80,8 +81,6 @@ description = "A list of features and limitations." | |||||||
|     files, watch folders and many more! |     files, watch folders and many more! | ||||||
|   - [Android App](@/docs/tools/android.md) to quickly upload files |   - [Android App](@/docs/tools/android.md) to quickly upload files | ||||||
|     from your android devices |     from your android devices | ||||||
|   - [Firefox plugin](@/docs/tools/browserext.md): right click on a |  | ||||||
|     link and send the file to docspell |  | ||||||
|   - [SMTP Gateway](@/docs/tools/smtpgateway.md): Setup a SMTP server |   - [SMTP Gateway](@/docs/tools/smtpgateway.md): Setup a SMTP server | ||||||
|     that delivers mails directly to docspell. |     that delivers mails directly to docspell. | ||||||
| - License: AGPLv3 | - License: AGPLv3 | ||||||
|   | |||||||
| @@ -1,12 +1,15 @@ | |||||||
| +++ | +++ | ||||||
| title = "Feed Data into Docspell" | title = "Feed Data into Docspell" | ||||||
| weight = 5 | weight = 8 | ||||||
| description = "Shows several ways for getting data into Docspell." | description = "Shows several ways for getting data into Docspell." | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
|  | template = "docs.html" | ||||||
| [extra] | [extra] | ||||||
| mktoc = true | mktoc = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Documents → Docspell | ||||||
|  |  | ||||||
| One of the main goals is to stow documents away quickly. | One of the main goals is to stow documents away quickly. | ||||||
|  |  | ||||||
| Docspell makes no assumptions about where your documents are. It | Docspell makes no assumptions about where your documents are. It | ||||||
| @@ -20,19 +23,19 @@ So the idea is to have most flexibility – that is, it is up to you how | |||||||
| documents arrive. Of course, there is something prepared: | documents arrive. Of course, there is something prepared: | ||||||
|  |  | ||||||
|  |  | ||||||
| # Upload in Webapp | ## Upload in Webapp | ||||||
|  |  | ||||||
| This is the simplest way, but also the least flexible. You can just | This is the simplest way, but also the least flexible. You can just | ||||||
| login and go to the upload page to submit files. | login and go to the upload page to submit files. | ||||||
|  |  | ||||||
|  |  | ||||||
| {{ figure(file="web-upload.png") }} | {{ figure2(light="web-upload.png", dark="web-upload_dark.png") }} | ||||||
|  |  | ||||||
| This requires to login at the webapp. Since this is complicated from | This requires to login at the webapp. Since this is complicated from | ||||||
| other applications, you can create custom hard-to-guess endpoints to | other applications, you can create custom hard-to-guess endpoints to | ||||||
| use with the following options. | use with the following options. | ||||||
|  |  | ||||||
| # Scanners / Watch Directories | ## Scanners / Watch Directories | ||||||
|  |  | ||||||
| If you have a (document) scanner (or think about getting one), it can | If you have a (document) scanner (or think about getting one), it can | ||||||
| usually be configured to place scanned documents as image or PDF files | usually be configured to place scanned documents as image or PDF files | ||||||
| @@ -54,10 +57,10 @@ your scanner is connected to your computer. This can create nice pdf | |||||||
| files from scanners with ADF, applying corrections and sending them to | files from scanners with ADF, applying corrections and sending them to | ||||||
| docspell. | docspell. | ||||||
|  |  | ||||||
| {{ buttonright(classes="is-primary ", href="/docs/tools/cli#watch-a-directory", text="More") }} | {{ buttonright(href="/docs/tools/cli#watch-a-directory", text="More") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| # Android | ## Android | ||||||
|  |  | ||||||
| There is an [android | There is an [android | ||||||
| client](https://github.com/docspell/android-client) provided that lets | client](https://github.com/docspell/android-client) provided that lets | ||||||
| @@ -71,42 +74,40 @@ into the Share-With menu and uploads the file to Docspell. | |||||||
| This is especially useful to quickly upload small things like shopping | This is especially useful to quickly upload small things like shopping | ||||||
| receipts. | receipts. | ||||||
|  |  | ||||||
| <div class="columns is-centered"> | <div class="grid grid-cols-2 gap-8 divide-x "> | ||||||
|   <div class="column is-one-third"> |     <div class="flex items-center justify-center"> | ||||||
|     <img src="/docs/tools/screenshot-share.jpg"> |  | ||||||
|   </div> |  | ||||||
|   <div class="column is-one-third"> |  | ||||||
|     <img src="/docs/tools/screenshot-uploading.jpg"> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| <div class="columns is-vcentered is-centered"> |  | ||||||
|     <div class="column is-one-third"> |  | ||||||
|         <a href="https://f-droid.org/packages/org.docspell.docspellshare"> |         <a href="https://f-droid.org/packages/org.docspell.docspellshare"> | ||||||
|             <img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" |             <img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" | ||||||
|                  alt="Get it on F-Droid"/> |                  alt="Get it on F-Droid" | ||||||
|  |                  class="w-56" | ||||||
|  |                  /> | ||||||
|         </a> |         </a> | ||||||
|     </div> |     </div> | ||||||
|     <div class="column is-one-third"> |     <div class="flex items-center justify-center text-xl"> | ||||||
|     Download the APK from <a href="https://github.com/docspell/android-client/releases/latest">here</a> |         <i class="fa fa-download mr-2"></i> | ||||||
|  |         <span> | ||||||
|  |            <a href="https://github.com/docspell/android-client/releases/latest">Download the APK</a> | ||||||
|  |         </span> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| {{ buttonright(classes="is-primary ", href="/docs/tools/android", text="More") }} | {{ buttonright(href="/docs/tools/android", text="More") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| # Poll E-Mails | ## Poll E-Mails | ||||||
|  |  | ||||||
| Your mailbox can be polled periodically to import mails. For example, | Your mailbox can be polled periodically to import mails. For example, | ||||||
| create a dedicated folder in your e-mail client and move mails in | create a dedicated folder in your e-mail client and move mails in | ||||||
| there that you want to push to Docspell. You can then define a | there that you want to push to Docspell. You can then define a | ||||||
| recurring job, that looks into this folders and imports the mails. | recurring job, that looks into this folders and imports the mails. | ||||||
|  |  | ||||||
| {{ figure(file="scanmailbox.png") }} | {{ figure2(light="scanmailbox.png", dark="scanmailbox_dark.png") }} | ||||||
|  |  | ||||||
| {{ buttonright(classes="is-primary ", href="/docs/webapp/scanmailbox", text="More") }} | {{ buttonright(href="/docs/webapp/scanmailbox", text="More") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| # E-Mail Server | ## E-Mail Server | ||||||
|  |  | ||||||
| This is a little more involved, but can be quite nice. A SMTP server | This is a little more involved, but can be quite nice. A SMTP server | ||||||
| can be setup that simply uploads incoming mails to Docspell (using | can be setup that simply uploads incoming mails to Docspell (using | ||||||
| @@ -120,29 +121,18 @@ part in Docspell to upload the files to the correct account. | |||||||
| There is a docker container prepared to get started. Click below to | There is a docker container prepared to get started. Click below to | ||||||
| read more. | read more. | ||||||
|  |  | ||||||
| {{ buttonright(classes="is-primary ", href="/docs/tools/smtpgateway", text="More") }} | {{ buttonright(href="/docs/tools/smtpgateway", text="More") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| # Command-Line | ## Command-Line | ||||||
|  |  | ||||||
| I like to use the command line, and so there is a cli that can be used | I like to use the command line, and so there is a cli that can be used | ||||||
| for some tasks, for example uploading files. Below is a quick demo, it | for some tasks, for example uploading files. Below is a quick demo, it | ||||||
| supports many more options, see the link below for details. | supports many more options, see the link below for details. | ||||||
|  |  | ||||||
| <div class="columns is-centered is-full-width"> | <figure> | ||||||
|   <div class="column"> |  | ||||||
|   <script id="asciicast-427679" src="https://asciinema.org/a/427679.js" async></script> |   <script id="asciicast-427679" src="https://asciinema.org/a/427679.js" async></script> | ||||||
|   </div> | </figure> | ||||||
| </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| {{ buttonright(classes="is-primary ", href="/docs/tools/cli", text="More") }} | {{ buttonright(href="/docs/tools/cli", text="More") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| # Browser Extension |  | ||||||
|  |  | ||||||
| For Firefox, there is a browser extension that creates a context-menu |  | ||||||
| entry if you right-click on a link. It then downloads the file to your |  | ||||||
| disk and uploads it to Docspell. |  | ||||||
|  |  | ||||||
| {{ buttonright(classes="is-primary ", href="/docs/tools/browserext", text="More") }} |  | ||||||
|   | |||||||
| Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 177 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/feed/scanmailbox_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 180 KiB | 
| Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 190 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/feed/web-upload_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 188 KiB | 
| @@ -1,9 +1,10 @@ | |||||||
| +++ | +++ | ||||||
| title = "Installation and Deployment" | title = "Installation" | ||||||
| description = "There are multiple ways to install Docspell. This section contains detailed instructions." | description = "There are multiple ways to install Docspell. This section contains detailed instructions." | ||||||
| weight = 30 | weight = 5 | ||||||
| sort_by = "weight" | sort_by = "weight" | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| template = "pages.html" | template = "docs.html" | ||||||
|  | page_template = "docs.html" | ||||||
| redirect_to = "/docs/install/quickstart" | redirect_to = "/docs/install/quickstart" | ||||||
| +++ | +++ | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ title = "Docker" | |||||||
| weight = 20 | weight = 20 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| ## Docker Images | # Docker Images | ||||||
|  |  | ||||||
| The docker images are at | The docker images are at | ||||||
| [hub.docker.com](https://hub.docker.com/u/docspell). The `latest` tag | [hub.docker.com](https://hub.docker.com/u/docspell). The `latest` tag | ||||||
| @@ -29,7 +29,7 @@ release page. The images contain all the necessary | |||||||
|   is used to watch a directory for uploading files. This runs the `dsc |   is used to watch a directory for uploading files. This runs the `dsc | ||||||
|   watch` command. |   watch` command. | ||||||
|  |  | ||||||
| ### Examples | ## Examples | ||||||
|  |  | ||||||
| These examples use `docker run` to start the restserver and | These examples use `docker run` to start the restserver and | ||||||
| jobexecutor. Both must be connected to the same database. For this | jobexecutor. Both must be connected to the same database. For this | ||||||
| @@ -127,7 +127,7 @@ fulltext search. For a more sophisticated docker setup, use | |||||||
| appropriate tools, for example `docker-compose` which is explained | appropriate tools, for example `docker-compose` which is explained | ||||||
| below. | below. | ||||||
|  |  | ||||||
| ## Docker Compose | # Docker Compose | ||||||
|  |  | ||||||
| There is a [docker-compose](https://docs.docker.com/compose/) setup | There is a [docker-compose](https://docs.docker.com/compose/) setup | ||||||
| available in the `/docker/docker-compose` folder. This setup is | available in the `/docker/docker-compose` folder. This setup is | ||||||
| @@ -135,8 +135,8 @@ similiar to the example above, but adding fulltext search and a | |||||||
| PostgreSQL database by using just one command. It's only a few steps | PostgreSQL database by using just one command. It's only a few steps | ||||||
| to get started. | to get started. | ||||||
|  |  | ||||||
| ### Start Docspell | ## Start Docspell | ||||||
| #### 1. Get the docker-compose files | ### 1. Get the docker-compose files | ||||||
|  |  | ||||||
| There are two options. You can clone the whole repository: | There are two options. You can clone the whole repository: | ||||||
|  |  | ||||||
| @@ -159,7 +159,7 @@ You can choose any directory instead of | |||||||
| make the rest of the guide work for both ways of obtaining the | make the rest of the guide work for both ways of obtaining the | ||||||
| docker-compose file. | docker-compose file. | ||||||
|  |  | ||||||
| #### 2. Run `docker-compose up` | ### 2. Run `docker-compose up` | ||||||
|  |  | ||||||
| Change into the new `docker-compose` directory, for example: | Change into the new `docker-compose` directory, for example: | ||||||
|  |  | ||||||
| @@ -210,7 +210,7 @@ command: | |||||||
| to the service definition (or add it to an existing `command:` | to the service definition (or add it to an existing `command:` | ||||||
| section). | section). | ||||||
|  |  | ||||||
| ### Override this setup | ## Override this setup | ||||||
|  |  | ||||||
| If you want to change this setup, you can simply use your own compose | If you want to change this setup, you can simply use your own compose | ||||||
| file or add a `docker-compose.override.yml` that allows to amend | file or add a `docker-compose.override.yml` that allows to amend | ||||||
| @@ -251,7 +251,7 @@ volumes: | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
| ### Upgrading | ## Upgrading | ||||||
|  |  | ||||||
| Since [downgrading](@/docs/install/downgrading.md) is not supported, | Since [downgrading](@/docs/install/downgrading.md) is not supported, | ||||||
| it is recommended to backup your database before upgrading. Should | it is recommended to backup your database before upgrading. Should | ||||||
| @@ -267,7 +267,7 @@ $ docker-compose pull | |||||||
| $ docker-compose up --force-recreate --build -d | $ docker-compose up --force-recreate --build -d | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Backups | ## Backups | ||||||
|  |  | ||||||
| When running the docker compose setup, you can use the following to | When running the docker compose setup, you can use the following to | ||||||
| backup the database. | backup the database. | ||||||
|   | |||||||
| @@ -3,7 +3,9 @@ title = "Downgrading" | |||||||
| weight = 37 | weight = 37 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| {% infobubble(mode="info", title="⚠ Please note") %} | # Downgrading | ||||||
|  |  | ||||||
|  | {% warningbubble(title="Note") %} | ||||||
| Downgrading is currently not supported! | Downgrading is currently not supported! | ||||||
|  |  | ||||||
| It is not safe to install a previous version, because the database | It is not safe to install a previous version, because the database | ||||||
|   | |||||||
| @@ -3,24 +3,23 @@ title = "Download & Run" | |||||||
| weight = 22 | weight = 22 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Download and Run | ||||||
|  |  | ||||||
| You can install via zip or deb archives. Please see the | You can install via zip or deb archives. Please see the | ||||||
| [prerequisites](@/docs/install/prereq.md) first. | [prerequisites](@/docs/install/prereq.md) first. | ||||||
|  |  | ||||||
| ## Using zip files | ## Using zip files | ||||||
|  |  | ||||||
| You need to download the two files: | 1. Download the two files: | ||||||
|  |    - <a href="https://github.com/eikek/docspell/releases/download/v{{version()}}/docspell-restserver-{{version()}}.zip">docspell-restserver-{{version()}}.zip</a> | ||||||
| - [docspell-restserver-{{version()}}.zip](https://github.com/eikek/docspell/releases/download/v{{version()}}/docspell-restserver-{{version()}}.zip) |    - <a href="https://github.com/eikek/docspell/releases/download/v{{version()}}/docspell-joex-{{version()}}.zip">docspell-joex-{{version()}}.zip</a> | ||||||
| - [docspell-joex-{{version()}}.zip](https://github.com/eikek/docspell/releases/download/v{{version()}}/docspell-joex-{{version()}}.zip) | 2. Unzip both files: | ||||||
|  |  | ||||||
|  |  | ||||||
| 1. Unzip both files: |  | ||||||
|    ``` bash |    ``` bash | ||||||
|    $ unzip docspell-*.zip |    $ unzip docspell-*.zip | ||||||
|    ``` |    ``` | ||||||
| 2. Open two terminal windows and navigate to the the directory | 3. Open two terminal windows and navigate to the the directory | ||||||
|    containing the zip files. |    containing the zip files. | ||||||
| 3. Start both components executing: | 4. Start both components executing: | ||||||
|    ``` bash |    ``` bash | ||||||
|    $ ./docspell-restserver*/bin/docspell-restserver |    $ ./docspell-restserver*/bin/docspell-restserver | ||||||
|    ``` |    ``` | ||||||
| @@ -29,8 +28,8 @@ You need to download the two files: | |||||||
|    $ ./docspell-joex*/bin/docspell-joex |    $ ./docspell-joex*/bin/docspell-joex | ||||||
|    ``` |    ``` | ||||||
|    in the other. |    in the other. | ||||||
| 4. Point your browser to: <http://localhost:7880/app> | 5. Point your browser to: <http://localhost:7880/app> | ||||||
| 5. Register a new account, sign in and try it. | 6. Register a new account, sign in and try it. | ||||||
|  |  | ||||||
| Note, that this setup doesn't include watching a directory nor | Note, that this setup doesn't include watching a directory nor | ||||||
| fulltext search. Using zip/deb files requires to take care of the | fulltext search. Using zip/deb files requires to take care of the | ||||||
| @@ -64,7 +63,7 @@ extracted and installed manually somewhere in your `$PATH`. There are | |||||||
| no deb files provided. | no deb files provided. | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Running | # Running | ||||||
|  |  | ||||||
| Run the start script (in the corresponding `bin/` directory when using | Run the start script (in the corresponding `bin/` directory when using | ||||||
| the zip files): | the zip files): | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ title = "Nix / NixOS" | |||||||
| weight = 24 | weight = 24 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Nix | ||||||
|  |  | ||||||
| ## Install via Nix | ## Install via Nix | ||||||
|  |  | ||||||
| @@ -73,7 +74,7 @@ back to the previous version. | |||||||
| When using the provided nix setup, the `currentPkg` always points to | When using the provided nix setup, the `currentPkg` always points to | ||||||
| the latest release. Thus it is enough to run `nix-build`. | the latest release. Thus it is enough to run `nix-build`. | ||||||
|  |  | ||||||
| ## Docspell on NixOS {#nixos} | # Docspell on NixOS {#nixos} | ||||||
|  |  | ||||||
| If you are running [NixOS](https://nixos.org), there is a module | If you are running [NixOS](https://nixos.org), there is a module | ||||||
| definition for installing Docspell as a service using systemd. | definition for installing Docspell as a service using systemd. | ||||||
| @@ -141,7 +142,7 @@ The modules files are only applicable to the newest version of | |||||||
| Docspell. If you really need an older version, checkout the | Docspell. If you really need an older version, checkout the | ||||||
| appropriate commit. | appropriate commit. | ||||||
|  |  | ||||||
| ### NixOS Example | ## NixOS Example | ||||||
|  |  | ||||||
| This is a example system configuration that installs docspell with a | This is a example system configuration that installs docspell with a | ||||||
| postgres database. This snippet can be used to create a vm (using | postgres database. This snippet can be used to create a vm (using | ||||||
|   | |||||||
| @@ -3,6 +3,8 @@ title = "Prerequisites" | |||||||
| weight = 10 | weight = 10 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Prerequisites | ||||||
|  |  | ||||||
| The two components have one prerequisite in common: they both require | The two components have one prerequisite in common: they both require | ||||||
| Java to run. While this is the only requirement for the *REST server*, | Java to run. While this is the only requirement for the *REST server*, | ||||||
| the *Joex* components requires some more external programs. | the *Joex* components requires some more external programs. | ||||||
| @@ -10,7 +12,7 @@ the *Joex* components requires some more external programs. | |||||||
| The rest server and joex components are not required to "see" each | The rest server and joex components are not required to "see" each | ||||||
| other, though it is recommended. | other, though it is recommended. | ||||||
|  |  | ||||||
| # Java | ## Java | ||||||
|  |  | ||||||
| Very often, Java is already installed. You can check this by opening a | Very often, Java is already installed. You can check this by opening a | ||||||
| terminal and typing `java -version`. Otherwise install Java using your | terminal and typing `java -version`. Otherwise install Java using your | ||||||
| @@ -28,7 +30,7 @@ works on newer java versions. The provided docker images use JDK11. | |||||||
| The next tools are only required on machines running the *Joex* | The next tools are only required on machines running the *Joex* | ||||||
| component. | component. | ||||||
|  |  | ||||||
| # External Programs for Joex | ## External Programs for Joex | ||||||
|  |  | ||||||
| - [Ghostscript](http://pages.cs.wisc.edu/~ghost/) (the `gs` command) | - [Ghostscript](http://pages.cs.wisc.edu/~ghost/) (the `gs` command) | ||||||
|   is used to extract/convert PDF files into images that are then fed |   is used to extract/convert PDF files into images that are then fed | ||||||
| @@ -57,7 +59,7 @@ The performance of `unoconv` can be improved by starting `unoconv -l` | |||||||
| in a separate process. This runs a libreoffice/openoffice listener and | in a separate process. This runs a libreoffice/openoffice listener and | ||||||
| therefore avoids starting one each time `unoconv` is called. | therefore avoids starting one each time `unoconv` is called. | ||||||
|  |  | ||||||
| ## Example Debian | ### Example Debian | ||||||
|  |  | ||||||
| On Debian this should install all joex requirements: | On Debian this should install all joex requirements: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,10 @@ | |||||||
| +++ | +++ | ||||||
| title = "Quickstart" | title = "Getting started" | ||||||
| weight = 0 | weight = 0 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Getting started | ||||||
|  |  | ||||||
| To get started, here are some quick links: | To get started, here are some quick links: | ||||||
|  |  | ||||||
| - Using [docker and docker-compose](@/docs/install/docker.md). This | - Using [docker and docker-compose](@/docs/install/docker.md). This | ||||||
| @@ -28,7 +30,7 @@ To get started, here are some quick links: | |||||||
|   thread](https://forums.unraid.net/topic/103425-docspell-hilfe/) in |   thread](https://forums.unraid.net/topic/103425-docspell-hilfe/) in | ||||||
|   the German Unraid forum. Thanks for providing these! |   the German Unraid forum. Thanks for providing these! | ||||||
|  |  | ||||||
| Every [component](@/docs/intro/_index.md#components) (restserver, | Every [component](@/docs/_index.md#components) (restserver, | ||||||
| joex, dsc watch) can run on different machines and multiple times. | joex, dsc watch) can run on different machines and multiple times. | ||||||
| Most of the time running all on one machine is sufficient and also for | Most of the time running all on one machine is sufficient and also for | ||||||
| simplicity, the docker-compose setup reflects this variant. | simplicity, the docker-compose setup reflects this variant. | ||||||
| @@ -39,7 +41,7 @@ file](@/docs/configure/_index.md). If this is not given, the default | |||||||
| is used, which gets you started on a single machine, but it is very | is used, which gets you started on a single machine, but it is very | ||||||
| likely you want to change these to match your use-case/setup. | likely you want to change these to match your use-case/setup. | ||||||
|  |  | ||||||
| {% infobubble(mode="info", title="⚠ Please note") %} | {% infobubble(title="Note") %} | ||||||
|  |  | ||||||
| Please have a look at the [configuration page](/docs/configure/) page, | Please have a look at the [configuration page](/docs/configure/) page, | ||||||
| before making docspell publicly available. By default, everyone can | before making docspell publicly available. By default, everyone can | ||||||
|   | |||||||
| @@ -3,6 +3,8 @@ title = "Reverse Proxy" | |||||||
| weight = 50 | weight = 50 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Reverse Proxy | ||||||
|  |  | ||||||
| This contains examples for how to use docspell behind a reverse proxy. | This contains examples for how to use docspell behind a reverse proxy. | ||||||
|  |  | ||||||
| For the examples below, assume the following: | For the examples below, assume the following: | ||||||
|   | |||||||
| @@ -1,8 +1,10 @@ | |||||||
| +++ | +++ | ||||||
| title = "Raspberry-Pi and Similiar" | title = "Raspberry-Pi" | ||||||
| weight = 40 | weight = 40 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Raspberry Pi | ||||||
|  |  | ||||||
| Both components can run next to each other on a raspberry pi or | Both components can run next to each other on a raspberry pi or | ||||||
| similiar device. | similiar device. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,149 +3,8 @@ title = "Introduction" | |||||||
| weight = 0 | weight = 0 | ||||||
| description = "Gives a short introduction to the goals of docspell and an overview of the components involved." | description = "Gives a short introduction to the goals of docspell and an overview of the components involved." | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
|  | redirect_to = "/docs/" | ||||||
| [extra] | [extra] | ||||||
| mktoc = true | mktoc = true | ||||||
|  | hidden = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Introduction |  | ||||||
|  |  | ||||||
| Docspell aims to be a simple yet effective document organizer that |  | ||||||
| makes stowing documents away very quick and finding them later |  | ||||||
| reliable (and also fast). It is a bit opinionated and more targeted |  | ||||||
| for home use and small/medium organizations. |  | ||||||
|  |  | ||||||
| In contrast to many DMS, the main focus is not so much to provide all |  | ||||||
| kinds of features to manually create organizational structures, like |  | ||||||
| folder hierarchies, where you place the documents yourself. The |  | ||||||
| approach is to leave it as a big pile of documents, but extract and |  | ||||||
| attach metadata from each document. These are mainly properties that |  | ||||||
| emerge from the document itself. The reason is that this is possible |  | ||||||
| to automate. This makes it very simple to *add* documents, because |  | ||||||
| there is no time spent to think about where to put it. And it is |  | ||||||
| possible to apply different structures on top later, like show first |  | ||||||
| all documents of a specific correspondent, then all with tag |  | ||||||
| 'invoice', etc. If these properties are attached to all documents, it |  | ||||||
| is really easy to find a document. It even can be combined with |  | ||||||
| fulltext search for the, hopefully rare, desperate cases. |  | ||||||
|  |  | ||||||
| Of course, it is also possible to add custom properties and arbitrary |  | ||||||
| tags. |  | ||||||
|  |  | ||||||
| Docspell analyzes the text to find metadata automatically. It can |  | ||||||
| learn from existing data and can apply |  | ||||||
| [NLP](https://en.wikipedia.org/wiki/Natural_language_processing) |  | ||||||
| techniques to support this. This metadata must be maintained manually |  | ||||||
| in the application. Docspell looks for candidates for: |  | ||||||
|  |  | ||||||
| - Correspondents |  | ||||||
| - Concerned person or things |  | ||||||
| - A date and due date |  | ||||||
| - Tags |  | ||||||
|  |  | ||||||
| For tags, it sets all that it thinks do apply. For the others, it will |  | ||||||
| propose a few candidates and sets the most likely one to your item. |  | ||||||
|  |  | ||||||
| This might be wrong, so it is recommended to curate the results. |  | ||||||
| However, very often the correct one is either set or within the |  | ||||||
| proposals where you fix it by a single click. |  | ||||||
|  |  | ||||||
| Besides these properties, there are more metadata you can use to |  | ||||||
| organize your files, for example custom fields, folders and notes. |  | ||||||
|  |  | ||||||
| Docspell is also for programmers. Everything is available via a REST |  | ||||||
| or HTTP api and can be easily used within your own scripts and tools, |  | ||||||
| for example using `curl`. There are also features for "advanced use" |  | ||||||
| and many configuration options. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Components |  | ||||||
|  |  | ||||||
| Docspell consists of multiple components that run in separate |  | ||||||
| processes: |  | ||||||
|  |  | ||||||
| - REST server |  | ||||||
| - JOEX, short for *job executor* |  | ||||||
| - Fulltext Search Index (optional, currently Apache SOLR) |  | ||||||
|  |  | ||||||
| The REST server provides the Api and the web application. The web |  | ||||||
| application is a |  | ||||||
| [SPA](https://en.wikipedia.org/wiki/Single-page_application) written |  | ||||||
| in [Elm](https://elm-lang.org) and is a client to the REST api. All |  | ||||||
| features are available via a http/rest api. |  | ||||||
|  |  | ||||||
| The *joex* is the component that does the “heavy work”, executing |  | ||||||
| long-running tasks, like processing files or importing your mails |  | ||||||
| periodically. While the joex component also exposes a small REST api |  | ||||||
| for controlling it, the main user interface is all inside the rest |  | ||||||
| server api. |  | ||||||
|  |  | ||||||
| The rest server and the job executor can be started multiple times in |  | ||||||
| order to scale out. It must be ensured, that all connect to the same |  | ||||||
| database. And it is also recommended (though not strictly required), |  | ||||||
| that all components can reach each other. |  | ||||||
|  |  | ||||||
| The fulltext search index is another separate component, where |  | ||||||
| currently only [SOLR](https://solr.apache.org) is supported. |  | ||||||
| Fulltext search is optional, so the SOLR component is not required if |  | ||||||
| docspell is run without fulltext search support. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Terms |  | ||||||
|  |  | ||||||
| In order to better understand the following pages, some terms are |  | ||||||
| explained. |  | ||||||
|  |  | ||||||
| ## Item |  | ||||||
|  |  | ||||||
| An *item* is roughly your document, only that an item may span |  | ||||||
| multiple files, which are called *attachments*. An item has *meta |  | ||||||
| data* associated: |  | ||||||
|  |  | ||||||
| - a *correspondent*: the other side of the communication. It can be |  | ||||||
|   an organization or a person. |  | ||||||
| - a *concerning person* or *equipment*: a person or thing that |  | ||||||
|   this item is about. Maybe it is an insurance contract about your |  | ||||||
|   car. |  | ||||||
| - *tag*: an item can be tagged with one or more tags (or labels). A |  | ||||||
|   tag can have a *category*. This is intended for grouping tags, for |  | ||||||
|   example a category `doctype` could be used to group tags like |  | ||||||
|   `bill`, `contract`, `receipt` etc. Usually an item is not tagged |  | ||||||
|   with more than one tag of a category. |  | ||||||
| - a *folder*: a folder is similiar to a tag, but an item can only be |  | ||||||
|   in exactly one folder (or none). Furthermore folders allow to |  | ||||||
|   associate users, so that items are only visible to the users who are |  | ||||||
|   members of a folder. |  | ||||||
| - an *item date*: this is the date of the document – if this is not |  | ||||||
|   set, the created date of the item is used. |  | ||||||
| - a *due date*: an optional date indicating that something has to be |  | ||||||
|   done (e.g. paying a bill, submitting it) about this item until this |  | ||||||
|   date |  | ||||||
| - a *direction*: one of "incoming" or "outgoing" |  | ||||||
| - a *name*: some item name, defaults to the file name of the |  | ||||||
|   attachments |  | ||||||
| - some *notes*: arbitrary descriptive text. You can use markdown |  | ||||||
|   here, which is properly formatted in the web application. |  | ||||||
|  |  | ||||||
| ## Collective |  | ||||||
|  |  | ||||||
| The users of the application are part of a *collective*. A |  | ||||||
| *collective* is a group of users that share access to the same |  | ||||||
| items. The account name is therefore comprised of a *collective name* |  | ||||||
| and a *user name*. |  | ||||||
|  |  | ||||||
| All users of a collective are equal; they have same permissions to |  | ||||||
| access all items. The items don't belong to a user, but to the |  | ||||||
| collective. |  | ||||||
|  |  | ||||||
| That means, to identify yourself when signing in, you have to give the |  | ||||||
| collective name and your user name. By default it is separated by a |  | ||||||
| slash `/`, for example `smith/john`. If your user name is the same as |  | ||||||
| the collective name, you can omit one; so `smith/smith` can be |  | ||||||
| abbreviated to just `smith`. |  | ||||||
|  |  | ||||||
| By default, all users can see all items of their collective. A |  | ||||||
| *folder* can be used to implement other visibilities: Every user can |  | ||||||
| create a folder and associate members. It is possible to put items in |  | ||||||
| these folders and docspell shows only items that are either in no |  | ||||||
| specific folder or in a folder where the current user is owner or |  | ||||||
| member. |  | ||||||
|   | |||||||
| @@ -7,6 +7,8 @@ insert_anchor_links = "right" | |||||||
| mktoc = true | mktoc = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # File Processing | ||||||
|  |  | ||||||
| When uploading a file, it is only saved to the database together with | When uploading a file, it is only saved to the database together with | ||||||
| the given meta information as a "job". The file is not visible in the | the given meta information as a "job". The file is not visible in the | ||||||
| ui yet. Then joex takes the next such job and starts processing it. | ui yet. Then joex takes the next such job and starts processing it. | ||||||
| @@ -319,7 +321,7 @@ docspell.joex { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| {% infobubble(mode="warning", title="Please note") %} | {% warningbubble(title="Please note") %} | ||||||
|  |  | ||||||
| When this is changed, you must re-generate all preview images. Check | When this is changed, you must re-generate all preview images. Check | ||||||
| the api for this, there is an endpoint to regenerate all preview | the api for this, there is an endpoint to regenerate all preview | ||||||
|   | |||||||
| @@ -7,7 +7,8 @@ insert_anchor_links = "right" | |||||||
| mktoc = true | mktoc = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Introduction | # Joex | ||||||
|  | ## Introduction | ||||||
|  |  | ||||||
| Joex is short for *Job Executor* and it is the component managing long | Joex is short for *Job Executor* and it is the component managing long | ||||||
| running tasks in docspell. One of these long running tasks is the file | running tasks in docspell. One of these long running tasks is the file | ||||||
| @@ -30,7 +31,7 @@ compete on getting the next job from the queue. After a job finishes | |||||||
| and no job is waiting in the queue, joex will sleep until notified | and no job is waiting in the queue, joex will sleep until notified | ||||||
| again. It will also periodically notify itself as a fallback. | again. It will also periodically notify itself as a fallback. | ||||||
|  |  | ||||||
| # Task vs Job | ## Task vs Job | ||||||
|  |  | ||||||
| Just for the sake of this document, a task denotes the code that has | Just for the sake of this document, a task denotes the code that has | ||||||
| to be executed or the thing that has to be done. It emerges in a job, | to be executed or the thing that has to be done. It emerges in a job, | ||||||
| @@ -39,7 +40,7 @@ up and executed eventually. A job maintains a state and other things, | |||||||
| while a task is just code. | while a task is just code. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Scheduler and Queue | ## Scheduler and Queue | ||||||
|  |  | ||||||
| The scheduler is the part that runs and monitors the long running | The scheduler is the part that runs and monitors the long running | ||||||
| jobs. It works together with the job queue, which defines what job to | jobs. It works together with the job queue, which defines what job to | ||||||
| @@ -62,7 +63,7 @@ logged in, jobs are more important that those submitted when not | |||||||
| logged in. | logged in. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Scheduler Config | ## Scheduler Config | ||||||
|  |  | ||||||
| The relevant part of the config file regarding the scheduler is shown | The relevant part of the config file regarding the scheduler is shown | ||||||
| below with some explanations. | below with some explanations. | ||||||
| @@ -130,7 +131,7 @@ reach a joex component. This periodic wakup is just to ensure that | |||||||
| jobs are eventually run. | jobs are eventually run. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Periodic Tasks | ## Periodic Tasks | ||||||
|  |  | ||||||
| The job executor can execute tasks periodically. These tasks are | The job executor can execute tasks periodically. These tasks are | ||||||
| stored in the database such that they can be submitted into the job | stored in the database such that they can be submitted into the job | ||||||
| @@ -139,7 +140,7 @@ something with a task. So a periodic task is never submitted twice. It | |||||||
| is also not submitted, if a previous task has not finished yet. | is also not submitted, if a previous task has not finished yet. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Starting on demand | ## Starting on demand | ||||||
|  |  | ||||||
| The job executor and rest server can be started multiple times. This | The job executor and rest server can be started multiple times. This | ||||||
| is especially useful for the job executor. For example, when | is especially useful for the job executor. For example, when | ||||||
| @@ -154,7 +155,7 @@ Once the files have been processced you can stop the additional | |||||||
| executors. | executors. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Shutting down | ## Shutting down | ||||||
|  |  | ||||||
| If a job executor is sleeping and not executing any jobs, you can just | If a job executor is sleeping and not executing any jobs, you can just | ||||||
| quit using SIGTERM or `Ctrl-C` when running in a terminal. But if | quit using SIGTERM or `Ctrl-C` when running in a terminal. But if | ||||||
|   | |||||||
| @@ -1,10 +1,15 @@ | |||||||
| +++ | +++ | ||||||
| title = "JSON (mini) query" | title = "JSON (mini) query" | ||||||
|  | weight = 58 | ||||||
|  | template = "docs.html" | ||||||
|  | page_template = "docs.html" | ||||||
|  |  | ||||||
| [extra] | [extra] | ||||||
| mktoc = true |  | ||||||
| hidden = true | hidden = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # JSON Miniquery | ||||||
|  |  | ||||||
| A "JSON mini query" is a simple expression that evaluates to `true` or | A "JSON mini query" is a simple expression that evaluates to `true` or | ||||||
| `false` for any given JSON value. | `false` for any given JSON value. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,15 +3,14 @@ title = "Query Language" | |||||||
| weight = 55 | weight = 55 | ||||||
| description = "The query language is a powerful way to search for documents." | description = "The query language is a powerful way to search for documents." | ||||||
| insert_anchor_links = "right" | insert_anchor_links = "right" | ||||||
| [extra] | template = "docs.html" | ||||||
| mktoc = true |  | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Query Language | ||||||
|  |  | ||||||
| Docspell uses a query language to provide a powerful way to search for | Docspell uses a query language to provide a powerful way to search for | ||||||
| your documents. It is targeted at "power users" and it needs to be | your documents. It currently needs to be enabled explicitely in your | ||||||
| enabled explicitely in your user settings to be used on the search | user settings to be used on the search page. | ||||||
| page. |  | ||||||
|  |  | ||||||
| <div class="colums"> | <div class="colums"> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,4 @@ insert_anchor_links = "right" | |||||||
| template = "pages.html" | template = "pages.html" | ||||||
| redirect_to = "docs/tools/cli/" | redirect_to = "docs/tools/cli/" | ||||||
| sort_by = "weight" | sort_by = "weight" | ||||||
| [extra] |  | ||||||
| mktoc = false |  | ||||||
| +++ | +++ | ||||||
|   | |||||||
| @@ -10,17 +10,22 @@ There is a simple Android App available to conveniently upload files | |||||||
| from your android devices. Combined with a scanner app, this allows to | from your android devices. Combined with a scanner app, this allows to | ||||||
| very quickly scan single page documents like receipts. | very quickly scan single page documents like receipts. | ||||||
|  |  | ||||||
| <div class="columns is-vcentered is-centered"> | <div class="grid grid-cols-2 gap-8 divide-x "> | ||||||
|     <div class="column"> |     <div class="flex items-center justify-center"> | ||||||
|         <a href="https://f-droid.org/packages/org.docspell.docspellshare"> |         <a href="https://f-droid.org/packages/org.docspell.docspellshare"> | ||||||
|             <img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" |             <img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" | ||||||
|                  alt="Get it on F-Droid" |                  alt="Get it on F-Droid" | ||||||
|                  style="height:120px;"/> |                  class="w-56" | ||||||
|  |                  /> | ||||||
|         </a> |         </a> | ||||||
|     </div> |     </div> | ||||||
|     <div class="column"> |     <div class="flex items-center justify-center text-xl"> | ||||||
|     Download the APK from <a href="https://github.com/docspell/android-client/releases/latest">here</a> |         <i class="fa fa-download mr-2"></i> | ||||||
|  |         <span> | ||||||
|  |            <a href="https://github.com/docspell/android-client/releases/latest">Download the APK</a> | ||||||
|  |         </span> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -43,32 +48,30 @@ The app is very simple: | |||||||
| - You can now either select an URL from the app, or the upload begins | - You can now either select an URL from the app, or the upload begins | ||||||
|   immediatly if you set a default URL. |   immediatly if you set a default URL. | ||||||
|  |  | ||||||
| <div class="columns"> | <div class="grid grid-cols-3 gap-4 mx-6 my-4"> | ||||||
|   <div class="column"> |   <div class="shadow dark:shadow-stone-600"> | ||||||
|   {{ imgnormal(file="screenshot-create.jpg", width="") }} |   {{ imgnormal(file="screenshot-create.jpg", width="") }} | ||||||
|   <p class="has-text-centered subtitle"> (A) </p> |   <p class="text-center font-mono"> (A) </p> | ||||||
|   </div> |   </div> | ||||||
|   <div class="column"> |   <div class="box-shadow"> | ||||||
|   {{ imgnormal(file="screenshot-choose.jpg", width="") }} |   {{ imgnormal(file="screenshot-choose.jpg", width="") }} | ||||||
|   <p class="has-text-centered subtitle"> (B) </p> |   <p class="text-center font-mono"> (B) </p> | ||||||
|   </div> |   </div> | ||||||
|   <div class="column"> |   <div class="box-shadow"> | ||||||
|   {{ imgnormal(file="screenshot-options.jpg", width="") }} |   {{ imgnormal(file="screenshot-options.jpg", width="") }} | ||||||
|   <p class="has-text-centered subtitle"> (C) </p> |   <p class="text-center font-mono"> (C) </p> | ||||||
|   </div> |   </div> | ||||||
| </div> |   <div class="box-shadow"> | ||||||
| <div class="columns"> |  | ||||||
|   <div class="column"> |  | ||||||
|   {{ imgnormal(file="screenshot-default.jpg", width="") }} |   {{ imgnormal(file="screenshot-default.jpg", width="") }} | ||||||
|   <p class="has-text-centered subtitle"> (D) </p> |   <p class="text-center font-mono"> (D) </p> | ||||||
|   </div> |   </div> | ||||||
|   <div class="column"> |   <div class="box-shadow"> | ||||||
|   {{ imgnormal(file="screenshot-share.jpg", width="") }} |   {{ imgnormal(file="screenshot-share.jpg", width="") }} | ||||||
|   <p class="has-text-centered subtitle"> (E) </p> |   <p class="text-center font-mono"> (E) </p> | ||||||
|   </div> |   </div> | ||||||
|   <div class="column"> |   <div class="box-shadow"> | ||||||
|   {{ imgnormal(file="screenshot-uploading.jpg", width="") }} |   {{ imgnormal(file="screenshot-uploading.jpg", width="") }} | ||||||
|   <p class="has-text-centered subtitle"> (F) </p> |   <p class="text-center font-mono"> (F) </p> | ||||||
|   </div> |   </div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,84 +0,0 @@ | |||||||
| +++ |  | ||||||
| title = "Browser Extension (Firefox)" |  | ||||||
| description = "An extension for firefox to upload files from your browser via right-click → upload to docspell." |  | ||||||
| weight = 40 |  | ||||||
| +++ |  | ||||||
|  |  | ||||||
| The idea is to click on a file in firefox and send it to docspell. It |  | ||||||
| is downloaded in the context of your current page. Then handed to an |  | ||||||
| application that pushes it to docspell. There is a browser add-on |  | ||||||
| implementing this in `tools/webextension`. This add-on only works with |  | ||||||
| firefox. |  | ||||||
|  |  | ||||||
| Installation is a bit complicated, since you need to install external |  | ||||||
| tools and the web extension. Both work together. |  | ||||||
|  |  | ||||||
| # Install `dsc` |  | ||||||
|  |  | ||||||
| First copy the [dsc](@/docs/tools/cli.md) tool somewhere in your |  | ||||||
| `PATH`, maybe `/usr/local/bin`. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Install the native part |  | ||||||
|  |  | ||||||
| Then install the "native" part of the web extension: |  | ||||||
|  |  | ||||||
| Copy or symlink the `native.py` script into some known location. For |  | ||||||
| example: |  | ||||||
|  |  | ||||||
| ``` bash |  | ||||||
| ln -s ~/docspell-checkout/tools/webextension/native/native.py /usr/local/share/docspell/native.py |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Then copy the `app_manifest.json` to |  | ||||||
| `$HOME/.mozilla/native-messaging-hosts/docspell.json`. For example: |  | ||||||
|  |  | ||||||
| ``` bash |  | ||||||
| cp ~/docspell-checkout/tools/webextension/native/app_manifest.json  ~/.mozilla/native-messaging-hosts/docspell.json |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| See |  | ||||||
| [here](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#manifest_location) |  | ||||||
| for details. |  | ||||||
|  |  | ||||||
| And you might want to modify this json file, so the path to the |  | ||||||
| `native.py` script is correct (it must be absolute). |  | ||||||
|  |  | ||||||
| If the `dsc` tool is in your `$PATH`, then this should work. You need |  | ||||||
| to provide a default source id in your `~/.config/dsc/config.toml` so |  | ||||||
| that the upload command can be used without further arguments. |  | ||||||
|  |  | ||||||
| Otherwise, edit the `native.py` script and change the path to the tool |  | ||||||
| and/or the arguments. Or create a file |  | ||||||
| `$HOME/.config/docspell/dsc.cmd` whose content is the path to the |  | ||||||
| `dsc` tool. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Install the extension |  | ||||||
|  |  | ||||||
| An extension file can be build using the `make-xpi.sh` script. But |  | ||||||
| installing it in "standard" firefox won't work, because [Mozilla |  | ||||||
| requires extensions to be signed by |  | ||||||
| them](https://wiki.mozilla.org/Add-ons/Extension_Signing). This means |  | ||||||
| creating an account and going through some process…. So here are two |  | ||||||
| alternatives: |  | ||||||
|  |  | ||||||
| 1. Open firefox and type `about:debugging` in the addressbar. Then |  | ||||||
|    click on *'Load Temporary Add-on...'* and select the |  | ||||||
|    `manifest.json` file. The extension is now installed. The downside |  | ||||||
|    is, that the extension will be removed once firefox is closed. |  | ||||||
| 2. Use Firefox ESR, which allows to install Add-ons not signed by |  | ||||||
|    Mozilla. But it has to be configured: Open firefox and type |  | ||||||
|    `about:config` in the address bar. Search for key |  | ||||||
|    `xpinstall.signatures.required` and set it to `false`. This is |  | ||||||
|    described on the last paragraph on [this |  | ||||||
|    page](https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox). |  | ||||||
|  |  | ||||||
| When you right click on a file link, there should be a context menu |  | ||||||
| entry *'Docspell Upload Helper'*. The add-on will download this file |  | ||||||
| using the browser and then send the file path to the `native.py` |  | ||||||
| script. This script will in turn call `dsc` which finally uploads it |  | ||||||
| to your configured URLs. |  | ||||||
|  |  | ||||||
| Open the Add-ons page (`Ctrl`+`Shift`+`A`), the new add-on should be |  | ||||||
| there. |  | ||||||
| @@ -4,7 +4,8 @@ description = "A command line interface to." | |||||||
| weight = 5 | weight = 5 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Introduction | # Docspell CLI | ||||||
|  | ## Introduction | ||||||
|  |  | ||||||
| The **d**oc**s**pell **c**lient, short | The **d**oc**s**pell **c**lient, short | ||||||
| [dsc](https://github.com/docspell/dsc), is a tool to use | [dsc](https://github.com/docspell/dsc), is a tool to use | ||||||
| @@ -17,7 +18,7 @@ directory. | |||||||
| It is a work in progress; eventually most of the | It is a work in progress; eventually most of the | ||||||
| [api](@/docs/api/_index.md) will be covered. | [api](@/docs/api/_index.md) will be covered. | ||||||
|  |  | ||||||
| # Usage | ## Usage | ||||||
|  |  | ||||||
| Download the binary for your architecture from the [release | Download the binary for your architecture from the [release | ||||||
| page](https://github.com/docspell/dsc/releases/latest) and rename it | page](https://github.com/docspell/dsc/releases/latest) and rename it | ||||||
| @@ -86,11 +87,9 @@ you need to `login` again. | |||||||
|  |  | ||||||
| ## Demo | ## Demo | ||||||
|  |  | ||||||
| <div class="columns is-centered is-full-width"> | <figure> | ||||||
|   <div class="column"> |  | ||||||
|   <script id="asciicast-427679" src="https://asciinema.org/a/427679.js" async></script> |   <script id="asciicast-427679" src="https://asciinema.org/a/427679.js" async></script> | ||||||
|   </div> | </figure> | ||||||
| </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Use Cases / Examples | # Use Cases / Examples | ||||||
|   | |||||||
| @@ -4,7 +4,9 @@ description = "Import your data from paperless." | |||||||
| weight = 60 | weight = 60 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
| # Introduction | # Import from Paperless | ||||||
|  |  | ||||||
|  | ## Introduction | ||||||
|  |  | ||||||
| Coming from | Coming from | ||||||
| [paperless](https://github.com/the-paperless-project/paperless/), the | [paperless](https://github.com/the-paperless-project/paperless/), the | ||||||
| @@ -15,7 +17,7 @@ importing your data from paperless into docspell. | |||||||
|  |  | ||||||
| The script imports the files and also tags and correspondents. | The script imports the files and also tags and correspondents. | ||||||
|  |  | ||||||
| {% infobubble(mode="info", title="⚠ Please note") %} | {% infobubble(title="Note") %} | ||||||
|  |  | ||||||
| The script was written some while ago. It currently doesn't work out | The script was written some while ago. It currently doesn't work out | ||||||
| of the box, but is a good starting point as the issues are most | of the box, but is a good starting point as the issues are most | ||||||
| @@ -25,7 +27,7 @@ issue](https://github.com/eikek/docspell/issues/1241). | |||||||
|  |  | ||||||
| {% end %} | {% end %} | ||||||
|  |  | ||||||
| # Usage | ## Usage | ||||||
|  |  | ||||||
| Copy the script to the machine where paperless is running. Run it with | Copy the script to the machine where paperless is running. Run it with | ||||||
| the following arguments: | the following arguments: | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ description = "Start a SMTP server that forwards all mails to docspell." | |||||||
| weight = 50 | weight = 50 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # SMTP Gateway with Exim | ||||||
|  |  | ||||||
| One possible use case for the [integration | One possible use case for the [integration | ||||||
| endpoint](@/docs/api/upload.md#integration-endpoint) is a SMTP server | endpoint](@/docs/api/upload.md#integration-endpoint) is a SMTP server | ||||||
| that forwards all local mail to docspell. This way there is no | that forwards all local mail to docspell. This way there is no | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ weight = 90 | |||||||
| mktoc = true | mktoc = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Auto-Tagging | ||||||
|  |  | ||||||
| Auto-Tagging must be enabled in the collective profile. Docspell can | Auto-Tagging must be enabled in the collective profile. Docspell can | ||||||
| go through your items periodically and learn from your existing tags. | go through your items periodically and learn from your existing tags. | ||||||
| @@ -20,7 +21,7 @@ determined by looking at the text of the document. It would mean that | |||||||
| Docspell could learn relationships that are not correct and then tag | Docspell could learn relationships that are not correct and then tag | ||||||
| the next incoming items with `Done`. | the next incoming items with `Done`. | ||||||
|  |  | ||||||
| {{ figure(file="collective-settings-autotag.png") }} | {{ figure2(light="collective-settings-autotag.png", dark="collective-settings-autotag_dark.png") }} | ||||||
|  |  | ||||||
| That is why you need to specify what tags to learn. This is done by | That is why you need to specify what tags to learn. This is done by | ||||||
| defining whitelist or a blacklist of tag categories. When defining a | defining whitelist or a blacklist of tag categories. When defining a | ||||||
|   | |||||||
| Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/bookmarks-01_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
| Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 84 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/bookmarks-02_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 83 KiB | 
| Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/bookmarks-03_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 26 KiB | 
| Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 72 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/bookmarks-04_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 76 KiB | 
| @@ -5,6 +5,8 @@ weight = 35 | |||||||
| mktoc = true | mktoc = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Bookmarks | ||||||
|  |  | ||||||
| Bookmarks allow you to save queries under a name and refer to it from the search menu. | Bookmarks allow you to save queries under a name and refer to it from the search menu. | ||||||
|  |  | ||||||
| ## Creating bookmarks | ## Creating bookmarks | ||||||
| @@ -12,13 +14,13 @@ Bookmarks allow you to save queries under a name and refer to it from the search | |||||||
| Bookmarks can be created from the search view. Apply some criteria to | Bookmarks can be created from the search view. Apply some criteria to | ||||||
| select items and then click on the top left menu. | select items and then click on the top left menu. | ||||||
|  |  | ||||||
| {{ figure(file="bookmarks-02.png") }} | {{ figure2(light="bookmarks-02.png", dark="bookmarks-02_dark.png") }} | ||||||
|  |  | ||||||
| This opens a small form right below the search bar where you can | This opens a small form right below the search bar where you can | ||||||
| adjust the query and enter the name. You can also decide whether this | adjust the query and enter the name. You can also decide whether this | ||||||
| bookmark is for all users or just for you. | bookmark is for all users or just for you. | ||||||
|  |  | ||||||
| {{ figure(file="bookmarks-03.png") }} | {{ figure2(light="bookmarks-03.png", dark="bookmarks-03_dark.png") }} | ||||||
|  |  | ||||||
| The other way is to go to *Manage Data* where you can edit and delete | The other way is to go to *Manage Data* where you can edit and delete | ||||||
| existing bookmarks and also create new ones. | existing bookmarks and also create new ones. | ||||||
| @@ -31,8 +33,8 @@ that shows you all your bookmarks as well as your shares. Clicking one | |||||||
| "enables" it, meaning the query is used in conjunction with other | "enables" it, meaning the query is used in conjunction with other | ||||||
| criteria. | criteria. | ||||||
|  |  | ||||||
| <div class="columns is-centered"> | <div class="flex items-center justify-center"> | ||||||
|   {{ imgnormal(file="bookmarks-01.png", width="") }} |   {{ imgnormal2(light="bookmarks-01.png", dark="bookmarks-01_dark.png", width="") }} | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| An active bookmark has a check icon next to its name. | An active bookmark has a check icon next to its name. | ||||||
| @@ -47,7 +49,7 @@ registered users), expired shares are shown as well. | |||||||
| The *Manage Data* page has a section for bookmarks. There you can | The *Manage Data* page has a section for bookmarks. There you can | ||||||
| delete and edit bookmarks. | delete and edit bookmarks. | ||||||
|  |  | ||||||
| {{ figure(file="bookmarks-04.png") }} | {{ figure2(light="bookmarks-04.png", dark="bookmarks-04_dark.png") }} | ||||||
|  |  | ||||||
| The personal bookmarks are only visible to you. The collective | The personal bookmarks are only visible to you. The collective | ||||||
| bookmarks are visible to every user in the collective, which also | bookmarks are visible to every user in the collective, which also | ||||||
|   | |||||||
| Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 148 KiB | 
| After Width: | Height: | Size: 156 KiB | 
| @@ -3,11 +3,13 @@ title = "Curate Items" | |||||||
| weight = 20 | weight = 20 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Curate items | ||||||
|  |  | ||||||
| Curating the items meta data helps finding them later. This page | Curating the items meta data helps finding them later. This page | ||||||
| describes how you can quickly go through those items and correct or | describes how you can quickly go through those items and correct or | ||||||
| amend with existing data. | amend with existing data. | ||||||
|  |  | ||||||
| # Select New items | ## Select New items | ||||||
|  |  | ||||||
| After files have been uploaded and the job executor created the | After files have been uploaded and the job executor created the | ||||||
| corresponding items, they will show up on the main page. All items the | corresponding items, they will show up on the main page. All items the | ||||||
| @@ -15,14 +17,14 @@ job executor has just created are initially marked as *New*. The | |||||||
| option *Inbox* in the left search menu can be used to select only new | option *Inbox* in the left search menu can be used to select only new | ||||||
| items: | items: | ||||||
|  |  | ||||||
| {{ figure(file="docspell-curate-1.png") }} | {{ figure2(light="docspell-curate-1.png", dark="docspell-curate-1_dark.png") }} | ||||||
|  |  | ||||||
| Then you can go through all new items and check their metadata: Click | Then you can go through all new items and check their metadata: Click | ||||||
| on the first item to open the detail view. This shows the documents | on the first item to open the detail view. This shows the documents | ||||||
| and the meta data in the header. | and the meta data in the header. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Modify if necessary | ## Modify if necessary | ||||||
|  |  | ||||||
| You can compare the data with the documents and change as you like. | You can compare the data with the documents and change as you like. | ||||||
| Since the item status is *New*, you'll see the suggestions docspell | Since the item status is *New*, you'll see the suggestions docspell | ||||||
| @@ -31,7 +33,7 @@ select another one by clicking its name in the suggestion list. In | |||||||
| state *New* the left menu is fully expanded so you see all suggestions | state *New* the left menu is fully expanded so you see all suggestions | ||||||
| immediatly. | immediatly. | ||||||
|  |  | ||||||
| {{ figure(file="docspell-curate-3.png") }} | {{ figure2(light="docspell-curate-3.png", dark="docspell-curate-3_dark.png") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| When you change something in the form, it is immediatly applied. | When you change something in the form, it is immediatly applied. | ||||||
| @@ -39,13 +41,11 @@ When you change something in the form, it is immediatly applied. | |||||||
| It is also possible to change tags and folders in the list view via | It is also possible to change tags and folders in the list view via | ||||||
| drag&drop. | drag&drop. | ||||||
|  |  | ||||||
| <div class="columns is-centered"> | <div class="flex items-center justify-center"> | ||||||
|   <div class="column is-narrow"> |   {{ imgnormal2(light="drop-tag.png", dark="drop-tag_dark.png", width="500px") }} | ||||||
|   {{ imgnormal(file="drop-tag.png", width="500px") }} |  | ||||||
|   </div> |  | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| # Confirm | ## Confirm | ||||||
|  |  | ||||||
| If everything looks good, click the *Confirm* button to confirm the | If everything looks good, click the *Confirm* button to confirm the | ||||||
| current data. The *New* status goes away and also the suggestions are | current data. The *New* status goes away and also the suggestions are | ||||||
| @@ -54,10 +54,10 @@ before. You can always go back by clicking the *Unconfirm* button at | |||||||
| the right of the menu bar. | the right of the menu bar. | ||||||
|  |  | ||||||
|  |  | ||||||
| {{ figure(file="docspell-curate-5.png") }} | {{ figure2(light="docspell-curate-5.png", dark="docspell-curate-5_dark.png") }} | ||||||
|  |  | ||||||
|  |  | ||||||
| # Proceed with next item | ## Proceed with next item | ||||||
|  |  | ||||||
| To look at the next item in the search results, click the *Next* | To look at the next item in the search results, click the *Next* | ||||||
| button in the menu (next to the *Edit* button). Clicking next, will | button in the menu (next to the *Edit* button). Clicking next, will | ||||||
| @@ -65,4 +65,4 @@ keep the current view, so you can continue checking the data. If you | |||||||
| are on the last item, the view switches to the listing view when | are on the last item, the view switches to the listing view when | ||||||
| clicking *Next*. | clicking *Next*. | ||||||
|  |  | ||||||
| {{ figure(file="docspell-curate-6.png") }} | {{ figure2(light="docspell-curate-6.png", dark="docspell-curate-6_dark.png") }} | ||||||
|   | |||||||
| Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 84 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/custom-fields-01_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 90 KiB | 
| Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 128 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/custom-fields-02_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 135 KiB | 
| Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB | 
| Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB | 
| Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 39 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/custom-fields-05_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 42 KiB | 
| Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 100 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/custom-fields-06_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 104 KiB | 
| Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 133 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/custom-fields-07_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 139 KiB | 
| @@ -3,6 +3,8 @@ title = "Custom Fields" | |||||||
| weight = 18 | weight = 18 | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Custom Fields | ||||||
|  |  | ||||||
| Custom fields allow to attach user defined metadata to items. For | Custom fields allow to attach user defined metadata to items. For | ||||||
| example, you may want to track the amount of each receipt or the | example, you may want to track the amount of each receipt or the | ||||||
| invoice number etc. You can define fields that can be associated to | invoice number etc. You can define fields that can be associated to | ||||||
| @@ -15,7 +17,7 @@ Custom fields can be deactivated in the user settings. | |||||||
| Go to the _Manage Data_ page, that can be reached from the top right | Go to the _Manage Data_ page, that can be reached from the top right | ||||||
| menu. One entry at the left shows _Custom Fields_: | menu. One entry at the left shows _Custom Fields_: | ||||||
|  |  | ||||||
| {{ figure(file="custom-fields-01.png") }} | {{ figure2(light="custom-fields-01.png", dark="custom-fields-01_dark.png") }} | ||||||
|  |  | ||||||
| Fields are defined per collective. They can also be created in the | Fields are defined per collective. They can also be created in the | ||||||
| item edit menu (just like creating organizations). The `#Usage` | item edit menu (just like creating organizations). The `#Usage` | ||||||
| @@ -23,7 +25,7 @@ columns show how many items have a value for this field. | |||||||
|  |  | ||||||
| A field consists of a name, a format and optional a label: | A field consists of a name, a format and optional a label: | ||||||
|  |  | ||||||
| {{ figure(file="custom-fields-02.png") }} | {{ figure2(light="custom-fields-02.png", dark="custom-fields-02_dark.png") }} | ||||||
|  |  | ||||||
| The name and format is required. The name must be unique among all | The name and format is required. The name must be unique among all | ||||||
| your fields and it is special in that it must be a valid _identifier_: | your fields and it is special in that it must be a valid _identifier_: | ||||||
| @@ -73,7 +75,7 @@ corresponding input field is shown asking for values. You can select | |||||||
| multiple fields. Only one value is allowed to set per item and field. | multiple fields. Only one value is allowed to set per item and field. | ||||||
| The example below shows a text field and a money field: | The example below shows a text field and a money field: | ||||||
|  |  | ||||||
| {{ figure(file="custom-fields-03.png") }} | {{ figure2(light="custom-fields-03.png", dark="custom-fields-03_dark.png") }} | ||||||
|  |  | ||||||
| You can create new fields right here without going to the _Manage | You can create new fields right here without going to the _Manage | ||||||
| Data_ page, by clicking the plus icon (1). The format of each field is | Data_ page, by clicking the plus icon (1). The format of each field is | ||||||
| @@ -83,14 +85,13 @@ As soon as a correct value is typed in, it is saved to the item and | |||||||
| shown in the header next to the tags. If you click the trash-can icon | shown in the header next to the tags. If you click the trash-can icon | ||||||
| next to an input, the value is removed from the item. | next to an input, the value is removed from the item. | ||||||
|  |  | ||||||
| {{ figure(file="custom-fields-04.png") }} | {{ figure2(light="custom-fields-04.png", dark="custom-fields-04_dark.png") }} | ||||||
|  |  | ||||||
| The item card also shows custom fields, in the same place as tags: | The item card also shows custom fields, in the same place as tags: | ||||||
|  |  | ||||||
| <div class="columns is-centered"> |  | ||||||
|     <div class="column is-one-quarter"> | <div class="flex flex-row items-center justify-center"> | ||||||
|     {{ imgnormal(file="custom-fields-05.png", width=300) }} | {{ imgnormal2(light="custom-fields-05.png", dark="custom-fields-05_dark.png", width=300) }} | ||||||
|     </div> |  | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| Adding values for custom fields in | Adding values for custom fields in | ||||||
| @@ -102,13 +103,13 @@ Adding values for custom fields in | |||||||
| The search menu shows the same dropdown for selecting a custom field. | The search menu shows the same dropdown for selecting a custom field. | ||||||
| Then you can set values that are matched against your items. | Then you can set values that are matched against your items. | ||||||
|  |  | ||||||
| {{ figure(file="custom-fields-06.png") }} | {{ figure2(light="custom-fields-06.png", dark="custom-fields-06_dark.png") }} | ||||||
|  |  | ||||||
| Values are also validated in the search form. Only valid values are | Values are also validated in the search form. Only valid values are | ||||||
| sent to the server for searching. There is one exception: you can use | sent to the server for searching. There is one exception: you can use | ||||||
| a wildcard at beginning and/or end to do a substring match: | a wildcard at beginning and/or end to do a substring match: | ||||||
|  |  | ||||||
| {{ figure(file="custom-fields-07.png") }} | {{ figure2(light="custom-fields-07.png", dark="custom-fields-07_dark.png") }} | ||||||
|  |  | ||||||
| For all numeric and money values, a little summary is displayed next | For all numeric and money values, a little summary is displayed next | ||||||
| to the overall item count at the top of the page. | to the overall item count at the top of the page. | ||||||
|   | |||||||
| Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 215 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/dashboards-01_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 234 KiB | 
| Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 137 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/dashboards-02_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 140 KiB | 
| Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 185 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/dashboards-03_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 205 KiB | 
| Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 123 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/dashboards-04_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 127 KiB | 
							
								
								
									
										
											BIN
										
									
								
								website/site/content/docs/webapp/dashboards-05_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 228 KiB | 
| @@ -5,18 +5,20 @@ weight = 5 | |||||||
| mktoc = true | mktoc = true | ||||||
| +++ | +++ | ||||||
|  |  | ||||||
|  | # Dashboards | ||||||
|  |  | ||||||
| The main page shows a dashboard that can be configured to show some | The main page shows a dashboard that can be configured to show some | ||||||
| aspects of your documents. The following shows the default dashboard | aspects of your documents. The following shows the default dashboard | ||||||
| that is bundled in the application: | that is bundled in the application: | ||||||
|  |  | ||||||
| {{ figure(file="dashboards-01.png") }} | {{ figure2(light="dashboards-01.png", dark="dashboards-01_dark.png") }} | ||||||
|  |  | ||||||
| It shows a predefined set of information, which can be customized. You | It shows a predefined set of information, which can be customized. You | ||||||
| can create multiple dashboards and switch between them, you can also | can create multiple dashboards and switch between them, you can also | ||||||
| define one as the "default" which is shown when the page loads. | define one as the "default" which is shown when the page loads. | ||||||
|  |  | ||||||
|  |  | ||||||
| # Side menu | ## Side menu | ||||||
|  |  | ||||||
| The side menu contains a list of useful links. The first loads the | The side menu contains a list of useful links. The first loads the | ||||||
| default dashboard. All others (and more) are available through the | default dashboard. All others (and more) are available through the | ||||||
| @@ -29,7 +31,7 @@ The _Settings_ section contains some links to useful settings and the | |||||||
| _Manage_ section has links to metadata that can be managed separately. | _Manage_ section has links to metadata that can be managed separately. | ||||||
| These links are fixed and cannot be changed. | These links are fixed and cannot be changed. | ||||||
|  |  | ||||||
| # Dasbhoard properties | ## Dasbhoard properties | ||||||
|  |  | ||||||
| The main component on this page is the "dashboard". A dashboard has | The main component on this page is the "dashboard". A dashboard has | ||||||
| the following properties (all required): | the following properties (all required): | ||||||
| @@ -57,7 +59,7 @@ removing boxes and the dashboard properties. | |||||||
|  |  | ||||||
| After clicking _Edit Dashboard_ the dashboard changes into a form: | After clicking _Edit Dashboard_ the dashboard changes into a form: | ||||||
|  |  | ||||||
| {{ figure(file="dashboards-02.png") }} | {{ figure2(light="dashboards-02.png", dark="dashboards-02_dark.png") }} | ||||||
|  |  | ||||||
| Note the message on the top: it indicates that this dashboard is the | Note the message on the top: it indicates that this dashboard is the | ||||||
| bundled one that is used only if there are no custom ones available. | bundled one that is used only if there are no custom ones available. | ||||||
| @@ -72,19 +74,19 @@ reorder the boxes using the arrow buttons or drag and drop. When | |||||||
| satisfied, click _Submit_. In the example, the last two boxes are | satisfied, click _Submit_. In the example, the last two boxes are | ||||||
| removed and box decorations are enabled for the field overview box. | removed and box decorations are enabled for the field overview box. | ||||||
|  |  | ||||||
| {{ figure(file="dashboards-03.png") }} | {{ figure2(light="dashboards-03.png", dark="dashboards-03_dark.png") }} | ||||||
|  |  | ||||||
| When you now edit this dasbhoard again, the message is gone and you | When you now edit this dasbhoard again, the message is gone and you | ||||||
| can change the dashboard and also delete it. You can also create a new | can change the dashboard and also delete it. You can also create a new | ||||||
| dashboard or copy the current one. | dashboard or copy the current one. | ||||||
|  |  | ||||||
| {{ figure(file="dashboards-04.png") }} | {{ figure2(light="dashboards-04.png", dark="dashboards-04_dark.png") }} | ||||||
|  |  | ||||||
| In this example, the dashboard was copied, then the message was | In this example, the dashboard was copied, then the message was | ||||||
| changed and it was set to the default dashboard. This is how it looks | changed and it was set to the default dashboard. This is how it looks | ||||||
| now: | now: | ||||||
|  |  | ||||||
| {{ figure(file="dashboards-05.png") }} | {{ figure2(light="dashboards-05.png", dark="dashboards-05_dark.png") }} | ||||||
|  |  | ||||||
| When there is more than one dashboard, the side menu shows all of | When there is more than one dashboard, the side menu shows all of | ||||||
| them. The little house icon indicates whether this is the default | them. The little house icon indicates whether this is the default | ||||||
|   | |||||||
| Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |