mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Add automatic coloring of tags
Please see this as proposal on how to implement automatic/random colors for tags while keeping the current set of hard coded colors in place (at least in the frontend). Bear with me as I have even less Angular knowledge than Django and just tried to get away with as few changes as possible. :-) AIUI you want to change to a color picking system anyways in the future, which could also play well with this. fixes #51
This commit is contained in:
		
							
								
								
									
										1
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Pipfile
									
									
									
									
									
								
							| @@ -40,6 +40,7 @@ whoosh="~=2.7.4" | ||||
| inotifyrecursive = ">=0.3.4" | ||||
| ocrmypdf = "*" | ||||
| tqdm = "*" | ||||
| colorhash = "*" | ||||
|  | ||||
| [dev-packages] | ||||
| coveralls = "*" | ||||
|   | ||||
| @@ -1,2 +1,2 @@ | ||||
| <span *ngIf="!clickable" class="badge" [style.background]="getColour().value" [style.color]="getColour().textColor">{{tag.name}}</span> | ||||
| <a [routerLink]="" [title]="linkTitle" *ngIf="clickable" class="badge" [style.background]="getColour().value" [style.color]="getColour().textColor">{{tag.name}}</a> | ||||
| <span *ngIf="!clickable" class="badge" [style.background]="getColour().id" [style.color]="getColour().textColor">{{tag.name}}</span> | ||||
| <a [routerLink]="" [title]="linkTitle" *ngIf="clickable" class="badge" [style.background]="getColour().id" [style.color]="getColour().textColor">{{tag.name}}</a> | ||||
| @@ -23,7 +23,11 @@ export class TagComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   getColour() { | ||||
|     return TAG_COLOURS.find(c => c.id == this.tag.colour) | ||||
|     var color = TAG_COLOURS.find(c => c.id == this.tag.colour) | ||||
|     if (color) { | ||||
|       return color | ||||
|     } | ||||
|     return { id: this.tag.colour, name: this.tag.colour, textColor: "#ffffff" } | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     </div> | ||||
|     <div class="modal-body"> | ||||
|       <app-input-text title="Name" formControlName="name"></app-input-text> | ||||
|       <app-input-select title="Colour" [items]="getColours()" formControlName="colour" [textColor]="getColor(objectForm.value.colour).textColor" [backgroundColor]="getColor(objectForm.value.colour).value"></app-input-select> | ||||
|       <app-input-select title="Colour" [items]="getColours()" formControlName="colour" [textColor]="getColor(objectForm.value.colour).textColor" [backgroundColor]="getColor(objectForm.value.colour).id"></app-input-select> | ||||
|       <app-input-check title="Inbox tag" formControlName="is_inbox_tag" hint="Inbox tags are automatically assigned to all consumed documents."></app-input-check> | ||||
|       <app-input-text title="Match" formControlName="match"></app-input-text> | ||||
|       <app-input-select title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|   | ||||
| @@ -20,7 +20,7 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> { | ||||
|   getForm(): FormGroup { | ||||
|     return new FormGroup({ | ||||
|       name: new FormControl(''), | ||||
|       colour: new FormControl(1), | ||||
|       colour: new FormControl(''), | ||||
|       is_inbox_tag: new FormControl(false), | ||||
|       matching_algorithm: new FormControl(1), | ||||
|       match: new FormControl(""), | ||||
| @@ -32,7 +32,7 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> { | ||||
|     return TAG_COLOURS | ||||
|   } | ||||
|  | ||||
|   getColor(id: number) { | ||||
|   getColor(id) { | ||||
|     return TAG_COLOURS.find(c => c.id == id) | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,7 @@ | ||||
|     <tr *ngFor="let tag of data"> | ||||
|       <td scope="row">{{ tag.name }}</td> | ||||
|       <td scope="row"><span class="badge" [style.color]="getColor(tag.colour).textColor" | ||||
|           [style.background-color]="getColor(tag.colour).value">{{ getColor(tag.colour).name }}</span></td> | ||||
|           [style.background-color]="tag.colour">{{ getColor(tag.colour).name }}</span></td> | ||||
|       <td scope="row">{{ getMatching(tag) }}</td> | ||||
|       <td scope="row">{{ tag.document_count }}</td> | ||||
|       <td scope="row"> | ||||
|   | ||||
| @@ -15,10 +15,14 @@ export class TagListComponent extends GenericListComponent<PaperlessTag> { | ||||
|  | ||||
|   constructor(tagService: TagService, modalService: NgbModal) { | ||||
|     super(tagService, modalService, TagEditDialogComponent) | ||||
|    } | ||||
|   } | ||||
|  | ||||
|   getColor(id) { | ||||
|     return TAG_COLOURS.find(c => c.id == id) | ||||
|     var color = TAG_COLOURS.find(c => c.id == id) | ||||
|     if (color) { | ||||
|       return color | ||||
|     } | ||||
|     return { id: id, name: id, textColor: "#ffffff" } | ||||
|   } | ||||
|  | ||||
|   getObjectName(object: PaperlessTag) { | ||||
|   | ||||
| @@ -3,24 +3,25 @@ import { ObjectWithId } from './object-with-id'; | ||||
|  | ||||
|  | ||||
| export const TAG_COLOURS = [ | ||||
|     {id: 1, value: "#a6cee3", name: "Light Blue", textColor: "#000000"}, | ||||
|     {id: 2, value: "#1f78b4", name: "Blue", textColor: "#ffffff"}, | ||||
|     {id: 3, value: "#b2df8a", name: "Light Green", textColor: "#000000"}, | ||||
|     {id: 4, value: "#33a02c", name: "Green", textColor: "#000000"}, | ||||
|     {id: 5, value: "#fb9a99", name: "Light Red", textColor: "#000000"}, | ||||
|     {id: 6, value: "#e31a1c", name: "Red ", textColor: "#ffffff"}, | ||||
|     {id: 7, value: "#fdbf6f", name: "Light Orange", textColor: "#000000"}, | ||||
|     {id: 8, value: "#ff7f00", name: "Orange", textColor: "#000000"}, | ||||
|     {id: 9, value: "#cab2d6", name: "Light Violet", textColor: "#000000"}, | ||||
|     {id: 10, value: "#6a3d9a", name: "Violet", textColor: "#ffffff"}, | ||||
|     {id: 11, value: "#b15928", name: "Brown", textColor: "#000000"}, | ||||
|     {id: 12, value: "#000000", name: "Black", textColor: "#ffffff"}, | ||||
|     {id: 13, value: "#cccccc", name: "Light Grey", textColor: "#000000"} | ||||
|     { id: "", name: "Auto", textColor: "#000000" }, | ||||
|     { id: "#a6cee3", name: "Light Blue", textColor: "#000000" }, | ||||
|     { id: "#1f78b4", name: "Blue", textColor: "#ffffff" }, | ||||
|     { id: "#b2df8a", name: "Light Green", textColor: "#000000" }, | ||||
|     { id: "#33a02c", name: "Green", textColor: "#000000" }, | ||||
|     { id: "#fb9a99", name: "Light Red", textColor: "#000000" }, | ||||
|     { id: "#e31a1c", name: "Red ", textColor: "#ffffff" }, | ||||
|     { id: "#fdbf6f", name: "Light Orange", textColor: "#000000" }, | ||||
|     { id: "#ff7f00", name: "Orange", textColor: "#000000" }, | ||||
|     { id: "#cab2d6", name: "Light Violet", textColor: "#000000" }, | ||||
|     { id: "#6a3d9a", name: "Violet", textColor: "#ffffff" }, | ||||
|     { id: "#b15928", name: "Brown", textColor: "#000000" }, | ||||
|     { id: "#000000", name: "Black", textColor: "#ffffff" }, | ||||
|     { id: "#cccccc", name: "Light Grey", textColor: "#000000" } | ||||
| ] | ||||
|  | ||||
| export interface PaperlessTag extends MatchingModel { | ||||
|  | ||||
|     colour?: number | ||||
|     colour?: string | ||||
|  | ||||
|     is_inbox_tag?: boolean | ||||
|  | ||||
|   | ||||
							
								
								
									
										70
									
								
								src/documents/migrations/1006_migrate_tag_colour.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/documents/migrations/1006_migrate_tag_colour.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| # Generated by Django 3.1.4 on 2020-12-02 21:43 | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
| COLOURS_OLD = { | ||||
|     1: "#a6cee3", | ||||
|     2: "#1f78b4", | ||||
|     3: "#b2df8a", | ||||
|     4: "#33a02c", | ||||
|     5: "#fb9a99", | ||||
|     6: "#e31a1c", | ||||
|     7: "#fdbf6f", | ||||
|     8: "#ff7f00", | ||||
|     9: "#cab2d6", | ||||
|     10: "#6a3d9a", | ||||
|     11: "#b15928", | ||||
|     12: "#000000", | ||||
|     13: "#cccccc", | ||||
| } | ||||
|  | ||||
|  | ||||
| def forward(apps, schema_editor): | ||||
|     Tag = apps.get_model('documents', 'Tag') | ||||
|  | ||||
|     for tag in Tag.objects.all(): | ||||
|         colour_old_id = tag.colour_old | ||||
|         rgb = COLOURS_OLD[colour_old_id] | ||||
|         tag.colour = rgb | ||||
|         tag.save() | ||||
|  | ||||
|  | ||||
| def reverse(apps, schema_editor): | ||||
|     Tag = apps.get_model('documents', 'Tag') | ||||
|  | ||||
|     def _get_colour_id(rdb): | ||||
|         for idx, rdbx in COLOURS_OLD.items(): | ||||
|             if rdbx == rdb: | ||||
|                 return idx | ||||
|         # Return colour 1 if we can't match anything | ||||
|         return 1 | ||||
|  | ||||
|     for tag in Tag.objects.all(): | ||||
|         colour_id = _get_colour_id(tag.colour) | ||||
|         tag.colour_old = colour_id | ||||
|         tag.save() | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('documents', '1005_checksums'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.RenameField( | ||||
|             model_name='tag', | ||||
|             old_name='colour', | ||||
|             new_name='colour_old', | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='tag', | ||||
|             name='colour', | ||||
|             field=models.CharField(blank=True, max_length=7), | ||||
|         ), | ||||
|         migrations.RunPython(forward, reverse), | ||||
|         migrations.RemoveField( | ||||
|             model_name='tag', | ||||
|             name='colour_old', | ||||
|         ) | ||||
|     ] | ||||
| @@ -6,6 +6,7 @@ import re | ||||
| from collections import OrderedDict | ||||
|  | ||||
| import dateutil.parser | ||||
| from colorhash import ColorHash | ||||
| from django.conf import settings | ||||
| from django.db import models | ||||
| from django.utils import timezone | ||||
| @@ -84,23 +85,7 @@ class Correspondent(MatchingModel): | ||||
|  | ||||
| class Tag(MatchingModel): | ||||
|  | ||||
|     COLOURS = ( | ||||
|         (1, "#a6cee3"), | ||||
|         (2, "#1f78b4"), | ||||
|         (3, "#b2df8a"), | ||||
|         (4, "#33a02c"), | ||||
|         (5, "#fb9a99"), | ||||
|         (6, "#e31a1c"), | ||||
|         (7, "#fdbf6f"), | ||||
|         (8, "#ff7f00"), | ||||
|         (9, "#cab2d6"), | ||||
|         (10, "#6a3d9a"), | ||||
|         (11, "#b15928"), | ||||
|         (12, "#000000"), | ||||
|         (13, "#cccccc") | ||||
|     ) | ||||
|  | ||||
|     colour = models.PositiveIntegerField(choices=COLOURS, default=1) | ||||
|     colour = models.CharField(blank=True, max_length=7) | ||||
|  | ||||
|     is_inbox_tag = models.BooleanField( | ||||
|         default=False, | ||||
| @@ -108,6 +93,15 @@ class Tag(MatchingModel): | ||||
|                   "documents will be tagged with inbox tags." | ||||
|     ) | ||||
|  | ||||
|     def save(self, *args, **kwargs): | ||||
|         if self.colour == "": | ||||
|             self.colour = ColorHash( | ||||
|                 self.name, | ||||
|                 lightness=(0.35, 0.45, 0.55, 0.65), | ||||
|                 saturation=(0.2, 0.3, 0.4, 0.5)).hex | ||||
|  | ||||
|         super().save(*args, **kwargs) | ||||
|  | ||||
|  | ||||
| class DocumentType(MatchingModel): | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 jayme-github
					jayme-github