Moved Modal t set instance url to a separate dedicated file

SetInstanceModal.vue
This commit is contained in:
jovuit 2019-02-25 14:03:53 +01:00 committed by Eliot Berriot
parent 8beb08d677
commit 1d7ad6978a
15 changed files with 205 additions and 103 deletions

View File

@ -0,0 +1,3 @@
Better workflow for connecting to another instance (#715)
Changing the instance used is now better integrated in the App, and it is checked that the chosen instance and the suggested instances are valid and running Funkwhale servers.

View File

@ -1,5 +1,5 @@
<template> <template>
<div id="app"> <div id="app" :key="String($store.state.instance.instanceUrl)">
<!-- here, we display custom stylesheets, if any --> <!-- here, we display custom stylesheets, if any -->
<link <link
v-for="url in customStylesheets" v-for="url in customStylesheets"
@ -8,40 +8,16 @@
:href="url" :href="url"
:key="url" :key="url"
> >
<div class="ui main text container instance-chooser" v-if="!$store.state.instance.instanceUrl"> <template>
<div class="ui padded segment">
<h1 class="ui header">
<translate>Choose your instance</translate>
</h1>
<form class="ui form" @submit.prevent="$store.dispatch('instance/setUrl', instanceUrl)">
<p>
<translate>You need to select an instance in order to continue</translate>
</p>
<div class="ui action input">
<input type="text" v-model="instanceUrl">
<button type="submit" class="ui button">
<translate>Submit</translate>
</button>
</div>
<p>
<translate>Suggested choices</translate>
</p>
<div class="ui bulleted list">
<div class="ui item" v-for="url in suggestedInstances">
<a @click="instanceUrl = url; $store.dispatch('instance/setUrl', url)">{{ url }}</a>
</div>
</div>
</form>
</div>
</div>
<template v-else>
<sidebar></sidebar> <sidebar></sidebar>
<set-instance-modal @update:show="showSetInstanceModal = $event" :show="showSetInstanceModal"></set-instance-modal>
<service-messages v-if="messages.length > 0"/> <service-messages v-if="messages.length > 0"/>
<router-view :key="$route.fullPath"></router-view> <router-view :key="$route.fullPath"></router-view>
<div class="ui fitted divider"></div> <div class="ui fitted divider"></div>
<app-footer <app-footer
:version="version" :version="version"
@show:shortcuts-modal="showShortcutsModal = !showShortcutsModal" @show:shortcuts-modal="showShortcutsModal = !showShortcutsModal"
@show:set-instance-modal="showSetInstanceModal = !showSetInstanceModal"
></app-footer> ></app-footer>
<playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal> <playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal>
<filter-modal v-if="$store.state.auth.authenticated"></filter-modal> <filter-modal v-if="$store.state.auth.authenticated"></filter-modal>
@ -66,6 +42,7 @@ import locales from './locales'
import PlaylistModal from '@/components/playlists/PlaylistModal' import PlaylistModal from '@/components/playlists/PlaylistModal'
import FilterModal from '@/components/moderation/FilterModal' import FilterModal from '@/components/moderation/FilterModal'
import ShortcutsModal from '@/components/ShortcutsModal' import ShortcutsModal from '@/components/ShortcutsModal'
import SetInstanceModal from '@/components/SetInstanceModal'
export default { export default {
name: 'app', name: 'app',
@ -76,7 +53,8 @@ export default {
PlaylistModal, PlaylistModal,
ShortcutsModal, ShortcutsModal,
GlobalEvents, GlobalEvents,
ServiceMessages ServiceMessages,
SetInstanceModal,
}, },
data () { data () {
return { return {
@ -84,6 +62,7 @@ export default {
nodeinfo: null, nodeinfo: null,
instanceUrl: null, instanceUrl: null,
showShortcutsModal: false, showShortcutsModal: false,
showSetInstanceModal: false,
} }
}, },
created () { created () {
@ -131,12 +110,6 @@ export default {
self.nodeinfo = response.data self.nodeinfo = response.data
}) })
}, },
switchInstance () {
let confirm = window.confirm(this.$gettext('This will erase your local data and disconnect you, do you want to continue?'))
if (confirm) {
this.$store.commit('instance/instanceUrl', null)
}
},
autodetectLanguage () { autodetectLanguage () {
let userLanguage = navigator.language || navigator.userLanguage let userLanguage = navigator.language || navigator.userLanguage
let available = locales.locales.map(e => { return e.code }) let available = locales.locales.map(e => { return e.code })
@ -257,7 +230,6 @@ export default {
console.log('No momentjs locale available for', shortLocale) console.log('No momentjs locale available for', shortLocale)
}) })
}) })
console.log(moment.locales())
} }
} }
} }

View File

@ -13,9 +13,9 @@
<div class="item" v-if="version"> <div class="item" v-if="version">
<translate :translate-params="{version: version}" >Version %{version}</translate> <translate :translate-params="{version: version}" >Version %{version}</translate>
</div> </div>
<a @click="switchInstance" class="item" > <div role="button" class="item" @click="$emit('show:set-instance-modal')" >
<translate>Use another instance</translate> <translate>Use another instance</translate>
</a> </div>
</div> </div>
<div class="ui form"> <div class="ui form">
<div class="ui field"> <div class="ui field">
@ -66,18 +66,6 @@ import axios from 'axios'
export default { export default {
props: ["version"], props: ["version"],
methods: {
switchInstance() {
let confirm = window.confirm(
this.$gettext(
"This will erase your local data and disconnect you, do you want to continue?"
)
)
if (confirm) {
this.$store.commit("instance/instanceUrl", null)
}
}
},
computed: { computed: {
...mapState({ ...mapState({
messages: state => state.ui.messages messages: state => state.ui.messages
@ -88,13 +76,6 @@ export default {
parser.href = url parser.href = url
return parser.hostname return parser.hostname
}, },
suggestedInstances() {
let instances = [
this.$store.getters["instance/defaultUrl"](),
"https://demo.funkwhale.audio"
]
return instances
}
} }
} }
</script> </script>

View File

@ -1,21 +1,21 @@
<template> <template>
<svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 141.7 141.7" enable-background="new 0 0 141.7 141.7" xml:space="preserve"> viewBox="0 0 141.7 141.7" enable-background="new 0 0 141.7 141.7" xml:space="preserve">
<g> <g>
<g> <g>
<path :fill="fill" d="M70.9,86.1c11.7,0,21.2-9.5,21.2-21.2c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1c0,6-4.9,11-11,11 <path :fill="fill" d="M70.9,86.1c11.7,0,21.2-9.5,21.2-21.2c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1c0,6-4.9,11-11,11
c-6,0-11-4.9-11-11c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1C49.7,76.6,59.2,86.1,70.9,86.1z"/> c-6,0-11-4.9-11-11c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1C49.7,76.6,59.2,86.1,70.9,86.1z"/>
<path :fill="fill" d="M70.9,106.1c22.7,0,41.2-18.5,41.2-41.2c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1 <path :fill="fill" d="M70.9,106.1c22.7,0,41.2-18.5,41.2-41.2c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1
c0,17.1-13.9,31-31,31c-17.1,0-31-13.9-31-31c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1C29.6,87.6,48.1,106.1,70.9,106.1z" c0,17.1-13.9,31-31,31c-17.1,0-31-13.9-31-31c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1C29.6,87.6,48.1,106.1,70.9,106.1z"
/> />
<path :fill="fill" d="M131.1,63.8h-8c-0.6,0-1.1,0.5-1.1,1.1C122,93.1,99,116,70.9,116c-28.2,0-51.1-22.9-51.1-51.1 <path :fill="fill" d="M131.1,63.8h-8c-0.6,0-1.1,0.5-1.1,1.1C122,93.1,99,116,70.9,116c-28.2,0-51.1-22.9-51.1-51.1
c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1c0,33.8,27.5,61.3,61.3,61.3c33.8,0,61.3-27.5,61.3-61.3 c0-0.6-0.5-1.1-1.1-1.1h-8c-0.6,0-1.1,0.5-1.1,1.1c0,33.8,27.5,61.3,61.3,61.3c33.8,0,61.3-27.5,61.3-61.3
C132.2,64.3,131.7,63.8,131.1,63.8z"/> C132.2,64.3,131.7,63.8,131.1,63.8z"/>
</g> </g>
<path :fill="fill" d="M43.3,37.3c4.1,2.1,8.5,2.5,12.5,4.8c2.6,1.5,4.2,3.2,5.8,5.7c2.5,3.8,2.4,8.5,2.4,8.5l0.3,5.2 <path :fill="fill" d="M43.3,37.3c4.1,2.1,8.5,2.5,12.5,4.8c2.6,1.5,4.2,3.2,5.8,5.7c2.5,3.8,2.4,8.5,2.4,8.5l0.3,5.2
c0,0,2,5.2,6.4,5.2c4.7,0,6.4-5.2,6.4-5.2l0.3-5.2c0,0-0.1-4.7,2.4-8.5c1.6-2.5,3.2-4.3,5.8-5.7c4-2.3,8.4-2.7,12.5-4.8 c0,0,2,5.2,6.4,5.2c4.7,0,6.4-5.2,6.4-5.2l0.3-5.2c0,0-0.1-4.7,2.4-8.5c1.6-2.5,3.2-4.3,5.8-5.7c4-2.3,8.4-2.7,12.5-4.8
c4.1-2.1,8.1-4.8,10.8-8.6c2.7-3.8,4-8.8,2.5-13.2c-7.8-0.4-16.8,0.5-23.7,4.2c-9.6,5.1-15.4,3.3-17.1,10.9h-0.1 c4.1-2.1,8.1-4.8,10.8-8.6c2.7-3.8,4-8.8,2.5-13.2c-7.8-0.4-16.8,0.5-23.7,4.2c-9.6,5.1-15.4,3.3-17.1,10.9h-0.1
c-1.7-7.7-7.5-5.8-17.1-10.9c-6.9-3.7-15.9-4.6-23.7-4.2c-1.5,4.4-0.2,9.4,2.5,13.2C35.2,32.5,39.2,35.2,43.3,37.3z"/> c-1.7-7.7-7.5-5.8-17.1-10.9c-6.9-3.7-15.9-4.6-23.7-4.2c-1.5,4.4-0.2,9.4,2.5,13.2C35.2,32.5,39.2,35.2,43.3,37.3z"/>
</g> </g>
</svg> </svg>

View File

@ -0,0 +1,146 @@
<template>
<modal @update:show="$emit('update:show', $event); isError = false" :show="show">
<div class="header"><translate :translate-context="'Popup/Instance/Title'">Choose your instance</translate></div>
<div class="scrolling content">
<div v-if="isError" class="ui negative message">
<div class="header"><translate :translate-context="'Popup/Instance/Error message.Title'">It is not possible to connect to the given URL</translate></div>
<ul class="list">
<li><translate :translate-context="'Popup/Instance/Error message.List item'">The server might be down</translate></li>
<li><translate :translate-context="'Popup/Instance/Error message.List item'">The given address is not a Funkwhale server</translate></li>
</ul>
</div>
<form class="ui form" @submit.prevent="checkAndSwitch(instanceUrl)">
<p v-if="$store.state.instance.instanceUrl" class="description" :translate-context="'Popup/Login/Paragraph'" v-translate="{url: $store.state.instance.instanceUrl, hostname: instanceHostname }">
You are currently connected to <a href="%{ url }" target="_blank">%{ hostname }&nbsp;<i class="external icon"></i></a>. If you continue, you will be disconnected from your current instance and all your local data will be deleted.
</p>
<p v-else>
<translate :translate-context="'Popup/Instance/Paragraph'">To continue, please select the Funkwhale instance you want to connect to. Enter the address directly, or select one of the suggested choices.</translate>
</p>
<div class="field">
<label><translate :translate-context="'Popup/Instance/Input.Label/Noun'">Instance URL</translate></label>
<div class="ui action input">
<input type="text" v-model="instanceUrl" placeholder="https://funkwhale.server">
<button type="submit" :class="['ui', 'icon', {loading: isLoading}, 'button']">
<translate :translate-context="'*/*/Button.Label/Verb'">Submit</translate>
</button>
</div>
</div>
</form>
<div class="ui hidden divider"></div>
<form class="ui form" @submit.prevent="">
<div class="field">
<label><translate :translate-context="'Popup/Instance/List.Label'">Suggested choices</translate></label>
<button v-for="url in suggestedInstances" @click="checkAndSwitch(url)" class="ui basic button">{{ url }}</button>
</div>
</form>
</div>
<div class="actions">
<div class="ui cancel button"><translate :translate-context="'*/*/Button.Label/Verb'">Cancel</translate></div>
</div>
</modal>
</template>
<script>
import Modal from '@/components/semantic/Modal'
import axios from 'axios'
export default {
props: ['show'],
components: {
Modal,
},
data() {
return {
instanceUrl: null,
nodeinfo: null,
isError: false,
isLoading: false,
path: 'api/v1/instance/nodeinfo/2.0/',
}
},
methods: {
fetchNodeInfo () {
let self = this
axios.get('instance/nodeinfo/2.0/').then(response => {
self.nodeinfo = response.data
})
},
fetchUrl (url) {
let urlFetch = url
if (!urlFetch.endsWith('/')) {
urlFetch = `${urlFetch}/${this.path}`
} else {
urlFetch = `${urlFetch}${this.path}`
}
if (!urlFetch.startsWith('https://') && !urlFetch.startsWith('http://')) {
urlFetch = `https://${urlFetch}`
}
return urlFetch
},
requestDistantNodeInfo (url) {
var self = this
axios.get(this.fetchUrl(url)).then(function (response) {
self.isLoading = false
if(!url.startsWith('https://') && !url.startsWith('http://')) {
url = `https://${url}`
}
self.switchInstance(url)
}).catch(function (error) {
self.isLoading = false
self.isError = true
})
},
switchInstance (url) {
// Here we disconnect from the current instance and reconnect to the new one. No check is performed...
this.$emit('update:show', false)
this.isError = false
let msg = this.$pgettext('*/Instance/Message', 'You are now using the Funkwhale instance at %{ url }')
this.$store.commit('ui/addMessage', {
content: this.$gettextInterpolate(msg, {url: url}),
date: new Date()
})
let self = this
this.$nextTick(() => {
self.$store.commit('instance/instanceUrl', null)
self.$store.dispatch('instance/setUrl', url)
})
},
checkAndSwitch (url) {
// First we have to check if the address is a valid FW server. If yes, we switch:
this.isError = false // Clear error message if any...
this.isLoading = true
this.requestDistantNodeInfo(url)
},
},
computed: {
suggestedInstances () {
let instances = this.$store.state.instance.knownInstances.slice(0)
if (this.$store.state.instance.frontSettings.defaultServerUrl) {
let serverUrl = this.$store.state.instance.frontSettings.defaultServerUrl
if (!serverUrl.endsWith('/')) {
serverUrl = serverUrl + '/'
}
instances.push(serverUrl)
}
let self = this
instances.push(this.$store.getters['instance/defaultUrl'](), 'https://demo.funkwhale.audio/')
return _.uniq(instances.filter((e) => {return e != self.$store.state.instance.instanceUrl}))
},
instanceHostname() {
let url = this.$store.state.instance.instanceUrl
let parser = document.createElement("a")
parser.href = url
return parser.hostname
},
},
watch: {
'$store.state.instance.instanceUrl' () {
this.$store.dispatch('instance/fetchSettings')
this.fetchNodeInfo()
},
},
}
</script>
<style scoped>
</style>

View File

@ -17,14 +17,14 @@
</template> </template>
</div> </div>
<div class="field"> <div class="field">
<button @click="copy" class="ui right teal labeled icon floated button"><i class="copy icon"></i><translate :translate-context="'Popup/*/Button.Label/Verb'">Copy</translate></button> <button @click="copy" class="ui right teal labeled icon floated button"><i class="copy icon"></i><translate :translate-context="'Popup/*/Button.Label/Verb'">Copy</translate></button>
<label for="embed-width"><translate :translate-context="'Popup/Embed/Input.Label/Noun'">Embed code</translate></label> <label for="embed-width"><translate :translate-context="'Popup/Embed/Input.Label/Noun'">Embed code</translate></label>
<p><translate :translate-context="'Popup/Embed/Paragraph'">Copy/paste this code in your website HTML</translate></p> <p><translate :translate-context="'Popup/Embed/Paragraph'">Copy/paste this code in your website HTML</translate></p>
<textarea ref="textarea":value="embedCode" rows="5" readonly> <textarea ref="textarea":value="embedCode" rows="5" readonly>
</textarea> </textarea>
<div class="ui right"> <div class="ui right">
<p class="message" v-if=copied><translate :translate-context="'Content/*/Paragraph'">Text copied to clipboard!</translate></p> <p class="message" v-if=copied><translate :translate-context="'Content/*/Paragraph'">Text copied to clipboard!</translate></p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@ -44,7 +44,7 @@ export default {
width: null, width: null,
height: 150, height: 150,
minHeight: 100, minHeight: 100,
copied: false copied: false
} }
if (this.type === 'album') { if (this.type === 'album') {
d.height = 330 d.height = 330
@ -73,11 +73,11 @@ export default {
copy () { copy () {
this.$refs.textarea.select() this.$refs.textarea.select()
document.execCommand("Copy") document.execCommand("Copy")
let self = this let self = this
self.copied = true self.copied = true
this.timeout = setTimeout(() => { this.timeout = setTimeout(() => {
self.copied = false self.copied = false
}, 5000) }, 5000)
} }
} }
} }
@ -86,8 +86,8 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped> <style scoped>
.message { .message {
position: absolute; position: absolute;
right: 0; right: 0;
bottom: -2em; bottom: -2em;
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<span :title="title" :class="['ui', {'tiny': discrete}, {'icon': !discrete}, {'buttons': !dropdownOnly && !iconOnly}]"> <span :title="title" :class="['ui', {'tiny': discrete}, {'icon': !discrete}, {'buttons': !dropdownOnly && !iconOnly}]">
<button <button
v-if="!dropdownOnly" v-if="!dropdownOnly"
:title="labels.playNow" :title="labels.playNow"

View File

@ -12,7 +12,7 @@
translate-plural="%{ count } favorites" translate-plural="%{ count } favorites"
:translate-n="$store.state.favorites.count" :translate-n="$store.state.favorites.count"
:translate-params="{count: results.count}" :translate-params="{count: results.count}"
:translate-context="'Content/Favorites/Title'"> :translate-context="'Content/Favorites/Title'">
1 favorite 1 favorite
</translate> </translate>
</h2> </h2>

View File

@ -63,7 +63,7 @@
tag="h2" tag="h2"
class="left floated" class="left floated"
:translate-params="{number: disc_number + 1}" :translate-params="{number: disc_number + 1}"
:translate-context="'Content/Album/'" :translate-context="'Content/Album/'"
>Volume %{ number }</translate> >Volume %{ number }</translate>
<play-button class="right floated orange" :tracks="tracks"> <play-button class="right floated orange" :tracks="tracks">
<translate :translate-context="'Content/*/Button.Label/Verb, Short'">Play all</translate> <translate :translate-context="'Content/*/Button.Label/Verb, Short'">Play all</translate>

View File

@ -34,7 +34,7 @@
<p><translate :translate-context="'Content/Library/Paragraph'">You are about to upload music to your library. Before proceeding, please ensure that:</translate></p> <p><translate :translate-context="'Content/Library/Paragraph'">You are about to upload music to your library. Before proceeding, please ensure that:</translate></p>
<ul> <ul>
<li v-if="library.privacy_level != 'me'"> <li v-if="library.privacy_level != 'me'">
<translate :translate-context="'Content/Library/List item'">You are not uploading copyrighted content in a public library, otherwise you may be infringing the law</translate> <translate :translate-context="'Content/Library/List item'">You are not uploading copyrighted content in a public library, otherwise you may be infringing the law</translate>
</li> </li>
<li> <li>
<translate :translate-context="'Content/Library/List item'">The music files you are uploading are tagged properly.</translate>&nbsp; <translate :translate-context="'Content/Library/List item'">The music files you are uploading are tagged properly.</translate>&nbsp;

View File

@ -30,7 +30,7 @@
<input id="public" type="checkbox" v-model="isPublic" /> <input id="public" type="checkbox" v-model="isPublic" />
<label for="public"><translate :translate-context="'Content/Radio/Checkbox.Label/Verb'">Display publicly</translate></label> <label for="public"><translate :translate-context="'Content/Radio/Checkbox.Label/Verb'">Display publicly</translate></label>
</div> </div>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<button :disabled="!canSave" @click="save" :class="['ui', 'green', {loading: isLoading}, 'button']"> <button :disabled="!canSave" @click="save" :class="['ui', 'green', {loading: isLoading}, 'button']">
<translate :translate-context="'Content/Radio/Button.Label/Verb'">Save</translate> <translate :translate-context="'Content/Radio/Button.Label/Verb'">Save</translate>
</button> </button>

View File

@ -42,7 +42,7 @@ export default {
return { return {
libraryFollowMessage, libraryFollowMessage,
libraryAcceptFollowMessage, libraryAcceptFollowMessage,
libraryPendingFollowMessage, libraryPendingFollowMessage,
markRead: this.$gettext('Mark as read'), markRead: this.$gettext('Mark as read'),
markUnread: this.$gettext('Mark as unread'), markUnread: this.$gettext('Mark as unread'),
@ -57,18 +57,18 @@ export default {
if (a.type === 'Follow') { if (a.type === 'Follow') {
if (a.object && a.object.type === 'music.Library') { if (a.object && a.object.type === 'music.Library') {
let action = null let action = null
let message = null let message = null
if (!a.related_object.approved) { if (!a.related_object.approved) {
message = this.labels.libraryPendingFollowMessage message = this.labels.libraryPendingFollowMessage
action = { action = {
buttonClass: 'green', buttonClass: 'green',
icon: 'check', icon: 'check',
label: this.$gettext('Approve'), label: this.$gettext('Approve'),
handler: () => { self.approveLibraryFollow(a.related_object) } handler: () => { self.approveLibraryFollow(a.related_object) }
} }
} else { } else {
message = this.labels.libraryFollowMessage message = this.labels.libraryFollowMessage
} }
return { return {
action, action,
detailUrl: {name: 'content.libraries.detail', params: {id: a.object.uuid}}, detailUrl: {name: 'content.libraries.detail', params: {id: a.object.uuid}},

View File

@ -15,7 +15,7 @@
</div> </div>
<div class="extra content"> <div class="extra content">
<user-link v-if="radio.user" :user="radio.user" class="left floated" /> <user-link v-if="radio.user" :user="radio.user" class="left floated" />
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<radio-button class="right floated button" :type="type" :custom-radio-id="customRadioId"></radio-button> <radio-button class="right floated button" :type="type" :custom-radio-id="customRadioId"></radio-button>
<router-link <router-link
class="ui basic yellow button right floated" class="ui basic yellow button right floated"

View File

@ -48,7 +48,7 @@
</h3> </h3>
</header> </header>
<p><translate :translate-context="'Content/Moderation/Card.Paragraph'">Moderation policies help you control how your instance interact with a given domain or account.</translate></p> <p><translate :translate-context="'Content/Moderation/Card.Paragraph'">Moderation policies help you control how your instance interact with a given domain or account.</translate></p>
<button @click="showPolicyForm = true" class="ui primary button"><translate :translate-context="'Content/Moderation/Button/Verb'">Add a moderation policy</translate></button> <button @click="showPolicyForm = true" class="ui primary button"><translate :translate-context="'Content/Moderation/Button/Verb'">Add a moderation policy</translate></button>
</template> </template>
<instance-policy-card v-else-if="policy && !showPolicyForm" :object="policy" @update="showPolicyForm = true"> <instance-policy-card v-else-if="policy && !showPolicyForm" :object="policy" @update="showPolicyForm = true">
<header class="ui header"> <header class="ui header">

View File

@ -14,7 +14,7 @@
translate-plural="Playlist containing %{ count } tracks, by %{ username }" translate-plural="Playlist containing %{ count } tracks, by %{ username }"
:translate-n="playlist.tracks_count" :translate-n="playlist.tracks_count"
:translate-params="{count: playlist.tracks_count, username: playlist.user.username}" :translate-params="{count: playlist.tracks_count, username: playlist.user.username}"
:translate-context="'Content/Playlist/Header.Subtitle'"> :translate-context="'Content/Playlist/Header.Subtitle'">
Playlist containing %{ count } track, by %{ username } Playlist containing %{ count } track, by %{ username }
</translate><br> </translate><br>
<duration :seconds="playlist.duration" /> <duration :seconds="playlist.duration" />