mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	add file-types bar to statistics widget (#2914)
This commit is contained in:
		| @@ -13,14 +13,33 @@ | ||||
|         <ng-container i18n>Total characters</ng-container>: | ||||
|         <span class="badge bg-secondary text-light rounded-pill">{{statistics?.character_count | number}}</span> | ||||
|       </div> | ||||
|       <div class="list-group-item d-flex justify-content-between align-items-center"> | ||||
|         <div class="flex-grow-1"><ng-container i18n>File types</ng-container>:</div> | ||||
|         <div class="d-flex flex-column flex-grow-1 filetypes-list"> | ||||
|           <div *ngFor="let filetype of statistics?.document_file_type_counts; let i = index" class="d-flex justify-content-between align-items-center"> | ||||
|             <span class="fst-italic text-muted text-truncate pe-3">{{filetype.mime_type}}</span> | ||||
|             <span class="badge bg-secondary text-light rounded-pill">{{getFileTypePercent(filetype) | number: '1.0-1'}}%</span> | ||||
|  | ||||
|       <div class="list-group-item widget-container"> | ||||
|         <div class="file-type-bar"> | ||||
|           <ng-container | ||||
|             *ngFor=" | ||||
|               let fileType of fileTypeDataArray; | ||||
|               let isFirst = first; | ||||
|               let isLast = last | ||||
|             " | ||||
|           > | ||||
|             <div | ||||
|               class="file-type" | ||||
|               [style.width.%]="fileType.percentage" | ||||
|               [style.backgroundColor]="fileType.color" | ||||
|               [ngClass]="{ 'rounded-left': isFirst, 'rounded-right': isLast }" | ||||
|             ></div> | ||||
|           </ng-container> | ||||
|         </div> | ||||
|         <ng-container *ngFor="let fileType of fileTypeDataArray"> | ||||
|           <div class="file-type-label"> | ||||
|             <div | ||||
|               class="file-type-color" | ||||
|               [style.backgroundColor]="fileType.color" | ||||
|             ></div> | ||||
|             <span>{{ fileType.name }} ({{ fileType.percentage }}%)</span> | ||||
|           </div> | ||||
|         </ng-container> | ||||
|       </div> | ||||
|     </div> | ||||
|   </ng-container> | ||||
|   | ||||
| @@ -1,7 +1,26 @@ | ||||
| .flex-column { | ||||
|     row-gap: 0.2rem; | ||||
| .file-type-bar { | ||||
|   display: flex; | ||||
|   height: 10px; | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
|  | ||||
| .filetypes-list { | ||||
|     max-width: 75%; | ||||
| .file-type { | ||||
|   height: 100%; | ||||
| } | ||||
| .file-type-label { | ||||
|   align-items: center; | ||||
|   float: left; | ||||
|   padding-right: 10px; | ||||
| } | ||||
| .file-type-color { | ||||
|   width: 10px; | ||||
|   height: 10px; | ||||
|   border-radius: 50%; | ||||
|   display: inline-block; | ||||
|   margin-right: 5px; | ||||
| } | ||||
| .rounded-left { | ||||
|   border-radius: 5px 0 0 5px; | ||||
| } | ||||
| .rounded-right { | ||||
|   border-radius: 0 5px 5px 0; | ||||
| } | ||||
|   | ||||
| @@ -44,15 +44,26 @@ export class StatisticsWidgetComponent implements OnInit, OnDestroy { | ||||
|     return this.http.get(`${environment.apiBaseUrl}statistics/`) | ||||
|   } | ||||
|  | ||||
|   fileTypeDataArray = [] | ||||
|  | ||||
|   private fileTypeColors = [ | ||||
|     '#e84118', // red | ||||
|     '#00a8ff', // blue | ||||
|     '#4cd137', // green | ||||
|     '#9c88ff', // purple | ||||
|     '#fbc531', // yellow | ||||
|     '#7f8fa6', // gray | ||||
|   ] | ||||
|  | ||||
|   reload() { | ||||
|     this.loading = true | ||||
|     this.getStatistics().subscribe((statistics) => { | ||||
|       this.loading = false | ||||
|       // truncate the list and sum others | ||||
|       if (statistics.document_file_type_counts?.length > 4) { | ||||
|         let others = statistics.document_file_type_counts.slice(4) | ||||
|       const fileTypeMax = 5 | ||||
|       if (statistics.document_file_type_counts?.length > fileTypeMax) { | ||||
|         let others = statistics.document_file_type_counts.slice(fileTypeMax) | ||||
|         statistics.document_file_type_counts = | ||||
|           statistics.document_file_type_counts.slice(0, 4) | ||||
|           statistics.document_file_type_counts.slice(0, fileTypeMax) | ||||
|         statistics.document_file_type_counts.push({ | ||||
|           mime_type: $localize`other`, | ||||
|           mime_type_count: others.reduce( | ||||
| @@ -63,9 +74,26 @@ export class StatisticsWidgetComponent implements OnInit, OnDestroy { | ||||
|         }) | ||||
|       } | ||||
|       this.statistics = statistics | ||||
|  | ||||
|       this.updateFileTypePercentages() | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   private updateFileTypePercentages() { | ||||
|     let colorIndex = 0 | ||||
|     this.fileTypeDataArray = this.statistics.document_file_type_counts.map( | ||||
|       (fileType) => { | ||||
|         const percentage = | ||||
|           (fileType.mime_type_count / this.statistics?.documents_total) * 100 | ||||
|         return { | ||||
|           name: this.getMimeTypeName(fileType.mime_type), | ||||
|           percentage: percentage.toFixed(2), | ||||
|           color: this.fileTypeColors[colorIndex++], | ||||
|         } | ||||
|       } | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     this.reload() | ||||
|     this.subscription = this.consumerStatusService | ||||
| @@ -88,7 +116,33 @@ export class StatisticsWidgetComponent implements OnInit, OnDestroy { | ||||
|     ]) | ||||
|   } | ||||
|  | ||||
|   getFileTypePercent(filetype: DocumentFileType): number { | ||||
|     return (filetype.mime_type_count / this.statistics?.documents_total) * 100 | ||||
|   getMimeTypeName(mimeType: string): string { | ||||
|     const mimeTypesMap: { [key: string]: string } = { | ||||
|       'application/msword': 'Microsoft Word', | ||||
|       'application/vnd.openxmlformats-officedocument.wordprocessingml.document': | ||||
|         'Microsoft Word', | ||||
|       'application/vnd.ms-excel': 'Microsoft Excel', | ||||
|       'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': | ||||
|         'Microsoft Excel', | ||||
|       'application/vnd.ms-powerpoint': 'Microsoft PowerPoint', | ||||
|       'application/vnd.openxmlformats-officedocument.presentationml.presentation': | ||||
|         'Microsoft PowerPoint', | ||||
|       'application/pdf': 'PDF', | ||||
|       'application/vnd.oasis.opendocument.text': 'OpenDocument Text', | ||||
|       'application/vnd.oasis.opendocument.spreadsheet': | ||||
|         'OpenDocument Spreadsheet', | ||||
|       'application/vnd.oasis.opendocument.presentation': | ||||
|         'OpenDocument Presentation', | ||||
|       'application/vnd.oasis.opendocument.graphics': 'OpenDocument Graphics', | ||||
|       'application/rtf': 'Rich Text Format', | ||||
|       'text/plain': 'Plain Text', | ||||
|       'text/csv': 'CSV', | ||||
|       'image/jpeg': 'JPEG', | ||||
|       'image/png': 'PNG', | ||||
|       'image/gif': 'GIF', | ||||
|       'image/svg+xml': 'SVG', | ||||
|     } | ||||
|  | ||||
|     return mimeTypesMap[mimeType] || mimeType | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tobias Schürg
					Tobias Schürg