mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 19:17:13 -05:00 
			
		
		
		
	Merge pull request #154 from shamoon/fix/issue-152
Searchable dropdowns on document details component
This commit is contained in:
		
						commit
						b262ec4b32
					
				
							
								
								
									
										8
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -2056,6 +2056,14 @@
 | 
				
			|||||||
        "tslib": "^2.0.0"
 | 
					        "tslib": "^2.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@ng-select/ng-select": {
 | 
				
			||||||
 | 
					      "version": "5.0.9",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-5.0.9.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-YZeSAiS8/Nx/eHZJPmOOYL8YmcvSq+dr1P8WIrsKmRA7mueorBpPc5xlUj+nLQbpLtsiQvdWDQspf/ykOvD/lA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "tslib": "^2.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@ngtools/webpack": {
 | 
					    "@ngtools/webpack": {
 | 
				
			||||||
      "version": "10.2.0",
 | 
					      "version": "10.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.2.0.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@
 | 
				
			|||||||
    "@angular/platform-browser-dynamic": "~10.1.5",
 | 
					    "@angular/platform-browser-dynamic": "~10.1.5",
 | 
				
			||||||
    "@angular/router": "~10.1.5",
 | 
					    "@angular/router": "~10.1.5",
 | 
				
			||||||
    "@ng-bootstrap/ng-bootstrap": "^8.0.0",
 | 
					    "@ng-bootstrap/ng-bootstrap": "^8.0.0",
 | 
				
			||||||
 | 
					    "@ng-select/ng-select": "^5.0.9",
 | 
				
			||||||
    "bootstrap": "^4.5.0",
 | 
					    "bootstrap": "^4.5.0",
 | 
				
			||||||
    "ng-bootstrap": "^1.6.3",
 | 
					    "ng-bootstrap": "^1.6.3",
 | 
				
			||||||
    "ng2-pdf-viewer": "^6.3.2",
 | 
					    "ng2-pdf-viewer": "^6.3.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -54,6 +54,7 @@ import { FileSizePipe } from './pipes/file-size.pipe';
 | 
				
			|||||||
import { FilterPipe } from './pipes/filter.pipe';
 | 
					import { FilterPipe } from './pipes/filter.pipe';
 | 
				
			||||||
import { DocumentTitlePipe } from './pipes/document-title.pipe';
 | 
					import { DocumentTitlePipe } from './pipes/document-title.pipe';
 | 
				
			||||||
import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component';
 | 
					import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component';
 | 
				
			||||||
 | 
					import { NgSelectModule } from '@ng-select/ng-select';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
  declarations: [
 | 
					  declarations: [
 | 
				
			||||||
@ -110,7 +111,8 @@ import { MetadataCollapseComponent } from './components/document-detail/metadata
 | 
				
			|||||||
    ReactiveFormsModule,
 | 
					    ReactiveFormsModule,
 | 
				
			||||||
    NgxFileDropModule,
 | 
					    NgxFileDropModule,
 | 
				
			||||||
    InfiniteScrollModule,
 | 
					    InfiniteScrollModule,
 | 
				
			||||||
    PdfViewerModule
 | 
					    PdfViewerModule,
 | 
				
			||||||
 | 
					    NgSelectModule
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  providers: [
 | 
					  providers: [
 | 
				
			||||||
    DatePipe,
 | 
					    DatePipe,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,15 @@
 | 
				
			|||||||
<div class="form-group">
 | 
					<div class="form-group paperless-input-select">
 | 
				
			||||||
  <label [for]="inputId">{{title}}</label>
 | 
					  <label [for]="inputId">{{title}}</label>
 | 
				
			||||||
  <div [class.input-group]="showPlusButton()">
 | 
					  <div [class.input-group]="showPlusButton()">
 | 
				
			||||||
    <select class="form-control" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" (blur)="onTouched()"
 | 
					    <ng-select name="correspondent" [(ngModel)]="value"
 | 
				
			||||||
      [disabled]="disabled" [style.color]="textColor" [style.background]="backgroundColor">
 | 
					      [disabled]="disabled"
 | 
				
			||||||
      <option *ngIf="allowNull" [ngValue]="null" class="form-control">---</option>
 | 
					      [style.color]="textColor"
 | 
				
			||||||
      <option *ngFor="let i of items" [ngValue]="i.id" class="form-control">{{i.name}}</option>
 | 
					      [style.background]="backgroundColor"
 | 
				
			||||||
    </select>
 | 
					      (change)="onChange(value)"
 | 
				
			||||||
 | 
					      (blur)="onTouched()">
 | 
				
			||||||
 | 
					      <ng-option *ngFor="let i of items" [value]="i.id">{{i.name}}</ng-option>
 | 
				
			||||||
 | 
					    </ng-select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div *ngIf="showPlusButton()" class="input-group-append">
 | 
					    <div *ngIf="showPlusButton()" class="input-group-append">
 | 
				
			||||||
      <button class="btn btn-outline-secondary" type="button" (click)="createNew.emit()">
 | 
					      <button class="btn btn-outline-secondary" type="button" (click)="createNew.emit()">
 | 
				
			||||||
        <svg class="buttonicon" fill="currentColor">
 | 
					        <svg class="buttonicon" fill="currentColor">
 | 
				
			||||||
@ -15,4 +19,4 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
 | 
					  <small *ngIf="hint" class="form-text text-muted">{{hint}}</small>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					// styles for ng-select child are in styles.scss
 | 
				
			||||||
@ -1,30 +1,41 @@
 | 
				
			|||||||
<div class="form-group">
 | 
					<div class="form-group paperless-input-select paperless-input-tags">
 | 
				
			||||||
  <label for="exampleFormControlTextarea1">Tags</label>
 | 
					  <label for="tags">Tags</label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="input-group">
 | 
					  <div class="input-group flex-nowrap">
 | 
				
			||||||
    <div class="form-control tags-form-control" id="tags">
 | 
					    <ng-select name="tags" [items]="tags" bindLabel="name" bindValue="id" [(ngModel)]="displayValue"
 | 
				
			||||||
      <app-tag class="mr-2" *ngFor="let id of displayValue" [tag]="getTag(id)" (click)="removeTag(id)"></app-tag>
 | 
					      [multiple]="true"
 | 
				
			||||||
    </div>
 | 
					      [closeOnSelect]="false"
 | 
				
			||||||
 | 
					      [disabled]="disabled"
 | 
				
			||||||
 | 
					      (change)="ngSelectChange()">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="input-group-append" ngbDropdown placement="top-right">
 | 
					      <ng-template ng-label-tmp let-item="item">
 | 
				
			||||||
      <button class="btn btn-outline-secondary" type="button" ngbDropdownToggle></button>
 | 
					        <span class="tag-wrap tag-wrap-delete" (click)="removeTag(item.id)">
 | 
				
			||||||
      <div ngbDropdownMenu class="scrollable-menu shadow">
 | 
					          <svg width="1.2em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
 | 
				
			||||||
        <button type="button" *ngFor="let tag of tags" ngbDropdownItem (click)="addTag(tag.id)">
 | 
					            <use xlink:href="assets/bootstrap-icons.svg#x"/>
 | 
				
			||||||
          <app-tag [tag]="tag"></app-tag>
 | 
					          </svg>
 | 
				
			||||||
        </button>
 | 
					          <app-tag style="background-color: none;" [tag]="getTag(item.id)"></app-tag>
 | 
				
			||||||
      </div>
 | 
					        </span>
 | 
				
			||||||
    </div>
 | 
					      </ng-template>
 | 
				
			||||||
 | 
					      <ng-template ng-option-tmp let-item="item" let-index="index" let-search="searchTerm">
 | 
				
			||||||
 | 
					        <div class="tag-wrap">
 | 
				
			||||||
 | 
					          <div class="selected-icon d-inline-block mr-1">
 | 
				
			||||||
 | 
					            <svg *ngIf="displayValue.includes(item.id)" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
 | 
				
			||||||
 | 
					              <use xlink:href="assets/bootstrap-icons.svg#check"/>
 | 
				
			||||||
 | 
					            </svg>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <app-tag class="mr-2" [tag]="getTag(item.id)"></app-tag>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </ng-template>
 | 
				
			||||||
 | 
					    </ng-select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="input-group-append">
 | 
					    <div class="input-group-append">
 | 
				
			||||||
 | 
					 | 
				
			||||||
      <button class="btn btn-outline-secondary" type="button" (click)="createTag()">
 | 
					      <button class="btn btn-outline-secondary" type="button" (click)="createTag()">
 | 
				
			||||||
        <svg class="buttonicon" fill="currentColor">
 | 
					        <svg class="buttonicon" fill="currentColor">
 | 
				
			||||||
          <use xlink:href="assets/bootstrap-icons.svg#plus" />
 | 
					          <use xlink:href="assets/bootstrap-icons.svg#plus" />
 | 
				
			||||||
        </svg>
 | 
					        </svg>
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <small class="form-text text-muted" *ngIf="hint">{{hint}}</small>
 | 
					  <small class="form-text text-muted" *ngIf="hint">{{hint}}</small>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,12 @@
 | 
				
			|||||||
.tags-form-control {
 | 
					.selected-icon {
 | 
				
			||||||
  height: auto;
 | 
					  min-width: 1em;
 | 
				
			||||||
 | 
					  min-height: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tag-wrap {
 | 
				
			||||||
 | 
					  font-size: 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.scrollable-menu {
 | 
					.tag-wrap-delete {
 | 
				
			||||||
  height: auto;
 | 
					  cursor: pointer;
 | 
				
			||||||
  max-height: 300px;
 | 
					}
 | 
				
			||||||
  overflow-x: hidden;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onChange = (newValue: number[]) => {};
 | 
					  onChange = (newValue: number[]) => {};
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
  onTouched = () => {};
 | 
					  onTouched = () => {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  writeValue(newValue: number[]): void {
 | 
					  writeValue(newValue: number[]): void {
 | 
				
			||||||
@ -66,29 +66,28 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
 | 
				
			|||||||
  removeTag(id) {
 | 
					  removeTag(id) {
 | 
				
			||||||
    let index = this.displayValue.indexOf(id)
 | 
					    let index = this.displayValue.indexOf(id)
 | 
				
			||||||
    if (index > -1) {
 | 
					    if (index > -1) {
 | 
				
			||||||
      this.displayValue.splice(index, 1)
 | 
					      let oldValue = this.displayValue
 | 
				
			||||||
 | 
					      oldValue.splice(index, 1)
 | 
				
			||||||
 | 
					      this.displayValue = [...oldValue]
 | 
				
			||||||
      this.onChange(this.displayValue)
 | 
					      this.onChange(this.displayValue)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  addTag(id) {
 | 
					 | 
				
			||||||
    let index = this.displayValue.indexOf(id)
 | 
					 | 
				
			||||||
    if (index == -1) {
 | 
					 | 
				
			||||||
      this.displayValue.push(id)
 | 
					 | 
				
			||||||
      this.onChange(this.displayValue)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  createTag() {
 | 
					  createTag() {
 | 
				
			||||||
    var modal = this.modalService.open(TagEditDialogComponent, {backdrop: 'static'})
 | 
					    var modal = this.modalService.open(TagEditDialogComponent, {backdrop: 'static'})
 | 
				
			||||||
    modal.componentInstance.dialogMode = 'create'
 | 
					    modal.componentInstance.dialogMode = 'create'
 | 
				
			||||||
    modal.componentInstance.success.subscribe(newTag => {
 | 
					    modal.componentInstance.success.subscribe(newTag => {
 | 
				
			||||||
      this.tagService.listAll().subscribe(tags => {
 | 
					      this.tagService.listAll().subscribe(tags => {
 | 
				
			||||||
        this.tags = tags.results
 | 
					        this.tags = tags.results
 | 
				
			||||||
        this.addTag(newTag.id)
 | 
					        this.displayValue = [...this.displayValue, newTag.id]
 | 
				
			||||||
 | 
					        this.onChange(this.displayValue)
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngSelectChange() {
 | 
				
			||||||
 | 
					    this.value = this.displayValue
 | 
				
			||||||
 | 
					    this.onChange(this.displayValue)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -52,9 +52,9 @@
 | 
				
			|||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                        <app-input-date-time titleDate="Date created" formControlName="created"></app-input-date-time>
 | 
					                        <app-input-date-time titleDate="Date created" formControlName="created"></app-input-date-time>
 | 
				
			||||||
                        <app-input-select [items]="correspondents" title="Correspondent" formControlName="correspondent"
 | 
					                        <app-input-select [items]="correspondents" title="Correspondent" formControlName="correspondent"
 | 
				
			||||||
                            allowNull="true" (createNew)="createCorrespondent()"></app-input-select>
 | 
					                            (createNew)="createCorrespondent()"></app-input-select>
 | 
				
			||||||
                        <app-input-select [items]="documentTypes" title="Document type" formControlName="document_type"
 | 
					                        <app-input-select [items]="documentTypes" title="Document type" formControlName="document_type"
 | 
				
			||||||
                            allowNull="true" (createNew)="createDocumentType()"></app-input-select>
 | 
					                            (createNew)="createDocumentType()"></app-input-select>
 | 
				
			||||||
                        <app-input-tags formControlName="tags" title="Tags"></app-input-tags>
 | 
					                        <app-input-tags formControlName="tags" title="Tags"></app-input-tags>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    </ng-template>
 | 
					                    </ng-template>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
@import "theme";
 | 
					@import "theme";
 | 
				
			||||||
 | 
					 | 
				
			||||||
@import "node_modules/bootstrap/scss/bootstrap";
 | 
					@import "node_modules/bootstrap/scss/bootstrap";
 | 
				
			||||||
 | 
					@import "~@ng-select/ng-select/themes/default.theme.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.toolbaricon {
 | 
					.toolbaricon {
 | 
				
			||||||
  width: 1.2em;
 | 
					  width: 1.2em;
 | 
				
			||||||
@ -20,7 +19,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
body {
 | 
					body {
 | 
				
			||||||
  font-size: .875rem;
 | 
					  font-size: 0.875rem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.form-control-dark {
 | 
					.form-control-dark {
 | 
				
			||||||
@ -65,4 +64,39 @@ body {
 | 
				
			|||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  background-size: 1rem;
 | 
					  background-size: 1rem;
 | 
				
			||||||
  float: right;
 | 
					  float: right;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.paperless-input-select {
 | 
				
			||||||
 | 
					  .ng-select {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    flex: 1 1 auto;
 | 
				
			||||||
 | 
					    margin-bottom: 0;
 | 
				
			||||||
 | 
					    min-height: calc(1.5em + 0.75rem + 5px);
 | 
				
			||||||
 | 
					    line-height: 1.5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .ng-select-container {
 | 
				
			||||||
 | 
					      height: 100%;
 | 
				
			||||||
 | 
					      border-top-right-radius: 0;
 | 
				
			||||||
 | 
					      border-bottom-right-radius: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .ng-value-container .ng-input {
 | 
				
			||||||
 | 
					        top: 10px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected,
 | 
				
			||||||
 | 
					    .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-selected.ng-option-marked {
 | 
				
			||||||
 | 
					      background: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.paperless-input-tags {
 | 
				
			||||||
 | 
					  .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value {
 | 
				
			||||||
 | 
					    background-color: transparent;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .ng-select.ng-select-multiple .ng-select-container .ng-value-container {
 | 
				
			||||||
 | 
					    padding-top: 1px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user