Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Commit

Permalink
Merge 0b6c749 into 5612ad0
Browse files Browse the repository at this point in the history
  • Loading branch information
shamoon committed Feb 19, 2022
2 parents 5612ad0 + 0b6c749 commit de9e273
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 43 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ If you want to see paperless-ng in action, [more screenshots are available in th

# Getting started

The recommended way to deploy paperless is docker-compose. The files in the /docker/hub directory are configured to pull the image from Docker Hub.
The recommended way to deploy paperless is docker-compose. The files in the /docker/compose directory are configured to pull the image from Docker Hub.

Read the [documentation](https://paperless-ng.readthedocs.io/en/latest/setup.html#installation) on how to get started.

Expand Down
2 changes: 1 addition & 1 deletion ansible/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
- regexp: PAPERLESS_TIKA_ENDPOINT
line: "PAPERLESS_TIKA_ENDPOINT={{ paperlessng_tika_endpoint }}"
- regexp: PAPERLESS_TIKA_GOTENBERG_ENDPOINT
line: "PAPERLESS_TIKA_GOTENBERG_ENDPOINT={{ paperlessng_tika_endpoint }}"
line: "PAPERLESS_TIKA_GOTENBERG_ENDPOINT={{ paperlessng_tika_gotenberg_endpoint }}"
# Software tweaks
- regexp: PAPERLESS_TIME_ZONE
line: "PAPERLESS_TIME_ZONE={{ paperlessng_time_zone }}"
Expand Down
7 changes: 7 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME=<str>

Defaults to `HTTP_REMOTE_USER`.

PAPERLESS_LOGOUT_REDIRECT_URL=<str>
URL to redirect the user to after a logout. This can be used together with
`PAPERLESS_ENABLE_HTTP_REMOTE_USER` to redirect the user back to the SSO
application's logout page.

Defaults to None, which disables this feature.

.. _configuration-ocr:

OCR settings
Expand Down
18 changes: 18 additions & 0 deletions docs/setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ Install Paperless from Docker Hub
Don't change the part after the colon or paperless wont find your documents.

You may also need to change the default port that the webserver will use
from the default (8000):

.. code::
ports:
- 8000:8000
Replace the part BEFORE the colon with a port of your choice:

.. code::
ports:
- 8010:8000
Don't change the part after the colon or edit other lines that refer to
port 8000. Modifying the part before the colon will map requests on another
port to the webserver running on the default port.

5. Modify ``docker-compose.env``, following the comments in the file. The
most important change is to set ``USERMAP_UID`` and ``USERMAP_GID``
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,35 @@
</button>
<div class="dropdown-menu py-0 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
<div class="list-group list-group-flush">
<div *ngIf="!editing && multiple" class="list-group-item d-flex">
<div class="btn-group btn-group-xs btn-group-toggle flex-fill" ngbRadioGroup [(ngModel)]="selectionModel.logicalOperator" (change)="selectionModel.toggleOperator()">
<label ngbButtonLabel class="btn btn-outline-primary">
<input ngbButton type="radio" name="logicalOperator" value="and" [disabled]="!operatorToggleEnabled"> All
</label>
<label ngbButtonLabel class="btn btn-outline-primary">
<input ngbButton type="radio" name="logicalOperator" value="or" [disabled]="!operatorToggleEnabled"> Any
</label>
</div>
</div>
<div class="list-group-item">
<div class="input-group input-group-sm">
<input class="form-control" type="text" [(ngModel)]="filterText" [placeholder]="filterPlaceholder" (keyup.enter)="listFilterEnter()" #listFilterTextInput>
</div>
</div>
<div *ngIf="selectionModel.items" class="items">
<ng-container *ngFor="let item of selectionModel.itemsSorted | filter: filterText">
<app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)"></app-toggleable-dropdown-button>
<app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)" (exclude)="excludeClicked(item.id)"></app-toggleable-dropdown-button>
</ng-container>
</div>
<button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!selectionModel.isDirty()">
<small class="ml-1" [ngClass]="{'font-weight-bold': selectionModel.isDirty()}" i18n>Apply</small>
<small class="ml-2" [ngClass]="{'font-weight-bold': selectionModel.isDirty()}" i18n>Apply</small>
<svg width="1.5em" height="1em" viewBox="0 0 16 16" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#arrow-right" />
</svg>
</button>
<div *ngIf="!editing && multiple" class="list-group-item list-group-item-note pt-1 pb-2">
<small i18n>Click again to exclude items.</small>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,38 @@
overflow-y: scroll;
}
}

.btn-group-xs {
> .btn {
padding: 0.2rem 0.25rem;
font-size: 0.675rem;
line-height: 1.2;
border-radius: 0.15rem;
}

> .btn:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

> .btn:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}

.btn-group > label.disabled {
filter: brightness(0.5);
}

small > svg {
margin-top: -2px;
}

.list-group-item-note {
line-height: 1;

small {
font-size: 65%;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export class FilterableDropdownSelectionModel {
changed = new Subject<FilterableDropdownSelectionModel>()

multiple = false
private _logicalOperator = 'and'
temporaryLogicalOperator = this._logicalOperator

items: MatchingModel[] = []

Expand Down Expand Up @@ -43,6 +45,10 @@ export class FilterableDropdownSelectionModel {
return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected)
}

getExcludedItems() {
return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded)
}

set(id: number, state: ToggleableItemState, fireEvent = true) {
if (state == ToggleableItemState.NotSelected) {
this.temporarySelectionStates.delete(id)
Expand All @@ -56,9 +62,9 @@ export class FilterableDropdownSelectionModel {

toggle(id: number, fireEvent = true) {
let state = this.temporarySelectionStates.get(id)
if (state == null || state != ToggleableItemState.Selected) {
if (state == null || (state != ToggleableItemState.Selected && state != ToggleableItemState.Excluded)) {
this.temporarySelectionStates.set(id, ToggleableItemState.Selected)
} else if (state == ToggleableItemState.Selected) {
} else if (state == ToggleableItemState.Selected || state == ToggleableItemState.Excluded) {
this.temporarySelectionStates.delete(id)
}

Expand All @@ -83,13 +89,46 @@ export class FilterableDropdownSelectionModel {
if (fireEvent) {
this.changed.next(this)
}
}

exclude(id: number, fireEvent:boolean = true) {
let state = this.temporarySelectionStates.get(id)
if (state == null || state != ToggleableItemState.Excluded) {
this.temporarySelectionStates.set(id, ToggleableItemState.Excluded)
this.temporaryLogicalOperator = this._logicalOperator = 'and'
} else if (state == ToggleableItemState.Excluded) {
this.temporarySelectionStates.delete(id)
}

if (!this.multiple) {
for (let key of this.temporarySelectionStates.keys()) {
if (key != id) {
this.temporarySelectionStates.delete(key)
}
}
}

if (fireEvent) {
this.changed.next(this)
}
}

private getNonTemporary(id: number) {
return this.selectionStates.get(id) || ToggleableItemState.NotSelected
}

get logicalOperator(): string {
return this.temporaryLogicalOperator
}

set logicalOperator(operator: string) {
this.temporaryLogicalOperator = operator
}

toggleOperator() {
this.changed.next(this)
}

get(id: number) {
return this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected
}
Expand All @@ -100,6 +139,7 @@ export class FilterableDropdownSelectionModel {

clear(fireEvent = true) {
this.temporarySelectionStates.clear()
this.temporaryLogicalOperator = this._logicalOperator = 'and'
if (fireEvent) {
this.changed.next(this)
}
Expand All @@ -110,6 +150,8 @@ export class FilterableDropdownSelectionModel {
return true
} else if (!Array.from(this.selectionStates.keys()).every(id => this.selectionStates.get(id) == this.temporarySelectionStates.get(id))) {
return true
} else if (this.temporaryLogicalOperator !== this._logicalOperator) {
return true
} else {
return false
}
Expand All @@ -129,6 +171,7 @@ export class FilterableDropdownSelectionModel {
this.temporarySelectionStates.forEach((value, key) => {
this.selectionStates.set(key, value)
})
this._logicalOperator = this.temporaryLogicalOperator
}

reset() {
Expand Down Expand Up @@ -228,6 +271,10 @@ export class FilterableDropdownComponent {
@Output()
open = new EventEmitter()

get operatorToggleEnabled(): boolean {
return this.selectionModel.selectionSize() > 1 && this.selectionModel.getExcludedItems().length == 0
}

constructor(private filterPipe: FilterPipe) {
this.selectionModel = new FilterableDropdownSelectionModel()
}
Expand Down Expand Up @@ -269,4 +316,12 @@ export class FilterableDropdownComponent {
}
}
}

excludeClicked(itemID: number) {
if (this.editing) {
this.selectionModel.toggle(itemID)
} else {
this.selectionModel.exclude(itemID)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-left-0 border-right-0 border-bottom" role="menuitem" (click)="toggleItem()">
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-left-0 border-right-0 border-bottom" role="menuitem" (click)="toggleItem($event)">
<div class="selected-icon mr-1">
<ng-container *ngIf="isChecked()">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
Expand All @@ -10,10 +10,14 @@
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>
</svg>
</ng-container>

<ng-container *ngIf="isExcluded()">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
</svg>
</ng-container>
</div>
<div class="mr-1">
<app-tag *ngIf="isTag; else displayName" [tag]="item" [clickable]="true" linkTitle="Filter by tag"></app-tag>
<app-tag *ngIf="isTag; else displayName" [tag]="item" [clickable]="false"></app-tag>
<ng-template #displayName><small>{{item.name}}</small></ng-template>
</div>
<div class="badge badge-light rounded-pill ml-auto mr-1">{{item.document_count}}</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
import { MatchingModel } from 'src/app/data/matching-model';

export interface ToggleableItem {
item: MatchingModel,
state: ToggleableItemState,
count: number
}

export enum ToggleableItemState {
NotSelected = 0,
Selected = 1,
PartiallySelected = 2
PartiallySelected = 2,
Excluded = 3
}

@Component({
Expand All @@ -32,12 +27,19 @@ export class ToggleableDropdownButtonComponent {
@Output()
toggle = new EventEmitter()

@Output()
exclude = new EventEmitter()

get isTag(): boolean {
return 'is_inbox_tag' in this.item
}

toggleItem(): void {
this.toggle.emit()
toggleItem(event: MouseEvent): void {
if (this.state == ToggleableItemState.Selected) {
this.exclude.emit()
} else {
this.toggle.emit()
}
}

isChecked() {
Expand All @@ -48,4 +50,7 @@ export class ToggleableDropdownButtonComponent {
return this.state == ToggleableItemState.PartiallySelected
}

isExcluded() {
return this.state == ToggleableItemState.Excluded
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,21 @@ export class DocumentListComponent implements OnInit, OnDestroy {
clickTag(tagID: number) {
this.list.selectNone()
setTimeout(() => {
this.filterEditor.toggleTag(tagID)
this.filterEditor.addTag(tagID)
})
}

clickCorrespondent(correspondentID: number) {
this.list.selectNone()
setTimeout(() => {
this.filterEditor.toggleCorrespondent(correspondentID)
this.filterEditor.addCorrespondent(correspondentID)
})
}

clickDocumentType(documentTypeID: number) {
this.list.selectNone()
setTimeout(() => {
this.filterEditor.toggleDocumentType(documentTypeID)
this.filterEditor.addDocumentType(documentTypeID)
})
}

Expand Down
Loading

0 comments on commit de9e273

Please sign in to comment.