From 6e82780e0d90bd4a1edecbc470acad730220ef95 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Wed, 28 Aug 2019 17:13:26 +0200 Subject: [PATCH] See #890: improved report card design, to include relevant context --- front/src/components/common/ExpandableDiv.vue | 32 ++ front/src/components/globals.js | 3 + front/src/components/library/EditCard.vue | 3 + .../manage/moderation/ReportCard.vue | 281 ++++++++++++++++++ front/src/entities.js | 201 +++++++++++++ front/src/style/_main.scss | 8 + front/src/views/admin/moderation/Base.vue | 3 + .../views/admin/moderation/ReportsList.vue | 94 +++--- 8 files changed, 584 insertions(+), 41 deletions(-) create mode 100644 front/src/components/common/ExpandableDiv.vue create mode 100644 front/src/components/manage/moderation/ReportCard.vue create mode 100644 front/src/entities.js diff --git a/front/src/components/common/ExpandableDiv.vue b/front/src/components/common/ExpandableDiv.vue new file mode 100644 index 000000000..653286ad2 --- /dev/null +++ b/front/src/components/common/ExpandableDiv.vue @@ -0,0 +1,32 @@ + + diff --git a/front/src/components/globals.js b/front/src/components/globals.js index 711b227ae..4131c5d15 100644 --- a/front/src/components/globals.js +++ b/front/src/components/globals.js @@ -48,4 +48,7 @@ import EmptyState from '@/components/common/EmptyState' Vue.component('empty-state', EmptyState) +import ExpandableDiv from '@/components/common/ExpandableDiv' + +Vue.component('expandable-div', ExpandableDiv) export default {} diff --git a/front/src/components/library/EditCard.vue b/front/src/components/library/EditCard.vue index bb8676cee..fc5efea55 100644 --- a/front/src/components/library/EditCard.vue +++ b/front/src/components/library/EditCard.vue @@ -158,6 +158,9 @@ export default { }, updatedFields () { + if (!this.obj.target) { + return [] + } let payload = this.obj.payload let previousState = this.previousState let fields = Object.keys(payload) diff --git a/front/src/components/manage/moderation/ReportCard.vue b/front/src/components/manage/moderation/ReportCard.vue new file mode 100644 index 000000000..bbf475b88 --- /dev/null +++ b/front/src/components/manage/moderation/ReportCard.vue @@ -0,0 +1,281 @@ + + + diff --git a/front/src/entities.js b/front/src/entities.js new file mode 100644 index 000000000..48d39df77 --- /dev/null +++ b/front/src/entities.js @@ -0,0 +1,201 @@ +function getTagsValueRepr (val) { + if (!val) { + return '' + } + return val.slice().sort().join('\n') +} + +export default { + getConfigs () { + return { + artist: { + label: this.$pgettext('*/*/*', 'Artist'), + icon: 'users', + urls: { + getAdminDetail: (obj) => { return {name: 'manage.library.artists.detail', params: {id: obj.id}}} + }, + moderatedFields: [ + { + id: 'name', + label: this.$pgettext('*/*/*/Noun', 'Name'), + getValue: (obj) => { return obj.name } + }, + { + id: 'creation_date', + label: this.$pgettext('*/*/*/Noun', 'Creation date'), + getValue: (obj) => { return obj.creation_date } + }, + { + id: 'tags', + type: 'tags', + label: this.$pgettext('*/*/*/Noun', 'Tags'), + getValue: (obj) => { return obj.tags }, + getValueRepr: getTagsValueRepr + }, + { + id: 'mbid', + label: this.$pgettext('*/*/*/Noun', 'MusicBrainz ID'), + getValue: (obj) => { return obj.mbid } + }, + ] + }, + album: { + label: this.$pgettext('*/*/*', 'Album'), + icon: 'play', + urls: { + getAdminDetail: (obj) => { return {name: 'manage.library.albums.detail', params: {id: obj.id}}} + }, + moderatedFields: [ + { + id: 'title', + label: this.$pgettext('*/*/*/Noun', 'Title'), + getValue: (obj) => { return obj.title } + }, + { + id: 'creation_date', + label: this.$pgettext('*/*/*/Noun', 'Creation date'), + getValue: (obj) => { return obj.creation_date } + }, + { + id: 'release_date', + 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 + }, + { + id: 'mbid', + label: this.$pgettext('*/*/*/Noun', 'MusicBrainz ID'), + getValue: (obj) => { return obj.mbid } + }, + ] + }, + track: { + label: this.$pgettext('*/*/*', 'Track'), + icon: 'music', + urls: { + getAdminDetail: (obj) => { return {name: 'manage.library.tracks.detail', params: {id: obj.id}}} + }, + moderatedFields: [ + { + id: 'title', + label: this.$pgettext('*/*/*/Noun', 'Title'), + getValue: (obj) => { return obj.title } + }, + { + id: 'position', + label: this.$pgettext('*/*/*/Short, Noun', 'Position'), + getValue: (obj) => { return obj.position } + }, + { + id: 'copyright', + label: this.$pgettext('Content/Track/*/Noun', 'Copyright'), + getValue: (obj) => { return obj.copyright } + }, + { + id: 'license', + label: this.$pgettext('Content/*/*/Noun', 'License'), + getValue: (obj) => { return obj.license }, + }, + { + id: 'tags', + label: this.$pgettext('*/*/*/Noun', 'Tags'), + getValue: (obj) => { return obj.tags }, + getValueRepr: getTagsValueRepr + }, + { + id: 'mbid', + label: this.$pgettext('*/*/*/Noun', 'MusicBrainz ID'), + getValue: (obj) => { return obj.mbid } + }, + ] + }, + library: { + label: this.$pgettext('*/*/*', 'Library'), + icon: 'book', + urls: { + getAdminDetail: (obj) => { return {name: 'manage.library.libraries.detail', params: {id: obj.uuid}}} + }, + moderatedFields: [ + { + id: 'name', + label: this.$pgettext('*/*/*/Noun', 'Name'), + getValue: (obj) => { return obj.name } + }, + { + id: 'description', + label: this.$pgettext('*/*/*/Noun', 'Description'), + getValue: (obj) => { return obj.position } + }, + { + id: 'privacy_level', + label: this.$pgettext('*/*/*', 'Visibility'), + getValue: (obj) => { return obj.privacy_level } + }, + ] + }, + playlist: { + label: this.$pgettext('*/*/*', 'Playlist'), + icon: 'list', + urls: { + // getAdminDetail: (obj) => { return {name: 'manage.playlists.detail', params: {id: obj.id}}} + }, + moderatedFields: [ + { + id: 'name', + label: this.$pgettext('*/*/*/Noun', 'Name'), + getValue: (obj) => { return obj.name } + }, + { + id: 'privacy_level', + label: this.$pgettext('*/*/*', 'Visibility'), + getValue: (obj) => { return obj.privacy_level } + }, + ] + }, + account: { + label: this.$pgettext('*/*/*', 'Account'), + icon: 'user', + urls: { + getAdminDetail: (obj) => { return {name: 'manage.moderation.accounts.detail', params: {id: `${obj.preferred_username}@${obj.domain}`}}} + }, + moderatedFields: [ + { + id: 'name', + label: this.$pgettext('*/*/*/Noun', 'Name'), + getValue: (obj) => { return obj.name } + }, + { + id: 'summary', + label: this.$pgettext('*/*/*/Noun', 'Bio'), + getValue: (obj) => { return obj.summary } + }, + ] + }, + } + }, + + getConfig () { + return this.configs[this.objectType] + }, + getFieldConfig (configs, type, fieldId) { + let c = configs[type] + return c.fields.filter((f) => { + return f.id == fieldId + })[0] + }, + getCurrentStateForObj (obj, config) { + let s = {} + config.fields.forEach(f => { + s[f.id] = {value: f.getValue(obj)} + }) + return s + }, + +} diff --git a/front/src/style/_main.scss b/front/src/style/_main.scss index 3687b6e22..cd863cb17 100644 --- a/front/src/style/_main.scss +++ b/front/src/style/_main.scss @@ -368,5 +368,13 @@ input + .help { margin-top: 0.5em; } +.expandable { + &:not(.expanded) { + overflow: hidden; + max-height: 15vh; + background: linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 90%, rgba(0, 0, 0, 0.3) 100%); + } +} + @import "./themes/_light.scss"; @import "./themes/_dark.scss"; diff --git a/front/src/views/admin/moderation/Base.vue b/front/src/views/admin/moderation/Base.vue index d1c3ae29f..04753cd36 100644 --- a/front/src/views/admin/moderation/Base.vue +++ b/front/src/views/admin/moderation/Base.vue @@ -1,6 +1,9 @@