mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Such a mess
This commit is contained in:
		| @@ -12,6 +12,8 @@ | ||||
|  | ||||
|     <pngx-input-color i18n-title title="Color" formControlName="color" [error]="error?.color"></pngx-input-color> | ||||
|  | ||||
|     <pngx-input-select i18n-title title="Parent" formControlName="parent" [items]="tags" [allowNull]="true" [error]="error?.parent"></pngx-input-select> | ||||
|  | ||||
|     <pngx-input-check i18n-title title="Inbox tag" formControlName="is_inbox_tag" i18n-hint hint="Inbox tags are automatically assigned to all consumed documents."></pngx-input-check> | ||||
|     <pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select> | ||||
|     @if (patternRequired) { | ||||
|   | ||||
| @@ -36,6 +36,8 @@ import { TextComponent } from '../../input/text/text.component' | ||||
|   ], | ||||
| }) | ||||
| export class TagEditDialogComponent extends EditDialogComponent<Tag> { | ||||
|   tags: Tag[] | ||||
|  | ||||
|   constructor( | ||||
|     service: TagService, | ||||
|     activeModal: NgbActiveModal, | ||||
| @@ -43,6 +45,10 @@ export class TagEditDialogComponent extends EditDialogComponent<Tag> { | ||||
|     settingsService: SettingsService | ||||
|   ) { | ||||
|     super(service, activeModal, userService, settingsService) | ||||
|  | ||||
|     this.service.listAll().subscribe((result) => { | ||||
|       this.tags = result.results | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   getCreateTitle() { | ||||
| @@ -58,6 +64,7 @@ export class TagEditDialogComponent extends EditDialogComponent<Tag> { | ||||
|       name: new FormControl(''), | ||||
|       color: new FormControl(randomColor()), | ||||
|       is_inbox_tag: new FormControl(false), | ||||
|       parent: new FormControl(null), | ||||
|       matching_algorithm: new FormControl(DEFAULT_MATCHING_ALGORITHM), | ||||
|       match: new FormControl(''), | ||||
|       is_insensitive: new FormControl(true), | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|       <div class="input-group flex-nowrap"> | ||||
|         <ng-select #tagSelect name="tags" [items]="tags" bindLabel="name" bindValue="id" [(ngModel)]="value" | ||||
|           [disabled]="disabled" | ||||
|           [multiple]="true" | ||||
|           [multiple]="multiple" | ||||
|           [closeOnSelect]="false" | ||||
|           [clearSearchOnAdd]="true" | ||||
|           [hideSelected]="tags.length > 0" | ||||
|   | ||||
| @@ -99,6 +99,9 @@ export class TagsComponent implements OnInit, ControlValueAccessor { | ||||
|   @Input() | ||||
|   horizontal: boolean = false | ||||
|  | ||||
|   @Input() | ||||
|   multiple: boolean = true | ||||
|  | ||||
|   @Output() | ||||
|   filterDocuments = new EventEmitter<Tag[]>() | ||||
|  | ||||
|   | ||||
| @@ -53,59 +53,7 @@ | ||||
|         </tr> | ||||
|       } | ||||
|       @for (object of data; track object) { | ||||
|         <tr (click)="toggleSelected(object); $event.stopPropagation();" class="data-row fade" [class.show]="show"> | ||||
|           <td> | ||||
|             <div class="form-check m-0 ms-2 me-n2"> | ||||
|               <input type="checkbox" class="form-check-input" id="{{typeName}}{{object.id}}" [checked]="selectedObjects.has(object.id)" (click)="toggleSelected(object); $event.stopPropagation();"> | ||||
|               <label class="form-check-label" for="{{typeName}}{{object.id}}"></label> | ||||
|             </div> | ||||
|           </td> | ||||
|           <td scope="row"><button class="btn btn-link ms-0 ps-0 text-start" (click)="userCanEdit(object) ? openEditDialog(object) : null; $event.stopPropagation()">{{ object.name }}</button> </td> | ||||
|           <td scope="row" class="d-none d-sm-table-cell">{{ getMatching(object) }}</td> | ||||
|           <td scope="row">{{ object.document_count }}</td> | ||||
|           @for (column of extraColumns; track column) { | ||||
|             <td scope="row" [ngClass]="{ 'd-none d-sm-table-cell' : column.hideOnMobile }"> | ||||
|               @if (column.rendersHtml) { | ||||
|                 <div [innerHtml]="column.valueFn.call(null, object) | safeHtml"></div> | ||||
|               } @else { | ||||
|                 {{ column.valueFn.call(null, object) }} | ||||
|               } | ||||
|             </td> | ||||
|           } | ||||
|           <td scope="row"> | ||||
|             <div class="btn-toolbar gap-2"> | ||||
|               <div class="btn-group d-block d-sm-none"> | ||||
|                 <div ngbDropdown container="body" class="d-inline-block"> | ||||
|                   <button type="button" class="btn btn-link" id="actionsMenuMobile" (click)="$event.stopPropagation()" ngbDropdownToggle> | ||||
|                     <i-bs name="three-dots-vertical"></i-bs> | ||||
|                   </button> | ||||
|                   <div ngbDropdownMenu aria-labelledby="actionsMenuMobile"> | ||||
|                     <button (click)="openEditDialog(object)" *pngxIfPermissions="{ action: PermissionAction.Change, type: permissionType }" ngbDropdownItem i18n>Edit</button> | ||||
|                     <button class="text-danger" (click)="openDeleteDialog(object)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: permissionType }" ngbDropdownItem i18n>Delete</button> | ||||
|                     @if (object.document_count > 0) { | ||||
|                       <button (click)="filterDocuments(object)" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }" ngbDropdownItem i18n>Filter Documents ({{ object.document_count }})</button> | ||||
|                     } | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div class="btn-group d-none d-sm-inline-block"> | ||||
|                 <button class="btn btn-sm btn-outline-secondary" (click)="openEditDialog(object); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Change, type: permissionType }" [disabled]="!userCanEdit(object)"> | ||||
|                   <i-bs width="1em" height="1em" name="pencil"></i-bs> <ng-container i18n>Edit</ng-container> | ||||
|                 </button> | ||||
|                 <button class="btn btn-sm btn-outline-danger" (click)="openDeleteDialog(object); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Delete, type: permissionType }" [disabled]="!userCanDelete(object)"> | ||||
|                   <i-bs width="1em" height="1em" name="trash"></i-bs> <ng-container i18n>Delete</ng-container> | ||||
|                 </button> | ||||
|               </div> | ||||
|               @if (object.document_count > 0) { | ||||
|                 <div class="btn-group d-none d-sm-inline-block"> | ||||
|                   <button class="btn btn-sm btn-outline-secondary" (click)="filterDocuments(object); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }"> | ||||
|                     <i-bs width="1em" height="1em" name="filter"></i-bs> <ng-container i18n>Documents</ng-container><span class="badge bg-light text-secondary ms-2">{{ object.document_count }}</span> | ||||
|                   </button> | ||||
|                 </div> | ||||
|               } | ||||
|             </div> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <ng-container [ngTemplateOutlet]="objectRow" [ngTemplateOutletContext]="{ object: object, depth: 0 }"></ng-container> | ||||
|       } | ||||
|     </tbody> | ||||
|   </table> | ||||
| @@ -126,3 +74,67 @@ | ||||
|     } | ||||
|   </div> | ||||
| } | ||||
|  | ||||
| <ng-template #objectRow let-object="object" let-depth="depth"> | ||||
|   <tr (click)="toggleSelected(object); $event.stopPropagation();" class="data-row fade" [class.show]="show"> | ||||
|     <td> | ||||
|       <div class="form-check m-0 ms-2 me-n2"> | ||||
|         <input type="checkbox" class="form-check-input" id="{{typeName}}{{object.id}}" [checked]="selectedObjects.has(object.id)" (click)="toggleSelected(object); $event.stopPropagation();"> | ||||
|         <label class="form-check-label" for="{{typeName}}{{object.id}}"></label> | ||||
|       </div> | ||||
|     </td> | ||||
|     <td scope="row" class="depth-{{depth}}"> | ||||
|       <button class="btn btn-link ms-0 ps-0 text-start" (click)="userCanEdit(object) ? openEditDialog(object) : null; $event.stopPropagation()">{{ object.name }}</button> | ||||
|     </td> | ||||
|     <td scope="row" class="d-none d-sm-table-cell">{{ getMatching(object) }}</td> | ||||
|     <td scope="row">{{ object.document_count }}</td> | ||||
|     @for (column of extraColumns; track column) { | ||||
|       <td scope="row" [ngClass]="{ 'd-none d-sm-table-cell' : column.hideOnMobile }"> | ||||
|         @if (column.rendersHtml) { | ||||
|           <div [innerHtml]="column.valueFn.call(null, object) | safeHtml"></div> | ||||
|         } @else { | ||||
|           {{ column.valueFn.call(null, object) }} | ||||
|         } | ||||
|       </td> | ||||
|     } | ||||
|     <td scope="row"> | ||||
|       <div class="btn-toolbar gap-2"> | ||||
|         <div class="btn-group d-block d-sm-none"> | ||||
|           <div ngbDropdown container="body" class="d-inline-block"> | ||||
|             <button type="button" class="btn btn-link" id="actionsMenuMobile" (click)="$event.stopPropagation()" ngbDropdownToggle> | ||||
|               <i-bs name="three-dots-vertical"></i-bs> | ||||
|             </button> | ||||
|             <div ngbDropdownMenu aria-labelledby="actionsMenuMobile"> | ||||
|               <button (click)="openEditDialog(object)" *pngxIfPermissions="{ action: PermissionAction.Change, type: permissionType }" ngbDropdownItem i18n>Edit</button> | ||||
|               <button class="text-danger" (click)="openDeleteDialog(object)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: permissionType }" ngbDropdownItem i18n>Delete</button> | ||||
|               @if (object.document_count > 0) { | ||||
|                 <button (click)="filterDocuments(object)" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }" ngbDropdownItem i18n>Filter Documents ({{ object.document_count }})</button> | ||||
|               } | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="btn-group d-none d-sm-inline-block"> | ||||
|           <button class="btn btn-sm btn-outline-secondary" (click)="openEditDialog(object); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Change, type: permissionType }" [disabled]="!userCanEdit(object)"> | ||||
|             <i-bs width="1em" height="1em" name="pencil"></i-bs> <ng-container i18n>Edit</ng-container> | ||||
|           </button> | ||||
|           <button class="btn btn-sm btn-outline-danger" (click)="openDeleteDialog(object); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Delete, type: permissionType }" [disabled]="!userCanDelete(object)"> | ||||
|             <i-bs width="1em" height="1em" name="trash"></i-bs> <ng-container i18n>Delete</ng-container> | ||||
|           </button> | ||||
|         </div> | ||||
|         @if (object.document_count > 0) { | ||||
|           <div class="btn-group d-none d-sm-inline-block"> | ||||
|             <button class="btn btn-sm btn-outline-secondary" (click)="filterDocuments(object); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }"> | ||||
|               <i-bs width="1em" height="1em" name="filter"></i-bs> <ng-container i18n>Documents</ng-container><span class="badge bg-light text-secondary ms-2">{{ object.document_count }}</span> | ||||
|             </button> | ||||
|           </div> | ||||
|         } | ||||
|       </div> | ||||
|     </td> | ||||
|   </tr> | ||||
|  | ||||
|   @if (object.children && object.children.length > 0) { | ||||
|     @for (child of object.children; track child) { | ||||
|       <ng-container [ngTemplateOutlet]="objectRow" [ngTemplateOutletContext]="{ object: child, depth: depth + 1 }"></ng-container> | ||||
|     } | ||||
|   } | ||||
| </ng-template> | ||||
|   | ||||
| @@ -10,3 +10,27 @@ tbody tr:last-child td { | ||||
| .form-check { | ||||
|     min-height: 0; | ||||
| } | ||||
|  | ||||
| .depth-0 { | ||||
|     padding-left: 0; | ||||
| } | ||||
|  | ||||
| .depth-1 { | ||||
|     padding-left: 20px; | ||||
| } | ||||
|  | ||||
| .depth-2 { | ||||
|     padding-left: 40px; | ||||
| } | ||||
|  | ||||
| .depth-3 { | ||||
|     padding-left: 60px; | ||||
| } | ||||
|  | ||||
| .depth-4 { | ||||
|     padding-left: 80px; | ||||
| } | ||||
|  | ||||
| .depth-5 { | ||||
|     padding-left: 100px; | ||||
| } | ||||
|   | ||||
| @@ -131,6 +131,10 @@ export abstract class ManagementListComponent<T extends MatchingModel> | ||||
|     this.reloadData() | ||||
|   } | ||||
|  | ||||
|   protected filterData(data: T[]): T[] { | ||||
|     return data | ||||
|   } | ||||
|  | ||||
|   reloadData(extraParams: { [key: string]: any } = null) { | ||||
|     this.loading = true | ||||
|     this.clearSelection() | ||||
| @@ -147,7 +151,7 @@ export abstract class ManagementListComponent<T extends MatchingModel> | ||||
|       .pipe( | ||||
|         takeUntil(this.unsubscribeNotifier), | ||||
|         tap((c) => { | ||||
|           this.data = c.results | ||||
|           this.data = this.filterData(c.results) | ||||
|           this.collectionSize = c.count | ||||
|         }), | ||||
|         delay(100) | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { NgClass, TitleCasePipe } from '@angular/common' | ||||
| import { NgClass, NgTemplateOutlet, TitleCasePipe } from '@angular/common' | ||||
| import { Component } from '@angular/core' | ||||
| import { FormsModule, ReactiveFormsModule } from '@angular/forms' | ||||
| import { | ||||
| @@ -36,6 +36,7 @@ import { ManagementListComponent } from '../management-list/management-list.comp | ||||
|     FormsModule, | ||||
|     ReactiveFormsModule, | ||||
|     NgClass, | ||||
|     NgTemplateOutlet, | ||||
|     NgbDropdownModule, | ||||
|     NgbPaginationModule, | ||||
|     NgxBootstrapIconsModule, | ||||
| @@ -76,4 +77,8 @@ export class TagListComponent extends ManagementListComponent<Tag> { | ||||
|   getDeleteMessage(object: Tag) { | ||||
|     return $localize`Do you really want to delete the tag "${object.name}"?` | ||||
|   } | ||||
|  | ||||
|   filterData(data: Tag[]) { | ||||
|     return data.filter((tag) => !tag.parent) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -6,4 +6,8 @@ export interface Tag extends MatchingModel { | ||||
|   text_color?: string | ||||
|  | ||||
|   is_inbox_tag?: boolean | ||||
|  | ||||
|   parent?: number // Tag ID | ||||
|  | ||||
|   children?: Tag[] // read-only | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon