From 995be4940208c919a09584fe9ed9c08c437f6bf5 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Mon, 15 Jul 2019 15:27:53 +0200 Subject: [PATCH 01/10] See #432: fixed an ordering issue on tag length --- api/funkwhale_api/tags/views.py | 3 +++ api/tests/tags/test_views.py | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/api/funkwhale_api/tags/views.py b/api/funkwhale_api/tags/views.py index d7b1d8aa5..1d052ca7b 100644 --- a/api/funkwhale_api/tags/views.py +++ b/api/funkwhale_api/tags/views.py @@ -1,6 +1,8 @@ from django.db.models import functions from rest_framework import viewsets +import django_filters.rest_framework + from funkwhale_api.users.oauth import permissions as oauth_permissions from . import filters @@ -20,3 +22,4 @@ class TagViewSet(viewsets.ReadOnlyModelViewSet): required_scope = "libraries" anonymous_policy = "setting" filterset_class = filters.TagFilter + filter_backends = [django_filters.rest_framework.DjangoFilterBackend] diff --git a/api/tests/tags/test_views.py b/api/tests/tags/test_views.py index fd3246adb..b42e9ab37 100644 --- a/api/tests/tags/test_views.py +++ b/api/tests/tags/test_views.py @@ -23,18 +23,21 @@ def test_tags_list_ordering_length(factories, logged_in_api_client): url = reverse("api:v1:tags-list") tags = [ factories["tags.Tag"](name="iamareallylongtag"), - factories["tags.Tag"](name="reallylongtag"), factories["tags.Tag"](name="short"), + factories["tags.Tag"](name="reallylongtag"), factories["tags.Tag"](name="bar"), ] expected = { "count": 4, "next": None, "previous": None, - "results": [serializers.TagSerializer(tag).data for tag in tags], + "results": [ + serializers.TagSerializer(tag).data + for tag in [tags[3], tags[1], tags[2], tags[0]] + ], } - response = logged_in_api_client.get(url, {"ordering": "-length"}) + response = logged_in_api_client.get(url, {"ordering": "length"}) assert response.data == expected From 9336fec430bf592833daedbe8d06aabec3dde9ba Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Mon, 15 Jul 2019 15:46:26 +0200 Subject: [PATCH 02/10] See #432: added some filters in tags API --- api/funkwhale_api/tags/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/funkwhale_api/tags/filters.py b/api/funkwhale_api/tags/filters.py index 4be4afeef..e0ac9675a 100644 --- a/api/funkwhale_api/tags/filters.py +++ b/api/funkwhale_api/tags/filters.py @@ -18,4 +18,4 @@ class TagFilter(filters.FilterSet): class Meta: model = models.Tag - fields = ["q"] + fields = {"q": ["exact"], "name": ["exact", "startswith"]} From d2b7db2caccb073359541f5342d1b186f636c434 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 16 Jul 2019 12:26:17 +0200 Subject: [PATCH 03/10] See #432: UI to suggest tags on tracks, albums and artists --- front/src/components/library/EditCard.vue | 53 ++++++++------- front/src/components/library/EditForm.vue | 22 +++++- front/src/components/library/TagsSelector.vue | 68 +++++++++++++++++++ front/src/edits.js | 38 ++++++++++- front/src/lodash.js | 1 + 5 files changed, 155 insertions(+), 27 deletions(-) create mode 100644 front/src/components/library/TagsSelector.vue diff --git a/front/src/components/library/EditCard.vue b/front/src/components/library/EditCard.vue index e72823aa7..bb8676cee 100644 --- a/front/src/components/library/EditCard.vue +++ b/front/src/components/library/EditCard.vue @@ -49,7 +49,7 @@ - + {{ field.id }} @@ -61,12 +61,12 @@ N/A - + {{ part.value }} - {{ field.new }} + {{ field.newRepr }} @@ -126,6 +126,7 @@ export default { } }, computed: { + configs: edits.getConfigs, canApprove: edits.getCanApprove, canDelete: edits.getCanDelete, previousState () { @@ -154,6 +155,32 @@ export default { namespace = 'library.artists.edit.detail' } return this.$router.resolve({name: namespace, params: {id, editId: this.obj.uuid}}).href + }, + + updatedFields () { + let payload = this.obj.payload + let previousState = this.previousState + let fields = Object.keys(payload) + let self = this + return fields.map((f) => { + let fieldConfig = edits.getFieldConfig(self.configs, this.obj.target.type, f) + let dummyRepr = (v) => { return v } + let getValueRepr = fieldConfig.getValueRepr || dummyRepr + let d = { + id: f, + } + if (previousState && previousState[f]) { + d.old = previousState[f] + d.oldRepr = castValue(getValueRepr(d.old.value)) + } + d.new = payload[f] + d.newRepr = castValue(getValueRepr(d.new)) + if (d.old) { + // we compute the diffs between the old and new values + d.diff = diffWordsWithSpace(d.oldRepr, d.newRepr) + } + return d + }) } }, methods: { @@ -184,26 +211,6 @@ export default { self.isLoading = false }) }, - getUpdatedFields (payload, previousState) { - let fields = Object.keys(payload) - return fields.map((f) => { - let d = { - id: f, - } - if (previousState && previousState[f]) { - d.old = previousState[f] - } - d.new = payload[f] - if (d.old) { - // we compute the diffs between the old and new values - - let oldValue = castValue(d.old.value) - let newValue = castValue(d.new) - d.diff = diffWordsWithSpace(oldValue, newValue) - } - return d - }) - } } } diff --git a/front/src/components/library/EditForm.vue b/front/src/components/library/EditForm.vue index 617917c68..ee462a1e2 100644 --- a/front/src/components/library/EditForm.vue +++ b/front/src/components/library/EditForm.vue @@ -77,10 +77,22 @@ +
@@ -110,13 +122,17 @@ import _ from '@/lodash' import axios from "axios" import EditList from '@/components/library/EditList' import EditCard from '@/components/library/EditCard' +import TagsSelector from '@/components/library/TagsSelector' import edits from '@/edits' +import lodash from '@/lodash' + export default { props: ["objectType", "object", "licenses"], components: { EditList, - EditCard + EditCard, + TagsSelector }, data() { return { @@ -159,7 +175,7 @@ export default { mutationPayload () { let self = this let changedFields = this.config.fields.filter(f => { - return self.values[f.id] != self.initialValues[f.id] + return !lodash.isEqual(self.values[f.id], self.initialValues[f.id]) }) if (changedFields.length === 0) { return null diff --git a/front/src/components/library/TagsSelector.vue b/front/src/components/library/TagsSelector.vue new file mode 100644 index 000000000..5494fe9f3 --- /dev/null +++ b/front/src/components/library/TagsSelector.vue @@ -0,0 +1,68 @@ + + diff --git a/front/src/edits.js b/front/src/edits.js index 76e92e841..5c9e9be88 100644 --- a/front/src/edits.js +++ b/front/src/edits.js @@ -1,3 +1,10 @@ +function getTagsValueRepr (val) { + if (!val) { + return '' + } + return val.slice().sort().join('\n') +} + export default { getConfigs () { return { @@ -10,6 +17,14 @@ export default { label: this.$pgettext('*/*/*/Noun', 'Name'), getValue: (obj) => { return obj.name } }, + { + id: 'tags', + type: 'tags', + required: true, + label: this.$pgettext('*/*/*/Noun', 'Tags'), + getValue: (obj) => { return obj.tags }, + getValueRepr: getTagsValueRepr + } ] }, album: { @@ -28,6 +43,14 @@ export default { label: this.$pgettext('Content/*/*/Noun', 'Release date'), getValue: (obj) => { return obj.release_date } }, + { + id: 'tags', + type: 'tags', + required: true, + label: this.$pgettext('*/*/*/Noun', 'Tags'), + getValue: (obj) => { return obj.tags }, + getValueRepr: getTagsValueRepr + } ] }, track: { @@ -61,6 +84,14 @@ export default { label: this.$pgettext('Content/*/*/Noun', 'License'), getValue: (obj) => { return obj.license }, }, + { + id: 'tags', + type: 'tags', + required: true, + label: this.$pgettext('*/*/*/Noun', 'Tags'), + getValue: (obj) => { return obj.tags }, + getValueRepr: getTagsValueRepr + } ] } } @@ -69,7 +100,12 @@ export default { getConfig () { return this.configs[this.objectType] }, - + getFieldConfig (configs, type, fieldId) { + let c = configs[type] + return c.fields.filter((f) => { + return f.id == fieldId + })[0] + }, getCurrentState () { let self = this let s = {} diff --git a/front/src/lodash.js b/front/src/lodash.js index 8cd3ed92f..31fdbaa58 100644 --- a/front/src/lodash.js +++ b/front/src/lodash.js @@ -12,4 +12,5 @@ export default { uniq: require('lodash/uniq'), remove: require('lodash/remove'), reverse: require('lodash/reverse'), + isEqual: require('lodash/isEqual'), } From 55cb7fc25dc99f7e6aa917249f4577c3c30eecae Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 16 Jul 2019 14:04:19 +0200 Subject: [PATCH 04/10] See #432: display tags on artist, album and track pages --- front/src/components/library/AlbumBase.vue | 5 ++- front/src/components/library/ArtistBase.vue | 6 +++- front/src/components/library/TrackBase.vue | 6 +++- front/src/components/tags/List.vue | 39 +++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 front/src/components/tags/List.vue diff --git a/front/src/components/library/AlbumBase.vue b/front/src/components/library/AlbumBase.vue index 016be2c37..083e5547b 100644 --- a/front/src/components/library/AlbumBase.vue +++ b/front/src/components/library/AlbumBase.vue @@ -13,6 +13,7 @@
+
@@ -103,6 +104,7 @@ import backend from "@/audio/backend" import PlayButton from "@/components/audio/PlayButton" import EmbedWizard from "@/components/audio/EmbedWizard" import Modal from '@/components/semantic/Modal' +import TagsList from "@/components/tags/List" const FETCH_URL = "albums/" @@ -123,7 +125,8 @@ export default { components: { PlayButton, EmbedWizard, - Modal + Modal, + TagsList, }, data() { return { diff --git a/front/src/components/library/ArtistBase.vue b/front/src/components/library/ArtistBase.vue index 3c21f603f..5472ee307 100644 --- a/front/src/components/library/ArtistBase.vue +++ b/front/src/components/library/ArtistBase.vue @@ -21,6 +21,7 @@
+
@@ -123,17 +124,20 @@ import PlayButton from "@/components/audio/PlayButton" import EmbedWizard from "@/components/audio/EmbedWizard" import Modal from '@/components/semantic/Modal' import RadioButton from "@/components/radios/Button" +import TagsList from "@/components/tags/List" const FETCH_URL = "albums/" + export default { props: ["id"], components: { PlayButton, EmbedWizard, Modal, - RadioButton + RadioButton, + TagsList, }, data() { return { diff --git a/front/src/components/library/TrackBase.vue b/front/src/components/library/TrackBase.vue index 2f3cc51a9..32942958b 100644 --- a/front/src/components/library/TrackBase.vue +++ b/front/src/components/library/TrackBase.vue @@ -17,6 +17,8 @@
+ +
@@ -121,6 +123,7 @@ import TrackFavoriteIcon from "@/components/favorites/TrackFavoriteIcon" import TrackPlaylistIcon from "@/components/playlists/TrackPlaylistIcon" import Modal from '@/components/semantic/Modal' import EmbedWizard from "@/components/audio/EmbedWizard" +import TagsList from "@/components/tags/List" const FETCH_URL = "tracks/" @@ -131,7 +134,8 @@ export default { TrackPlaylistIcon, TrackFavoriteIcon, Modal, - EmbedWizard + EmbedWizard, + TagsList, }, data() { return { diff --git a/front/src/components/tags/List.vue b/front/src/components/tags/List.vue new file mode 100644 index 000000000..9ffb0f1f0 --- /dev/null +++ b/front/src/components/tags/List.vue @@ -0,0 +1,39 @@ + + + From ccca292405d1536778bd0caa466430d4e6694324 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 16 Jul 2019 14:50:39 +0200 Subject: [PATCH 05/10] See #432: added tag filter on artist/album browse page --- front/package.json | 1 + front/src/components/library/Albums.vue | 31 ++++++++++++++++--- front/src/components/library/Artists.vue | 31 ++++++++++++++++--- front/src/components/library/TagsSelector.vue | 2 +- front/src/router/index.js | 2 ++ front/yarn.lock | 2 +- 6 files changed, 59 insertions(+), 10 deletions(-) diff --git a/front/package.json b/front/package.json index 54cf3c8e1..2c8f041f0 100644 --- a/front/package.json +++ b/front/package.json @@ -22,6 +22,7 @@ "masonry-layout": "^4.2.2", "moment": "^2.22.2", "fomantic-ui-css": "^2.7", + "qs": "^6.7.0", "showdown": "^1.8.6", "vue": "^2.5.17", "vue-gettext": "^2.1.0", diff --git a/front/src/components/library/Albums.vue b/front/src/components/library/Albums.vue index 9817af830..ed97f7a4e 100644 --- a/front/src/components/library/Albums.vue +++ b/front/src/components/library/Albums.vue @@ -20,6 +20,10 @@
+
+ + +