Frontend: Add photos to new album
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
1cc8cefc92
commit
4ab44c5c23
|
@ -103,6 +103,13 @@
|
|||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
|
||||
<!-- v-list-tile v-if="config.albums.length === 0"
|
||||
@click.stop="createAlbum">
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Create Album</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile -->
|
||||
|
||||
<v-list-tile v-for="(album, index) in config.albums"
|
||||
:key="index"
|
||||
:to="{ name: 'album', params: { uuid: album.AlbumUUID, slug: album.AlbumSlug } }">
|
||||
|
@ -225,6 +232,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Album from "../model/album";
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
export default {
|
||||
name: "p-navigation",
|
||||
data() {
|
||||
|
@ -240,10 +250,17 @@
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
showNavigation: function () {
|
||||
showNavigation () {
|
||||
this.drawer = true;
|
||||
this.mini = false;
|
||||
},
|
||||
createAlbum() {
|
||||
let name = DateTime.local().toFormat("LLLL yyyy");
|
||||
const album = new Album({AlbumName: name, AlbumFavorite: true});
|
||||
album.save().then((a) => {
|
||||
console.log("created", a)
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
this.$session.logout();
|
||||
},
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
@click.stop="dialog.album = true"
|
||||
class="p-photo-clipboard-album"
|
||||
>
|
||||
<v-icon>create_new_folder</v-icon>
|
||||
<v-icon>folder</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn
|
||||
|
@ -105,7 +105,7 @@
|
|||
v-if="album"
|
||||
class="p-photo-clipboard-delete"
|
||||
>
|
||||
<v-icon>remove_circle</v-icon>
|
||||
<v-icon>delete_outline</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
fab
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
<v-container fluid class="pb-2 pr-2 pl-2">
|
||||
<v-layout row wrap>
|
||||
<v-flex xs3 text-xs-center>
|
||||
<v-icon size="54" color="grey lighten-1">folder</v-icon>
|
||||
<v-icon size="54" color="grey lighten-1" v-if="newAlbum">create_new_folder</v-icon>
|
||||
<v-icon size="54" color="grey lighten-1" v-else>folder</v-icon>
|
||||
</v-flex>
|
||||
<v-flex xs9 text-xs-left align-self-center>
|
||||
<v-autocomplete
|
||||
v-model="album"
|
||||
:items="albums"
|
||||
browser-autocomplete="off"
|
||||
hint="Album Name"
|
||||
:items="items"
|
||||
:search-input.sync="search"
|
||||
:loading="loading"
|
||||
hide-details
|
||||
|
@ -26,7 +29,9 @@
|
|||
<translate>Cancel</translate>
|
||||
</v-btn>
|
||||
<v-btn color="blue-grey lighten-2" depressed dark @click.stop="confirm"
|
||||
class="p-photo-dialog-confirm"><translate>Add to album</translate>
|
||||
class="p-photo-dialog-confirm">
|
||||
<span v-if="newAlbum">{{ labels.createAlbum }}</span>
|
||||
<span v-else>{{ labels.addToAlbum }}</span>
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
@ -44,12 +49,16 @@
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
loading: false,
|
||||
search: null,
|
||||
newAlbum: null,
|
||||
album: "",
|
||||
albums: [],
|
||||
items: [],
|
||||
labels: {
|
||||
select: this.$gettext("Select album"),
|
||||
addToAlbum: this.$gettext("Add to album"),
|
||||
createAlbum: this.$gettext("Create album"),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -58,29 +67,59 @@
|
|||
this.$emit('cancel');
|
||||
},
|
||||
confirm() {
|
||||
this.$emit('confirm', this.album);
|
||||
if(this.album === "" && this.newAlbum) {
|
||||
console.log("NEW", this.album, this.newAlbum);
|
||||
this.loading = true;
|
||||
|
||||
this.newAlbum.save().then((a) => {
|
||||
this.loading = false;
|
||||
this.$emit('confirm', a.AlbumUUID);
|
||||
});
|
||||
} else {
|
||||
console.log("OLD", this.album, this.newAlbum);
|
||||
this.$emit('confirm', this.album);
|
||||
}
|
||||
},
|
||||
},
|
||||
updated() {
|
||||
if(this.albums.length > 0) {
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
q: "",
|
||||
count: 1000,
|
||||
offset: 0,
|
||||
};
|
||||
|
||||
Album.search(params).then(response => {
|
||||
if(response.models.length > 0) {
|
||||
this.album = response.models[0].AlbumUUID;
|
||||
queryServer(q) {
|
||||
if(this.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.albums = response.models;
|
||||
this.loading = false;
|
||||
});
|
||||
this.loading = true;
|
||||
|
||||
const params = {
|
||||
q: q,
|
||||
count: 1000,
|
||||
offset: 0,
|
||||
};
|
||||
|
||||
Album.search(params).then(response => {
|
||||
this.loading = false;
|
||||
|
||||
if(response.models.length > 0 && !this.album) {
|
||||
this.album = response.models[0].AlbumUUID;
|
||||
}
|
||||
|
||||
this.albums = response.models;
|
||||
this.items = [...this.albums];
|
||||
}).catch(() => this.loading = false);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
search (q) {
|
||||
const exists = this.albums.findIndex((album) => album.AlbumName === q);
|
||||
|
||||
if (exists !== -1 || !q) {
|
||||
this.items = this.albums;
|
||||
this.newAlbum = null;
|
||||
} else {
|
||||
this.newAlbum = new Album({AlbumName: q, AlbumUUID: ""});
|
||||
this.items = this.albums.concat([this.newAlbum]);
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.queryServer("");
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
methods: {
|
||||
viewType() {
|
||||
let queryParam = this.$route.query['view'];
|
||||
let defaultType = window.localStorage.getItem("photo_view_type");
|
||||
let storedType = window.localStorage.getItem("album_view_type");
|
||||
|
||||
if (queryParam) {
|
||||
|
@ -101,6 +102,8 @@
|
|||
return queryParam;
|
||||
} else if (storedType) {
|
||||
return storedType;
|
||||
} else if (defaultType) {
|
||||
return defaultType;
|
||||
} else if (window.innerWidth < 960) {
|
||||
return 'mosaic';
|
||||
} else if (window.innerWidth > 1600) {
|
||||
|
|
|
@ -132,6 +132,7 @@
|
|||
import Album from "model/album";
|
||||
import {DateTime} from "luxon";
|
||||
import Util from "common/util";
|
||||
import Event from "pubsub-js";
|
||||
|
||||
export default {
|
||||
name: 'p-page-albums',
|
||||
|
@ -156,6 +157,7 @@
|
|||
const settings = {};
|
||||
|
||||
return {
|
||||
subId: null,
|
||||
results: [],
|
||||
loading: true,
|
||||
scrollDisabled: true,
|
||||
|
@ -313,10 +315,17 @@
|
|||
} else {
|
||||
this.selection.push(uuid)
|
||||
}
|
||||
},
|
||||
onCount() {
|
||||
// TODO
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.search();
|
||||
this.subId = Event.subscribe("count.albums", (ev, data) => this.onCount(ev, data));
|
||||
},
|
||||
destroyed() {
|
||||
Event.unsubscribe(this.subId);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -223,17 +223,17 @@
|
|||
}).catch(() => this.loading = false);
|
||||
},
|
||||
onKeypress(event) {
|
||||
if (event.key === "Escape") {
|
||||
/* if (event.key === "Escape") {
|
||||
this.$clipboard.clear();
|
||||
}
|
||||
} */
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.search();
|
||||
window.addEventListener('keydown', this.onKeypress);
|
||||
// window.addEventListener('keydown', this.onKeypress);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('keydown', this.onKeypress);
|
||||
// window.removeEventListener('keydown', this.onKeypress);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -80,6 +80,9 @@ func CreateAlbum(router *gin.RouterGroup, conf *config.Config) {
|
|||
}
|
||||
|
||||
m := entity.NewAlbum(f.AlbumName)
|
||||
m.AlbumFavorite = f.AlbumFavorite
|
||||
|
||||
log.Debugf("create album: %+v %+v", f, m)
|
||||
|
||||
if res := conf.Db().Create(m); res.Error != nil {
|
||||
log.Error(res.Error.Error())
|
||||
|
@ -93,6 +96,8 @@ func CreateAlbum(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
event.Success(fmt.Sprintf("album \"%s\" created", m.AlbumName))
|
||||
|
||||
// event.Publish("config.updated", event.Data(conf.ClientConfig()))
|
||||
|
||||
c.JSON(http.StatusOK, m)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ func LabelThumbnail(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
if !ok {
|
||||
log.Errorf("invalid type: %s", typeName)
|
||||
c.Data(http.StatusBadRequest, "image/svg+xml", photoIconSvg)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,8 @@ func LabelThumbnail(router *gin.RouterGroup, conf *config.Config) {
|
|||
file, err := r.FindLabelThumbByUUID(labelUUID)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": util.UcFirst(err.Error())})
|
||||
log.Errorf(err.Error())
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -153,7 +154,7 @@ func LabelThumbnail(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
if !util.Exists(fileName) {
|
||||
log.Errorf("could not find original for thumbnail: %s", fileName)
|
||||
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
|
||||
// Set missing flag so that the file doesn't show up in search results anymore
|
||||
file.FileMissing = true
|
||||
|
@ -166,7 +167,7 @@ func LabelThumbnail(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
if err != nil {
|
||||
log.Errorf("could not read thumbnail: %s", err)
|
||||
c.Data(http.StatusInternalServerError, "image/svg+xml", photoIconSvg)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -178,7 +179,7 @@ func LabelThumbnail(router *gin.RouterGroup, conf *config.Config) {
|
|||
} else {
|
||||
log.Errorf("could not create thumbnail: %s", err)
|
||||
|
||||
c.Data(http.StatusInternalServerError, "image/svg+xml", photoIconSvg)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
|
|
@ -65,13 +65,13 @@ func TestLabelThumbnail(t *testing.T) {
|
|||
LabelThumbnail(router, ctx)
|
||||
result := PerformRequest(app, "GET", "/api/v1/labels/dog/thumbnail/xxx")
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, result.Code)
|
||||
assert.Equal(t, http.StatusOK, result.Code)
|
||||
})
|
||||
t.Run("invalid label", func(t *testing.T) {
|
||||
app, router, ctx := NewApiTest()
|
||||
LabelThumbnail(router, ctx)
|
||||
result := PerformRequest(app, "GET", "/api/v1/labels/xxx/thumbnail/tile_500")
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, result.Code)
|
||||
assert.Equal(t, http.StatusOK, result.Code)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,3 +9,6 @@ var photoIconSvg = []byte(`
|
|||
var albumIconSvg = []byte(`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/></svg>`)
|
||||
|
||||
var labelIconSvg = []byte(`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg>`)
|
||||
|
|
|
@ -63,17 +63,26 @@ func (s *Repo) FindLabelThumbBySlug(labelSlug string) (file entity.File, err err
|
|||
|
||||
// FindLabelThumbByUUID returns a label preview file based on the label UUID.
|
||||
func (s *Repo) FindLabelThumbByUUID(labelUUID string) (file entity.File, err error) {
|
||||
// s.db.LogMode(true)
|
||||
|
||||
if err := s.db.Where("files.file_primary AND files.deleted_at IS NULL").
|
||||
// Search matching label
|
||||
err = s.db.Where("files.file_primary AND files.deleted_at IS NULL").
|
||||
Joins("JOIN labels ON labels.label_uuid = ?", labelUUID).
|
||||
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id").
|
||||
Order("photos_labels.label_uncertainty ASC").
|
||||
First(&file).Error; err != nil {
|
||||
return file, err
|
||||
First(&file).Error
|
||||
|
||||
if err == nil {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
return file, nil
|
||||
// If failed, search for category instead
|
||||
err = s.db.Where("files.file_primary AND files.deleted_at IS NULL").
|
||||
Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id").
|
||||
Joins("JOIN categories c ON photos_labels.label_id = c.label_id").
|
||||
Joins("JOIN labels ON c.category_id = labels.id AND labels.label_uuid= ?", labelUUID).
|
||||
Order("photos_labels.label_uncertainty ASC").
|
||||
First(&file).Error
|
||||
|
||||
return file, err
|
||||
}
|
||||
|
||||
// Labels searches labels based on their name.
|
||||
|
|
Loading…
Reference in a new issue