diff --git a/frontend/src/dialog/photo-edit/details.vue b/frontend/src/dialog/photo-edit/details.vue index 0381b8182..b4c05b9b7 100644 --- a/frontend/src/dialog/photo-edit/details.vue +++ b/frontend/src/dialog/photo-edit/details.vue @@ -349,15 +349,19 @@ this.model.TakenAt = utcDate; - const localDate = DateTime.fromISO(utcDate).setZone(this.model.TimeZone); + let localDate = DateTime.fromISO(utcDate); + + if(this.model.TimeZone) { + localDate = localDate.setZone(this.model.TimeZone); + } else { + localDate = localDate.toUTC(0); + } this.model.TakenAtLocal = localDate.toISO({ suppressMilliseconds: true, includeOffset: false, }) + "Z"; - console.log(this.model.TakenAt, this.model.TakenAtLocal); - return localDate.toLocaleString(DateTime.TIME_24_WITH_SECONDS); }, countryOptions() { diff --git a/frontend/src/model/abstract.js b/frontend/src/model/abstract.js index c33766736..77a8a1278 100644 --- a/frontend/src/model/abstract.js +++ b/frontend/src/model/abstract.js @@ -1,5 +1,6 @@ import Api from "common/api"; import Form from "common/form"; +import Event from "pubsub-js"; class Abstract { constructor(values) { @@ -25,6 +26,18 @@ class Abstract { return this; } + publishValues(values) { + if (!values) return; + + this.setValues(values); + + if(this.hasId()) { + Event.publish(`model.${this.constructor.getCollectionResource()}.${this.getId()}`, this.getValues()); + } + + return this; + } + getValues(changed) { const result = {}; const defaults = this.getDefaults(); @@ -78,11 +91,11 @@ class Abstract { return this.update(); } - return Api.post(this.constructor.getCollectionResource(), this.getValues()).then((response) => Promise.resolve(this.setValues(response.data))); + return Api.post(this.constructor.getCollectionResource(), this.getValues()).then((response) => Promise.resolve(this.publishValues(response.data))); } update() { - return Api.put(this.getEntityResource(), this.getValues(true)).then((response) => Promise.resolve(this.setValues(response.data))); + return Api.put(this.getEntityResource(), this.getValues(true)).then((response) => Promise.resolve(this.publishValues(response.data))); } remove() { diff --git a/frontend/src/model/photo.js b/frontend/src/model/photo.js index fe9a44bba..3af67aec7 100644 --- a/frontend/src/model/photo.js +++ b/frontend/src/model/photo.js @@ -184,7 +184,9 @@ class Photo extends Abstract { } getCamera() { - if (this.CameraModel) { + if(this.Camera) { + return this.Camera.CameraMake + " " + this.Camera.CameraModel; + } else if (this.CameraModel) { return this.CameraMake + " " + this.CameraModel; } @@ -213,12 +215,12 @@ class Photo extends Abstract { addLabel(name) { return Api.post(this.getEntityResource() + "/label", {LabelName: name}) - .then((response) => Promise.resolve(this.setValues(response.data))); + .then((response) => Promise.resolve(this.publishValues(response.data))); } removeLabel(id) { return Api.delete(this.getEntityResource() + "/label/" + id) - .then((response) => Promise.resolve(this.setValues(response.data))); + .then((response) => Promise.resolve(this.publishValues(response.data))); } static getCollectionResource() { diff --git a/frontend/src/pages/photos.vue b/frontend/src/pages/photos.vue index 54821e1aa..104c0a57d 100644 --- a/frontend/src/pages/photos.vue +++ b/frontend/src/pages/photos.vue @@ -86,6 +86,8 @@ return { uploadSubId: null, countSubId: null, + modelSubId: null, + listen: false, dirty: false, results: [], scrollDisabled: true, @@ -156,6 +158,8 @@ Object.assign(params, this.lastFilter); + this.listen = false; + Photo.search(params).then(response => { this.results = this.results.concat(response.models); @@ -164,7 +168,7 @@ if (this.scrollDisabled) { this.$notify.info(this.$gettext('All ') + this.results.length + this.$gettext(' photos loaded')); } - }); + }).finally(() => this.listen = true); }, updateQuery() { const query = { @@ -220,12 +224,11 @@ this.offset = 0; this.loading = true; + this.listen = false; const params = this.searchParams(); Photo.search(params).then(response => { - this.loading = false; - this.dirty = false; this.results = response.models; this.scrollDisabled = (response.models.length < this.pageSize); @@ -243,20 +246,34 @@ this.$nextTick(() => this.$emit("scrollRefresh")); } - }).catch(() => this.loading = false); + }).finally(() => { + this.dirty = false; + this.loading = false; + this.listen = true; + }); }, onImportCompleted() { this.dirty = true; - console.log("onImportCompleted", this.selection, this.offset); - if(this.selection.length === 0 && this.offset === 0) { - console.log("REFRESH"); this.refresh(); } }, onCount() { this.dirty = true; + }, + onModelUpdate(ev, data) { + if(!this.listen) { + return + } + + const found = this.results.find((m) => m.ID === data.ID); + + if(found) { + found.setValues(data); + this.$forceUpdate(); + this.$forceUpdate(); + } } }, created() { @@ -264,10 +281,12 @@ this.uploadSubId = Event.subscribe("import.completed", (ev, data) => this.onImportCompleted(ev, data)); this.countSubId = Event.subscribe("count.photos", (ev, data) => this.onCount(ev, data)); + this.modelSubId = Event.subscribe("model.photos", (ev, data) => this.onModelUpdate(ev, data)); }, destroyed() { Event.unsubscribe(this.uploadSubId); Event.unsubscribe(this.countSubId); + Event.unsubscribe(this.modelSubId); } }; diff --git a/frontend/src/resources/themes.json b/frontend/src/resources/themes.json index af43ddb1d..6950bedc5 100644 --- a/frontend/src/resources/themes.json +++ b/frontend/src/resources/themes.json @@ -10,7 +10,7 @@ "error": "#E57373", "info": "#0097A7", "success": "#00897B", - "warning": "#FFE082", + "warning": "#FFD740", "remove": "#E57373", "restore": "#64B5F6", "album": "#FFAB00", @@ -33,7 +33,7 @@ "error": "#E57373", "info": "#0097A7", "success": "#00897B", - "warning": "#FFE082", + "warning": "#FFD740", "remove": "#E57373", "restore": "#64B5F6", "album": "#FFAB00", @@ -56,7 +56,7 @@ "error": "#E57373", "info": "#0097A7", "success": "#00897B", - "warning": "#FFE082", + "warning": "#FFD740", "remove": "#E57373", "restore": "#64B5F6", "album": "#FFAB00", @@ -79,7 +79,7 @@ "error": "#E57373", "info": "#0097A7", "success": "#00897B", - "warning": "#FFE082", + "warning": "#FFD740", "remove": "#E57373", "restore": "#64B5F6", "album": "#FFAB00", @@ -102,7 +102,7 @@ "error": "#E57373", "info": "#0097A7", "success": "#00897B", - "warning": "#FFE082", + "warning": "#FFD740", "remove": "#E57373", "restore": "#64B5F6", "album": "#FFAB00", @@ -125,7 +125,7 @@ "error": "#E57373", "info": "#0097A7", "success": "#00897B", - "warning": "#FFE082", + "warning": "#FFD740", "remove": "#E57373", "restore": "#64B5F6", "album": "#FFAB00", diff --git a/internal/api/photo.go b/internal/api/photo.go index 3e8ed742d..d9369ff48 100644 --- a/internal/api/photo.go +++ b/internal/api/photo.go @@ -63,7 +63,14 @@ func UpdatePhoto(router *gin.RouterGroup, conf *config.Config) { event.Success("photo saved") - c.JSON(http.StatusOK, m) + p, err := q.PreloadPhotoByUUID(c.Param("uuid")) + + if err != nil { + c.AbortWithStatusJSON(http.StatusNotFound, ErrPhotoNotFound) + return + } + + c.JSON(http.StatusOK, p) }) } diff --git a/internal/entity/photo.go b/internal/entity/photo.go index 7e3badc02..8e5336371 100644 --- a/internal/entity/photo.go +++ b/internal/entity/photo.go @@ -47,8 +47,8 @@ type Photo struct { TakenAtChanged bool PhotoViews uint CountryChanged bool - Camera *Camera `json:"-"` - Lens *Lens `json:"-"` + Camera *Camera `json:"Camera"` + Lens *Lens `json:"Lens"` Location *Location `json:"-"` Place *Place `json:"-"` Files []File