From d7f0d2a7f214cdc28da1013fdfa792fb42b190b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gremaud?= Date: Thu, 3 Oct 2024 22:29:32 +0200 Subject: [PATCH] Add history + more components --- k356/app/settings.py | 4 +- k356/app/utils/models.py | 21 ++++- ...calitem_historicalitemrelation_and_more.py | 14 ++-- .../components/ItemDetail/template.html | 80 +++++++++++++++++-- .../templates/components/ItemDetail/vue.js | 47 +++++++++++ .../ItemRelationDetail/template.html | 6 +- .../components/ItemTypeDetail/template.html | 40 ++++++++++ .../components/ItemTypeDetail/vue.js | 46 +++++++++++ .../components/ItemView/template.html | 1 + k356/items/urls.py | 2 + k356/items/views/item_view.py | 59 ++++++++++++++ .../components/Loading/template.html | 6 +- k356/main/templates/components/Loading/vue.js | 4 + k356/templates/base.html | 4 +- .../base_components/glist/template.html | 9 ++- k356/templates/vue/index.js | 33 +++++++- k356/templates/vue/stores.js | 2 + .../migrations/0006_historicalusersettings.py | 4 +- 18 files changed, 352 insertions(+), 30 deletions(-) create mode 100644 k356/items/templates/components/ItemTypeDetail/template.html create mode 100644 k356/items/templates/components/ItemTypeDetail/vue.js diff --git a/k356/app/settings.py b/k356/app/settings.py index 71da10d..7113879 100644 --- a/k356/app/settings.py +++ b/k356/app/settings.py @@ -157,10 +157,8 @@ USE_I18N = True USE_TZ = True -# Default primary key field type -# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +SIMPLE_HISTORY_HISTORY_ID_USE_UUID = True from app.settingsLocal import * diff --git a/k356/app/utils/models.py b/k356/app/utils/models.py index cff5aa8..35fc9d6 100644 --- a/k356/app/utils/models.py +++ b/k356/app/utils/models.py @@ -1,6 +1,9 @@ from django.contrib.auth import get_user_model +from django.contrib.postgres.expressions import ArraySubquery from django.db import models +from django.db.models import OuterRef from django.db.models.fields.related import RelatedField +from django.db.models.functions import JSONObject from app.utils.helpers import recursive_getattr @@ -78,7 +81,23 @@ class BaseQuerySet(models.QuerySet): for field_name, _ in self.headers().items(): fields.append(field_name) - return self.values(*fields) + if hasattr(self.model, "history"): + qs = self.annotate( + history=ArraySubquery( + self.model.history.model.objects.filter(id=OuterRef("id")).values( + json=JSONObject( + id="history_id", + date="history_date", + ) + ) + ) + ) + fields.append("history") + + else: + qs = self + + return qs.values(*fields) class BaseManager(models.Manager.from_queryset(BaseQuerySet)): diff --git a/k356/items/migrations/0006_historicalitem_historicalitemrelation_and_more.py b/k356/items/migrations/0006_historicalitem_historicalitemrelation_and_more.py index 9b77cfc..dd115a8 100644 --- a/k356/items/migrations/0006_historicalitem_historicalitemrelation_and_more.py +++ b/k356/items/migrations/0006_historicalitem_historicalitemrelation_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.1 on 2024-10-01 13:41 +# Generated by Django 5.1.1 on 2024-10-01 14:14 import django.db.models.deletion import simple_history.models @@ -23,7 +23,7 @@ class Migration(migrations.Migration): ("last_modified_at", models.DateTimeField(blank=True, editable=False)), ("name", models.TextField(max_length=2048)), ("description", models.TextField(max_length=2048)), - ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ("history_date", models.DateTimeField(db_index=True)), ("history_change_reason", models.CharField(max_length=100, null=True)), ("history_type", models.CharField(choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], max_length=1)), @@ -71,7 +71,7 @@ class Migration(migrations.Migration): ("custom_identifier", models.TextField(blank=True, max_length=2048, null=True)), ("created_at", models.DateTimeField(blank=True, editable=False)), ("last_modified_at", models.DateTimeField(blank=True, editable=False)), - ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ("history_date", models.DateTimeField(db_index=True)), ("history_change_reason", models.CharField(max_length=100, null=True)), ("history_type", models.CharField(choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], max_length=1)), @@ -120,7 +120,7 @@ class Migration(migrations.Migration): ("custom_identifier", models.TextField(blank=True, max_length=2048, null=True)), ("created_at", models.DateTimeField(blank=True, editable=False)), ("last_modified_at", models.DateTimeField(blank=True, editable=False)), - ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ("history_date", models.DateTimeField(db_index=True)), ("history_change_reason", models.CharField(max_length=100, null=True)), ("history_type", models.CharField(choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], max_length=1)), @@ -158,7 +158,7 @@ class Migration(migrations.Migration): ("created_at", models.DateTimeField(blank=True, editable=False)), ("last_modified_at", models.DateTimeField(blank=True, editable=False)), ("value", models.TextField(max_length=2048)), - ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ("history_date", models.DateTimeField(db_index=True)), ("history_change_reason", models.CharField(max_length=100, null=True)), ("history_type", models.CharField(choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], max_length=1)), @@ -234,7 +234,7 @@ class Migration(migrations.Migration): max_length=32, ), ), - ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ("history_date", models.DateTimeField(db_index=True)), ("history_change_reason", models.CharField(max_length=100, null=True)), ("history_type", models.CharField(choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], max_length=1)), @@ -272,7 +272,7 @@ class Migration(migrations.Migration): ("created_at", models.DateTimeField(blank=True, editable=False)), ("last_modified_at", models.DateTimeField(blank=True, editable=False)), ("value", models.TextField(max_length=2048)), - ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ("history_date", models.DateTimeField(db_index=True)), ("history_change_reason", models.CharField(max_length=100, null=True)), ("history_type", models.CharField(choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], max_length=1)), diff --git a/k356/items/templates/components/ItemDetail/template.html b/k356/items/templates/components/ItemDetail/template.html index 767751a..e2230cc 100644 --- a/k356/items/templates/components/ItemDetail/template.html +++ b/k356/items/templates/components/ItemDetail/template.html @@ -8,14 +8,82 @@ + + + + {% trans "History version" %} + + + + + + + + mdi-eye + {% trans "View history" %} + + + + + + {% trans "History for" %} [[ $route.params.id ]] + + + + + + + + + + + + + + + mdi-arrow-left + {% trans "Go back" %} + + + + + + + diff --git a/k356/items/templates/components/ItemDetail/vue.js b/k356/items/templates/components/ItemDetail/vue.js index 679bda0..8881064 100644 --- a/k356/items/templates/components/ItemDetail/vue.js +++ b/k356/items/templates/components/ItemDetail/vue.js @@ -3,6 +3,12 @@ ItemDetail = { router_path: "/ItemDetail/:id", delimiters: ["[[", "]]"], + data: function() { + return { + dialog: false, + } + }, + computed: { object: function() { return this.$store.state.items.items.find(i => i.id == this.$route.params.id) @@ -47,10 +53,51 @@ ItemDetail = { all_properties: function() { return this.$store.state.properties.items }, + + history: function() { + return this.$store.state.history.items + }, }, methods: { + async showHistory () { + const response = await this.$http.get(Urls["items:history"](this.$route.params.id)) + + this.$store.state.history.headers = response.data.headers + this.$store.dispatch("history/setItems", { self: this, items: response.data.history }) + this.dialog = true + }, + + showType () { + this.$router.push({ name: "ItemTypeDetail", params: { id: this.object.type }}) + }, + + closeDialog () { + this.dialog = false + this.$store.state.history.items = [] + }, + + async deleteVersion(version) { + const response = await this.$http.delete(Urls["items:history.edit"](this.$route.params.id, version.history_id)) + + Swal.fire({title: "{{_('Version successfully deleted') | escapejs}}", icon: "success", position:"top-end", showConfirmButton: false, toast: true, timer: 1000}) + + this.closeDialog() + }, + + async useVersion(version) { + const response = await this.$http.post(Urls["items:history.edit"](this.$route.params.id, version.history_id)) + const efields = this.$store.getters["items/encryptedFields"] + const new_item = await this.decryptObject(efields, response.data.object) + + this.$store.commit("items/editItem", new_item) + + Swal.fire({title: "{{_('Version successfully restored') | escapejs}}", icon: "success", position:"top-end", showConfirmButton: false, toast: true, timer: 1000}) + + this.closeDialog() + }, + linkedPropertyEdition (method, item) { return this.object_edit("items:linked.property.edit", "items:linked.property.create", 'linkedProperties', method, item) }, diff --git a/k356/items/templates/components/ItemRelationDetail/template.html b/k356/items/templates/components/ItemRelationDetail/template.html index dd1388a..f6f0f77 100644 --- a/k356/items/templates/components/ItemRelationDetail/template.html +++ b/k356/items/templates/components/ItemRelationDetail/template.html @@ -12,11 +12,11 @@ [[ field.text ]]