Merge branch 'develop' into 'feature/route-for-status'

# Conflicts:
#   src/store/modules/status.js
This commit is contained in:
Angelina Filippova 2020-05-24 17:00:12 +00:00
commit 1c2691478b
38 changed files with 686 additions and 286 deletions

View file

@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased ## Unreleased
### Changed
- Statuses count changes when an instance is selected and shows the amount of statuses from an originating instance
- Add a dialog window with a confirmation when a remove button is clicked on the Settings page
- Disable tab on the Settings page if there are no settings on this tab that can be changed in Admin FE
- Settings that can't be altered in Admin FE are removed: HTTP Signatures settings, Federation publisher modules and Oban Repo
### Fixed
- Send `true` and `false` as booleans if they are values of single selects on the Settings page
## [2.0.3] - 2020-04-29
### Added ### Added
- Link settings that enable registrations and invites - Link settings that enable registrations and invites

View file

@ -0,0 +1,4 @@
export async function fetchPeers(authHost, token) {
const data = ['lain.com', 'heaven.com']
return Promise.resolve({ data })
}

View file

@ -5,3 +5,66 @@ export async function changeStatusScope(id, sensitive, visibility, authHost, tok
export async function deleteStatus(id, authHost, token) { export async function deleteStatus(id, authHost, token) {
return Promise.resolve() return Promise.resolve()
} }
export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) {
let data
if (pageSize === 1) {
data = page === 1 || page === 2
? [{
'account': {
'avatar': 'http://localhost:4000/images/avi.png',
'display_name': 'sky',
'url': 'http://localhost:4000/users/sky'
},
'content': 'A nice young couple contacted us from Brazil to decorate their newly acquired apartment.',
'created_at': '2020-01-31T18:20:01.000Z',
'id': '9rZIr0Jzao5Gjgfmro',
'sensitive': false,
'url': 'http://localhost:4000/objects/7af9abbd-fb6c-4318-aeb7-6636c138ac98',
'visibility': 'unlisted'
}]
: []
} else {
data = [
{
'account': {
'avatar': 'http://localhost:4000/images/avi.png',
'display_name': 'sky',
'url': 'http://localhost:4000/users/sky'
},
'content': 'A nice young couple contacted us from Brazil to decorate their newly acquired apartment.',
'created_at': '2020-01-31T18:20:01.000Z',
'id': '9rZIr0Jzao5Gjgfmro',
'sensitive': false,
'url': 'http://localhost:4000/objects/7af9abbd-fb6c-4318-aeb7-6636c138ac98',
'visibility': 'unlisted'
},
{
'account': {
'avatar': 'http://localhost:4000/images/avi.png',
'display_name': 'sky',
'url': 'http://localhost:4000/users/sky'
},
'content': 'the happiest man ever',
'created_at': '2019-11-23T12:56:18.000Z',
'id': '9pFoVfWMU3A96Rzq3k',
'sensitive': false,
'url': 'http://localhost:4000/objects/449c90fe-c457-4c64-baf2-fe6d0a59ca25',
'visibility': 'unlisted'
}]
}
return Promise.resolve({ data })
}
export async function fetchStatusesCount(instance, authHost, token) {
const data = instance === 'heaven.com'
? {
'status_visibility':
{ 'direct': 1, 'private': 2, 'public': 3, 'unlisted': 0 }
}
: {
'status_visibility':
{ 'direct': 4, 'private': 10, 'public': 4, 'unlisted': 10 }
}
return Promise.resolve({ data })
}

View file

@ -2,22 +2,77 @@ import request from '@/utils/request'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { baseName } from './utils' import { baseName } from './utils'
import _ from 'lodash' export async function addNewEmojiFile(packName, file, shortcode, filename, host, token) {
const data = new FormData()
if (filename.trim() !== '') {
data.set('filename', filename)
}
if (shortcode.trim() !== '') {
data.set('shortcode', shortcode)
}
data.set('file', file)
export async function deletePack(host, token, name) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${name}`, url: `/api/pleroma/emoji/packs/${packName}/files`,
method: 'post',
headers: authHeaders(token),
data
})
}
export function addressOfEmojiInPack(host, packName, name) {
return `${baseName(host)}/emoji/${packName}/${name}`
}
export async function createPack(host, token, packName) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${packName}`,
method: 'post',
headers: authHeaders(token)
})
}
export async function deleteEmojiFile(packName, shortcode, host, token) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${packName}/files`,
method: 'delete',
headers: authHeaders(token),
data: { shortcode }
})
}
export async function deletePack(host, token, packName) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${packName}`,
method: 'delete', method: 'delete',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function reloadEmoji(host, token) { export async function downloadFrom(host, instance, packName, as, token) {
if (as.trim() === '') {
as = null
}
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: '/api/pleroma/admin/reload_emoji', url: '/api/pleroma/emoji/packs/download',
method: 'post', method: 'post',
headers: authHeaders(token),
data: { url: baseName(instance), name: packName, as },
timeout: 0
})
}
export async function fetchPack(packName, host, token) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${packName}`,
method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
@ -25,17 +80,8 @@ export async function reloadEmoji(host, token) {
export async function importFromFS(host, token) { export async function importFromFS(host, token) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: '/api/pleroma/emoji/packs/import_from_fs', url: '/api/pleroma/emoji/packs/import',
method: 'post', method: 'get',
headers: authHeaders(token)
})
}
export async function createPack(host, token, name) {
return await request({
baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${name}`,
method: 'put',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
@ -51,106 +97,40 @@ export async function listPacks(host) {
export async function listRemotePacks(host, token, instance) { export async function listRemotePacks(host, token, instance) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/list_from`, url: `/api/pleroma/emoji/packs/remote?url=${baseName(instance)}`,
method: 'post', method: 'get',
headers: authHeaders(token), headers: authHeaders(token)
data: { instance_address: baseName(instance) }
}) })
} }
export async function downloadFrom(host, instance_address, pack_name, as, token) { export async function reloadEmoji(host, token) {
if (as.trim() === '') {
as = null
}
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: '/api/pleroma/emoji/packs/download_from', url: '/api/pleroma/admin/reload_emoji',
method: 'post', method: 'post',
headers: authHeaders(token), headers: authHeaders(token)
data: { instance_address: baseName(instance_address), pack_name, as },
timeout: 0
}) })
} }
export async function savePackMetadata(host, token, name, new_data) { export async function savePackMetadata(host, token, packName, metadata) {
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${name}/update_metadata`, url: `/api/pleroma/emoji/packs/${packName}`,
method: 'post', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { name, new_data }, data: { metadata },
timeout: 0 // This might take a long time timeout: 0 // This might take a long time
}) })
} }
function fileUpdateFormData(d) { export async function updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, host, token) {
const data = new FormData()
_.each(d, (v, k) => {
data.set(k, v)
})
return data
}
export async function updatePackFile(host, token, args) {
let data = null
switch (args.action) {
case 'add': {
const { shortcode, file, fileName } = args
data = fileUpdateFormData({
action: 'add',
shortcode: shortcode,
file: file
})
if (fileName.trim() !== '') {
data.set('filename', fileName)
}
break
}
case 'update': {
const { oldName, newName, newFilename } = args
data = fileUpdateFormData({
action: 'update',
shortcode: oldName,
new_shortcode: newName,
new_filename: newFilename
})
break
}
case 'remove': {
const { name } = args
data = fileUpdateFormData({
action: 'remove',
shortcode: name
})
break
}
}
const { packName } = args
return await request({ return await request({
baseURL: baseName(host), baseURL: baseName(host),
url: `/api/pleroma/emoji/packs/${packName}/update_file`, url: `/api/pleroma/emoji/packs/${packName}/files`,
method: 'post', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: data, data: { shortcode, new_shortcode: newShortcode, new_filename: newFilename, force }
timeout: 0
}) })
} }
export function addressOfEmojiInPack(host, packName, name) {
return `${baseName(host)}/emoji/${packName}/${name}`
}
const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {} const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {}

View file

@ -39,10 +39,10 @@ export async function fetchStatuses({ godmode, localOnly, authHost, token, pageS
}) })
} }
export async function fetchStatusesCount(authHost, token) { export async function fetchStatusesCount(instance, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/stats`, url: instance ? `/api/pleroma/admin/stats?instance=${instance}` : `/api/pleroma/admin/stats`,
method: 'get', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })

View file

@ -387,7 +387,8 @@ export default {
corsPlug: 'CORS plug config', corsPlug: 'CORS plug config',
instanceReboot: 'Reboot Instance', instanceReboot: 'Reboot Instance',
restartApp: 'You must restart the instance to apply settings', restartApp: 'You must restart the instance to apply settings',
restartSuccess: 'Instance rebooted successfully!' restartSuccess: 'Instance rebooted successfully!',
removeSettingConfirmation: 'Are you sure you want to remove this setting\'s value from the database?'
}, },
invites: { invites: {
inviteTokens: 'Invite tokens', inviteTokens: 'Invite tokens',

View file

@ -1,13 +1,16 @@
import { import {
addNewEmojiFile,
createPack,
deleteEmojiFile,
deletePack,
downloadFrom,
importFromFS,
listPacks, listPacks,
listRemotePacks, listRemotePacks,
downloadFrom,
reloadEmoji, reloadEmoji,
createPack,
deletePack,
savePackMetadata, savePackMetadata,
importFromFS, updateEmojiFile
updatePackFile } from '@/api/emojiPacks' } from '@/api/emojiPacks'
import i18n from '@/lang' import i18n from '@/lang'
import { Message } from 'element-ui' import { Message } from 'element-ui'
@ -49,6 +52,36 @@ const packs = {
} }
}, },
actions: { actions: {
async AddNewEmojiFile({ commit, getters }, { packName, file, shortcode, filename }) {
let result
try {
result = await addNewEmojiFile(packName, file, shortcode, filename, getters.authHost, getters.token)
} catch (_e) {
return
}
Message({
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
},
async DeleteEmojiFile({ commit, getters }, { packName, shortcode }) {
let result
try {
result = await deleteEmojiFile(packName, shortcode, getters.authHost, getters.token)
} catch (_e) {
return
}
Message({
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
},
async CreatePack({ getters }, { name }) { async CreatePack({ getters }, { name }) {
await createPack(getters.authHost, getters.token, name) await createPack(getters.authHost, getters.token, name)
}, },
@ -116,20 +149,23 @@ const packs = {
commit('SET_REMOTE_INSTANCE', remoteInstance) commit('SET_REMOTE_INSTANCE', remoteInstance)
commit('SET_REMOTE_PACKS', data) commit('SET_REMOTE_PACKS', data)
}, },
async UpdateAndSavePackFile({ commit, getters }, args) { SetRemoteInstance({ commit }, instance) {
const result = await updatePackFile(getters.authHost, getters.token, args) commit('SET_REMOTE_INSTANCE', instance)
},
if (result.status === 200) { async UpdateEmojiFile({ commit, getters }, { packName, shortcode, newShortcode, newFilename, force }) {
const { packName } = args let result
try {
Message({ result = await updateEmojiFile(packName, shortcode, newShortcode, newFilename, force, getters.authHost, getters.token)
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`, } catch (_e) {
type: 'success', return
duration: 5 * 1000
})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
} }
Message({
message: `${i18n.t('settings.successfullyUpdated')} ${packName} ${i18n.t('settings.metadatLowerCase')}`,
type: 'success',
duration: 5 * 1000
})
commit('UPDATE_LOCAL_PACK_FILES', { name: packName, files: result.data })
}, },
async UpdateLocalPackVal({ commit }, args) { async UpdateLocalPackVal({ commit }, args) {
commit('UPDATE_LOCAL_PACK_VAL', args) commit('UPDATE_LOCAL_PACK_VAL', args)

View file

@ -1,5 +1,14 @@
import _ from 'lodash' import _ from 'lodash'
export const getBooleanValue = value => {
if (value === 'true') {
return true
} else if (value === 'false') {
return false
}
return value
}
export const checkPartialUpdate = (settings, updatedSettings, description) => { export const checkPartialUpdate = (settings, updatedSettings, description) => {
return Object.keys(updatedSettings).reduce((acc, group) => { return Object.keys(updatedSettings).reduce((acc, group) => {
acc[group] = Object.keys(updatedSettings[group]).reduce((acc, key) => { acc[group] = Object.keys(updatedSettings[group]).reduce((acc, key) => {

View file

@ -68,6 +68,14 @@ const status = {
dispatch('FetchStatus', statusId) dispatch('FetchStatus', statusId)
} }
}, },
ClearState({ commit }) {
commit('CHANGE_SELECTED_INSTANCE', '')
commit('SET_STATUSES_BY_INSTANCE', [])
commit('CHANGE_LOCAL_CHECKBOX_VALUE', false)
commit('CHANGE_GODMODE_CHECKBOX_VALUE', false)
commit('SET_ALL_LOADED', false)
commit('CHANGE_PAGE', 1)
},
async DeleteStatus({ dispatch, getters }, { statusId, reportCurrentPage, userId, godmode, fetchStatusesByInstance }) { async DeleteStatus({ dispatch, getters }, { statusId, reportCurrentPage, userId, godmode, fetchStatusesByInstance }) {
await deleteStatus(statusId, getters.authHost, getters.token) await deleteStatus(statusId, getters.authHost, getters.token)
if (reportCurrentPage !== 0) { // called from Reports if (reportCurrentPage !== 0) { // called from Reports
@ -89,12 +97,13 @@ const status = {
}, },
async FetchStatusesCount({ commit, getters }) { async FetchStatusesCount({ commit, getters }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
const { data } = await fetchStatusesCount(getters.authHost, getters.token) const { data } = await fetchStatusesCount(instance, getters.authHost, getters.token)
commit('SET_STATUS_VISIBILITY', data.status_visibility) commit('SET_STATUS_VISIBILITY', data.status_visibility)
commit('SET_LOADING', false) commit('SET_LOADING', false)
}, },
async FetchStatusesByInstance({ commit, getters, state, rootState }) { async FetchStatusesByInstance({ commit, dispatch, getters, state, rootState }) {
commit('SET_LOADING', true) commit('SET_LOADING', true)
dispatch('FetchStatusesCount', state.statusesByInstance.selectedInstance)
if (state.statusesByInstance.selectedInstance === '') { if (state.statusesByInstance.selectedInstance === '') {
commit('SET_STATUSES_BY_INSTANCE', []) commit('SET_STATUSES_BY_INSTANCE', [])
} else { } else {

View file

@ -44,11 +44,11 @@
</el-collapse-item> </el-collapse-item>
<el-collapse-item v-if="Object.keys(pack.files).length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background"> <el-collapse-item v-if="Object.keys(pack.files).length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
<single-emoji-editor <single-emoji-editor
v-for="(file, ename) in pack.files" v-for="(file, shortcode) in pack.files"
:key="ename" :key="shortcode"
:host="host" :host="host"
:pack-name="name" :pack-name="name"
:name="ename" :shortcode="shortcode"
:file="file" :file="file"
:is-local="isLocal" /> :is-local="isLocal" />
</el-collapse-item> </el-collapse-item>
@ -96,9 +96,9 @@ export default {
if (this.isMobile) { if (this.isMobile) {
return '90px' return '90px'
} else if (this.isTablet) { } else if (this.isTablet) {
return '120px' return '155px'
} else { } else {
return '120px' return '155px'
} }
}, },
share: { share: {

View file

@ -1,7 +1,7 @@
<template> <template>
<el-form :label-position="isMobile ? 'top' : 'left'" label-width="130px" size="small" class="new-emoji-uploader-form"> <el-form :label-position="isMobile ? 'top' : 'left'" label-width="130px" size="small" class="new-emoji-uploader-form">
<el-form-item :label="$t('emoji.shortcode')"> <el-form-item :label="$t('emoji.shortcode')">
<el-input v-model="shortcode" :placeholder="$t('emoji.required')"/> <el-input v-model="shortcode" :placeholder="$t('emoji.optional')"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('emoji.customFilename')"> <el-form-item :label="$t('emoji.customFilename')">
<el-input v-model="customFileName" :placeholder="$t('emoji.optional')"/> <el-input v-model="customFileName" :placeholder="$t('emoji.optional')"/>
@ -9,7 +9,7 @@
<el-form-item :label="$t('emoji.uploadFile')"> <el-form-item :label="$t('emoji.uploadFile')">
<div class="upload-file-url"> <div class="upload-file-url">
<el-input v-model="imageUploadURL" :placeholder="$t('emoji.url')"/> <el-input v-model="imageUploadURL" :placeholder="$t('emoji.url')"/>
<el-button :disabled="shortcodePresent" type="primary" class="upload-button" @click="uploadEmoji">{{ $t('emoji.upload') }}</el-button> <el-button type="primary" class="upload-button" @click="uploadEmoji">{{ $t('emoji.upload') }}</el-button>
</div> </div>
<div class="upload-container"> <div class="upload-container">
<p class="text">or</p> <p class="text">or</p>
@ -18,7 +18,7 @@
:multiple="false" :multiple="false"
:show-file-list="false" :show-file-list="false"
action="add"> action="add">
<el-button :disabled="shortcodePresent" type="primary">{{ $t('emoji.clickToUpload') }}</el-button> <el-button type="primary">{{ $t('emoji.clickToUpload') }}</el-button>
</el-upload> </el-upload>
</div> </div>
</el-form-item> </el-form-item>
@ -46,26 +46,25 @@ export default {
}, },
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
},
shortcodePresent() {
return this.shortcode.trim() === ''
} }
}, },
methods: { methods: {
uploadEmoji({ file }) { async uploadEmoji({ file }) {
this.$store.dispatch('UpdateAndSavePackFile', { try {
action: 'add', this.$store.dispatch('AddNewEmojiFile', {
packName: this.packName, packName: this.packName,
shortcode: this.shortcode, file: file || this.imageUploadURL,
file: file || this.imageUploadURL, shortcode: this.shortcode,
fileName: this.customFileName filename: this.customFileName
}).then(() => { })
this.shortcode = '' } catch (e) {
this.imageUploadURL = '' return
this.customFileName = '' }
this.shortcode = ''
this.imageUploadURL = ''
this.customFileName = ''
this.$store.dispatch('ReloadEmoji') this.$store.dispatch('ReloadEmoji')
})
} }
} }
} }

View file

@ -36,11 +36,11 @@
<el-collapse v-model="showPackContent" class="contents-collapse"> <el-collapse v-model="showPackContent" class="contents-collapse">
<el-collapse-item v-if="Object.keys(pack.files).length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background"> <el-collapse-item v-if="Object.keys(pack.files).length > 0" :title=" $t('emoji.manageEmoji')" name="manageEmoji" class="no-background">
<single-emoji-editor <single-emoji-editor
v-for="(file, ename) in pack.files" v-for="(file, shortcode) in pack.files"
:key="ename" :key="shortcode"
:host="host" :host="host"
:pack-name="name" :pack-name="name"
:name="ename" :shortcode="shortcode"
:file="file" :file="file"
:is-local="isLocal" /> :is-local="isLocal" />
</el-collapse-item> </el-collapse-item>
@ -52,7 +52,7 @@
</p> </p>
<div class="download-shared-pack"> <div class="download-shared-pack">
<el-input v-model="downloadSharedAs" :placeholder=" $t('emoji.downloadAsOptional')"/> <el-input v-model="downloadSharedAs" :placeholder=" $t('emoji.downloadAsOptional')"/>
<el-button type="primary" class="download-shared-pack-button" @click="downloadFromInstance(pack.pack['homepage'])"> <el-button type="primary" class="download-shared-pack-button" @click="downloadFromInstance">
{{ isDesktop ? $t('emoji.downloadSharedPack') : $t('emoji.downloadSharedPackMobile') }} {{ isDesktop ? $t('emoji.downloadSharedPack') : $t('emoji.downloadSharedPackMobile') }}
</el-button> </el-button>
</div> </div>
@ -113,6 +113,9 @@ export default {
loadRemotePack() { loadRemotePack() {
return this.$store.state.emojiPacks.activeCollapseItems.includes(this.name) return this.$store.state.emojiPacks.activeCollapseItems.includes(this.name)
}, },
remoteInstanceAddress() {
return this.$store.state.emojiPacks.remoteInstance
},
share: { share: {
get() { return this.pack.pack['share-files'] }, get() { return this.pack.pack['share-files'] },
set(value) { set(value) {
@ -171,11 +174,10 @@ export default {
} }
}, },
methods: { methods: {
downloadFromInstance(url) { downloadFromInstance() {
const instanceAddress = `${new URL(url).protocol}//${new URL(url).hostname}`
this.$store.dispatch( this.$store.dispatch(
'DownloadFrom', 'DownloadFrom',
{ instanceAddress, packName: this.name, as: this.downloadSharedAs } { instanceAddress: this.remoteInstanceAddress, packName: this.name, as: this.downloadSharedAs }
).then(() => this.$store.dispatch('ReloadEmoji')) ).then(() => this.$store.dispatch('ReloadEmoji'))
.then(() => this.$store.dispatch('SetLocalEmojiPacks')) .then(() => this.$store.dispatch('SetLocalEmojiPacks'))
} }

View file

@ -34,6 +34,7 @@
<el-button <el-button
:disabled="!copyToLocalPackName" :disabled="!copyToLocalPackName"
type="primary" type="primary"
class="copy-to-local-pack-button"
@click="copyToLocal">{{ $t('emoji.copy') }}</el-button> @click="copyToLocal">{{ $t('emoji.copy') }}</el-button>
<el-button slot="reference" type="primary" class="emoji-button">{{ $t('emoji.copyToLocalPack') }}</el-button> <el-button slot="reference" type="primary" class="emoji-button">{{ $t('emoji.copyToLocalPack') }}</el-button>
</el-popover> </el-popover>
@ -54,7 +55,7 @@ export default {
type: String, type: String,
required: true required: true
}, },
name: { shortcode: {
type: String, type: String,
required: true required: true
}, },
@ -69,7 +70,7 @@ export default {
}, },
data() { data() {
return { return {
newName: null, newShortcode: null,
newFile: null, newFile: null,
copyToLocalPackName: null, copyToLocalPackName: null,
copyPopoverVisible: false, copyPopoverVisible: false,
@ -80,14 +81,14 @@ export default {
computed: { computed: {
emojiName: { emojiName: {
get() { get() {
// Return a modified name if it was modified, otherwise return the old name // Return a modified shortcode if it was modified, otherwise return the old shortcode
return this.newName !== null ? this.newName : this.name return this.newShortcode !== null ? this.newShortcode : this.shortcode
}, },
set(val) { this.newName = val } set(val) { this.newShortcode = val }
}, },
emojiFile: { emojiFile: {
get() { get() {
// Return a modified name if it was modified, otherwise return the old name // Return a modified file name if it was modified, otherwise return the old file name
return this.newFile !== null ? this.newFile : this.file return this.newFile !== null ? this.newFile : this.file
}, },
set(val) { this.newFile = val } set(val) { this.newFile = val }
@ -102,23 +103,26 @@ export default {
return this.$store.state.emojiPacks.localPacks return this.$store.state.emojiPacks.localPacks
}, },
remoteInstance() { remoteInstance() {
return this.$store.state.emojiPacks.remoteInstance return new URL(this.$store.state.emojiPacks.remoteInstance).host
} }
}, },
methods: { methods: {
update() { async update() {
this.$store.dispatch('UpdateAndSavePackFile', { try {
action: 'update', this.$store.dispatch('UpdateEmojiFile', {
packName: this.packName, packName: this.packName,
oldName: this.name, shortcode: this.shortcode,
newName: this.emojiName, newShortcode: this.emojiName,
newFilename: this.emojiFile newFilename: this.emojiFile,
}).then(() => { force: true
this.newName = null })
this.newFile = null } catch (e) {
return
}
this.newShortcode = null
this.newFile = null
this.$store.dispatch('ReloadEmoji') this.$store.dispatch('ReloadEmoji')
})
}, },
remove() { remove() {
this.$confirm('This will delete the emoji, are you sure?', 'Warning', { this.$confirm('This will delete the emoji, are you sure?', 'Warning', {
@ -126,12 +130,11 @@ export default {
cancelButtonText: 'No, leave it be', cancelButtonText: 'No, leave it be',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.$store.dispatch('UpdateAndSavePackFile', { this.$store.dispatch('DeleteEmojiFile', {
action: 'remove',
packName: this.packName, packName: this.packName,
name: this.name shortcode: this.shortcode
}).then(() => { }).then(() => {
this.newName = null this.newShortcode = null
this.newFile = null this.newFile = null
this.$store.dispatch('ReloadEmoji') this.$store.dispatch('ReloadEmoji')
@ -139,20 +142,22 @@ export default {
}) })
}, },
copyToLocal() { copyToLocal() {
this.$store.dispatch('UpdateAndSavePackFile', { try {
action: 'add', this.$store.dispatch('AddNewEmojiFile', {
packName: this.copyToLocalPackName, packName: this.copyToLocalPackName,
shortcode: this.copyToShortcode.trim() !== '' ? this.copyToShortcode.trim() : this.name, file: this.addressOfEmojiInPack(this.remoteInstance, this.packName, this.file),
fileName: this.copyToFilename.trim() !== '' ? this.copyToFilename.trim() : this.file, shortcode: this.copyToShortcode.trim() !== '' ? this.copyToShortcode.trim() : this.shortcode,
file: this.addressOfEmojiInPack(this.host, this.packName, this.file) filename: this.copyToFilename.trim() !== '' ? this.copyToFilename.trim() : this.file
}).then(() => { })
this.copyToLocalPackName = null } catch (e) {
this.copyToLocalVisible = false return
this.copyToShortcode = '' }
this.copyToFilename = '' this.copyToLocalPackName = null
this.copyToLocalVisible = false
this.copyToShortcode = ''
this.copyToFilename = ''
this.$store.dispatch('ReloadEmoji') this.$store.dispatch('ReloadEmoji')
})
}, },
addressOfEmojiInPack addressOfEmojiInPack
} }
@ -163,6 +168,10 @@ export default {
.copy-popover { .copy-popover {
width: 330px width: 330px
} }
.copy-to-local-pack-button {
margin-top: 15px;
float: right;
}
.emoji-buttons { .emoji-buttons {
place-self: center; place-self: center;
min-width: 200px min-width: 200px

View file

@ -69,7 +69,6 @@ export default {
components: { LocalEmojiPack, RebootButton, RemoteEmojiPack }, components: { LocalEmojiPack, RebootButton, RemoteEmojiPack },
data() { data() {
return { return {
remoteInstanceAddress: '',
newPackName: '', newPackName: '',
activeLocalPack: [], activeLocalPack: [],
activeRemotePack: [], activeRemotePack: [],
@ -95,6 +94,14 @@ export default {
localPacks() { localPacks() {
return this.$store.state.emojiPacks.localPacks return this.$store.state.emojiPacks.localPacks
}, },
remoteInstanceAddress: {
get() {
return this.$store.state.emojiPacks.remoteInstance
},
set(instance) {
this.$store.dispatch('SetRemoteInstance', instance)
}
},
remotePacks() { remotePacks() {
return this.$store.state.emojiPacks.remotePacks return this.$store.state.emojiPacks.remotePacks
} }

View file

@ -3,7 +3,7 @@
<el-form ref="activitypubData" :model="activitypubData" :label-position="labelPosition" :label-width="labelWidth" data-search=":activitypub"> <el-form ref="activitypubData" :model="activitypubData" :label-position="labelPosition" :label-width="labelWidth" data-search=":activitypub">
<setting :setting-group="activitypub" :data="activitypubData"/> <setting :setting-group="activitypub" :data="activitypubData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="activitypub" class="divider thick-line"/>
<el-form ref="userData" :model="userData" :label-position="labelPosition" :label-width="labelWidth" data-search=":user"> <el-form ref="userData" :model="userData" :label-position="labelPosition" :label-width="labelWidth" data-search=":user">
<setting :setting-group="user" :data="userData"/> <setting :setting-group="user" :data="userData"/>
</el-form> </el-form>

View file

@ -3,15 +3,15 @@
<el-form ref="pleromaAuthenticatorData" :model="pleromaAuthenticatorData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="pleromaAuthenticatorData" :model="pleromaAuthenticatorData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="pleromaAuthenticator" :data="pleromaAuthenticatorData"/> <setting :setting-group="pleromaAuthenticator" :data="pleromaAuthenticatorData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="pleromaAuthenticator" class="divider thick-line"/>
<el-form ref="authData" :model="authData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="authData" :model="authData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="auth" :data="authData"/> <setting :setting-group="auth" :data="authData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="auth" class="divider thick-line"/>
<el-form ref="ldapData" :model="ldapData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="ldapData" :model="ldapData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="ldap" :data="ldapData"/> <setting :setting-group="ldap" :data="ldapData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="oauth2" class="divider thick-line"/>
<el-form ref="oauth2" :model="oauth2Data" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="oauth2" :model="oauth2Data" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="oauth2" :data="oauth2Data"/> <setting :setting-group="oauth2" :data="oauth2Data"/>
</el-form> </el-form>

View file

@ -3,7 +3,7 @@
<el-form ref="captchaData" :model="captchaData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="captchaData" :model="captchaData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="captcha" :data="captchaData"/> <setting :setting-group="captcha" :data="captchaData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="captcha" class="divider thick-line"/>
<el-form ref="kocaptchaData" :model="kocaptchaData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="kocaptchaData" :model="kocaptchaData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="kocaptcha" :data="kocaptchaData"/> <setting :setting-group="kocaptcha" :data="kocaptchaData"/>
</el-form> </el-form>

View file

@ -6,27 +6,27 @@
<el-form ref="staticFeData" :model="staticFeData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="staticFeData" :model="staticFeData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="staticFe" :data="staticFeData"/> <setting :setting-group="staticFe" :data="staticFeData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="staticFe" class="divider thick-line"/>
<el-form ref="assetsData" :model="assetsData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="assetsData" :model="assetsData" :label-position="labelPosition" :label-width="labelWidth">
<el-form-item class="grouped-settings-header"> <el-form-item v-if="assets" class="grouped-settings-header">
<span class="label-font label-with-margin">{{ $t('settings.assets') }}</span> <span class="label-font label-with-margin">{{ $t('settings.assets') }}</span>
</el-form-item> </el-form-item>
<setting :setting-group="assets" :data="assetsData"/> <setting :setting-group="assets" :data="assetsData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="assets" class="divider thick-line"/>
<el-form ref="emojiData" :model="emojiData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="emojiData" :model="emojiData" :label-position="labelPosition" :label-width="labelWidth">
<el-form-item data-search=":emoji" class="grouped-settings-header"> <el-form-item v-if="emoji" data-search=":emoji" class="grouped-settings-header">
<span class="label-font label-with-margin">{{ $t('settings.emoji') }}</span> <span class="label-font label-with-margin">{{ $t('settings.emoji') }}</span>
</el-form-item> </el-form-item>
<setting :setting-group="emoji" :data="emojiData"/> <setting :setting-group="emoji" :data="emojiData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="emoji" class="divider thick-line"/>
<el-form ref="chatData" :model="chatData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="chatData" :model="chatData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="chat" :data="chatData"/> <setting :setting-group="chat" :data="chatData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="chat" class="divider thick-line"/>
<el-form ref="markupData" :model="markupData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="markupData" :model="markupData" :label-position="labelPosition" :label-width="labelWidth">
<el-form-item data-search=":markup" class="grouped-settings-header"> <el-form-item v-if="markup" data-search=":markup" class="grouped-settings-header">
<span class="label-font label-with-margin">{{ $t('settings.markup') }}</span> <span class="label-font label-with-margin">{{ $t('settings.markup') }}</span>
</el-form-item> </el-form-item>
<setting :setting-group="markup" :data="markupData"/> <setting :setting-group="markup" :data="markupData"/>

View file

@ -4,20 +4,20 @@
<setting :setting-group="http" :data="httpData"/> <setting :setting-group="http" :data="httpData"/>
</el-form> </el-form>
<el-form ref="corsPlugData" :model="corsPlugData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="corsPlugData" :model="corsPlugData" :label-position="labelPosition" :label-width="labelWidth">
<el-form-item data-search=":cors_plug" class="grouped-settings-header"> <el-form-item v-if="corsPlug" data-search=":cors_plug" class="grouped-settings-header">
<span class="label-font label-with-margin">{{ $t('settings.corsPlug') }}</span> <span class="label-font label-with-margin">{{ $t('settings.corsPlug') }}</span>
</el-form-item> </el-form-item>
<setting :setting-group="corsPlug" :data="corsPlugData"/> <setting :setting-group="corsPlug" :data="corsPlugData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="corsPlug" class="divider thick-line"/>
<el-form ref="httpSignatures" :model="httpSignaturesData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="httpSignatures" :model="httpSignaturesData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="httpSignatures" :data="httpSignaturesData"/> <setting :setting-group="httpSignatures" :data="httpSignaturesData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="httpSignatures" class="divider thick-line"/>
<el-form ref="httpSecurityData" :model="httpSecurityData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="httpSecurityData" :model="httpSecurityData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="httpSecurity" :data="httpSecurityData"/> <setting :setting-group="httpSecurity" :data="httpSecurityData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="httpSecurity" class="divider thick-line"/>
<el-form ref="webCacheTtl" :model="webCacheTtlData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="webCacheTtl" :model="webCacheTtlData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="webCacheTtl" :data="webCacheTtlData"/> <setting :setting-group="webCacheTtl" :data="webCacheTtlData"/>
</el-form> </el-form>
@ -58,12 +58,6 @@ export default {
httpSecurityData() { httpSecurityData() {
return _.get(this.settings.settings, [':pleroma', ':http_security']) || {} return _.get(this.settings.settings, [':pleroma', ':http_security']) || {}
}, },
httpSignatures() {
return this.settings.description.find(setting => setting.group === ':http_signatures')
},
httpSignaturesData() {
return _.get(this.settings.settings, [':http_signatures']) || {}
},
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
}, },

View file

@ -55,7 +55,7 @@
:data-search="setting.key || setting.group" :data-search="setting.key || setting.group"
@change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/> @change="update($event, settingGroup.group, settingGroup.key, settingParent, setting.key, setting.type, nested)"/>
<el-select <el-select
v-if="!reducedSelects && (setting.type === 'module' || (setting.type.includes('atom') && setting.type.includes('dropdown')))" v-if="renderSingleSelect(setting.type)"
:value="inputValue === false ? 'false' : inputValue" :value="inputValue === false ? 'false' : inputValue"
:data-search="setting.key || setting.group" :data-search="setting.key || setting.group"
clearable clearable
@ -67,7 +67,7 @@
:key="index"/> :key="index"/>
</el-select> </el-select>
<el-select <el-select
v-if="!reducedSelects && renderMultipleSelect(setting.type)" v-if="renderMultipleSelect(setting.type)"
:value="inputValue" :value="inputValue"
:data-search="setting.key || setting.group" :data-search="setting.key || setting.group"
multiple multiple
@ -99,12 +99,12 @@
<editable-keyword-input v-if="editableKeyword(setting.key, setting.type)" :data="keywordData" :setting-group="settingGroup" :setting="setting"/> <editable-keyword-input v-if="editableKeyword(setting.key, setting.type)" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<icons-input v-if="setting.key === ':icons'" :data="iconsData" :setting-group="settingGroup" :setting="setting"/> <icons-input v-if="setting.key === ':icons'" :data="iconsData" :setting-group="settingGroup" :setting="setting"/>
<mascots-input v-if="setting.key === ':mascots'" :data="keywordData" :setting-group="settingGroup" :setting="setting"/> <mascots-input v-if="setting.key === ':mascots'" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<multiple-select v-if="setting.key === ':backends' || setting.key === ':args'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<proxy-url-input v-if="setting.key === ':proxy_url'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting" :parents="settingParent"/> <proxy-url-input v-if="setting.key === ':proxy_url'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting" :parents="settingParent"/>
<prune-input v-if="setting.key === ':prune'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting"/> <prune-input v-if="setting.key === ':prune'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting"/>
<rate-limit-input v-if="settingGroup.key === ':rate_limit'" :data="data" :setting-group="settingGroup" :setting="setting"/> <rate-limit-input v-if="settingGroup.key === ':rate_limit'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<reg-invites-input v-if="[':registrations_open', ':invites_enabled'].includes(setting.key)" :data="data" :setting-group="settingGroup" :setting="setting"/> <reg-invites-input v-if="[':registrations_open', ':invites_enabled'].includes(setting.key)" :data="data" :setting-group="settingGroup" :setting="setting"/>
<select-input-with-reduced-labels v-if="reducedSelects" :data="data" :setting-group="settingGroup" :setting="setting"/> <select-input-with-reduced-labels v-if="reducedSelects" :data="data" :setting-group="settingGroup" :setting="setting"/>
<specific-multiple-select v-if="setting.key === ':backends' || setting.key === ':args'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<!--------------------> <!-------------------->
<el-tooltip v-if="canBeDeleted && isTablet" :content="$t('settings.removeFromDB')" placement="bottom-end" class="delete-setting-button-container"> <el-tooltip v-if="canBeDeleted && isTablet" :content="$t('settings.removeFromDB')" placement="bottom-end" class="delete-setting-button-container">
<el-button icon="el-icon-delete" circle size="mini" class="delete-setting-button" @click="removeSetting"/> <el-button icon="el-icon-delete" circle size="mini" class="delete-setting-button" @click="removeSetting"/>
@ -126,13 +126,13 @@ import {
EditableKeywordInput, EditableKeywordInput,
IconsInput, IconsInput,
MascotsInput, MascotsInput,
MultipleSelect,
ProxyUrlInput, ProxyUrlInput,
PruneInput, PruneInput,
RateLimitInput, RateLimitInput,
RegInvitesInput, RegInvitesInput,
SelectInputWithReducedLabels } from './inputComponents' SelectInputWithReducedLabels,
import { processNested } from '@/store/modules/normalizers' SpecificMultipleSelect } from './inputComponents'
import { getBooleanValue, processNested } from '@/store/modules/normalizers'
import _ from 'lodash' import _ from 'lodash'
import marked from 'marked' import marked from 'marked'
@ -144,12 +144,12 @@ export default {
EditableKeywordInput, EditableKeywordInput,
IconsInput, IconsInput,
MascotsInput, MascotsInput,
MultipleSelect,
ProxyUrlInput, ProxyUrlInput,
PruneInput, PruneInput,
RateLimitInput, RateLimitInput,
RegInvitesInput, RegInvitesInput,
SelectInputWithReducedLabels SelectInputWithReducedLabels,
SpecificMultipleSelect
}, },
props: { props: {
customLabelWidth: { customLabelWidth: {
@ -215,7 +215,7 @@ export default {
return Array.isArray(this.data[':icons']) ? this.data[':icons'] : [] return Array.isArray(this.data[':icons']) ? this.data[':icons'] : []
}, },
inputValue() { inputValue() {
if ([':esshd', ':cors_plug', ':quack', ':http_signatures', ':tesla', ':swoosh'].includes(this.settingGroup.group) && if ([':esshd', ':cors_plug', ':quack', ':tesla', ':swoosh'].includes(this.settingGroup.group) &&
this.data[this.setting.key]) { this.data[this.setting.key]) {
return this.setting.type === 'atom' && this.data[this.setting.key].value[0] === ':' return this.setting.type === 'atom' && this.data[this.setting.key].value[0] === ':'
? this.data[this.setting.key].value.substr(1) ? this.data[this.setting.key].value.substr(1)
@ -296,21 +296,34 @@ export default {
{ group, key: parentKey, input: setting.key, value: valueForState }) { group, key: parentKey, input: setting.key, value: valueForState })
}, },
async removeSetting() { async removeSetting() {
const config = this.settingGroup.key this.$confirm(
? [{ group: this.settingGroup.group, key: this.settingGroup.key, delete: true, subkeys: [this.setting.key] }] this.$t('settings.removeSettingConfirmation'),
: [{ group: this.settingGroup.group, key: this.setting.key, delete: true }] {
try { confirmButtonText: this.$t('users.ok'),
await this.$store.dispatch('RemoveSetting', config) cancelButtonText: this.$t('users.cancel'),
} catch (e) { type: 'warning'
return }).then(async() => {
} const config = this.settingGroup.key
this.$message({ ? [{ group: this.settingGroup.group, key: this.settingGroup.key, delete: true, subkeys: [this.setting.key] }]
type: 'success', : [{ group: this.settingGroup.group, key: this.setting.key, delete: true }]
message: i18n.t('settings.successfullyRemoved') try {
await this.$store.dispatch('RemoveSetting', config)
} catch (e) {
return
}
this.$message({
type: 'success',
message: i18n.t('settings.successfullyRemoved')
})
}).catch(() => {
this.$message({
type: 'info',
message: this.$t('users.canceled')
})
}) })
}, },
renderMultipleSelect(type) { renderMultipleSelect(type) {
return Array.isArray(type) && this.setting.key !== ':backends' && this.setting.key !== ':args' && ( return !this.reducedSelects && Array.isArray(type) && this.setting.key !== ':backends' && this.setting.key !== ':args' && (
type.includes('module') || type.includes('module') ||
(type.includes('list') && type.includes('string')) || (type.includes('list') && type.includes('string')) ||
(type.includes('list') && type.includes('atom')) || (type.includes('list') && type.includes('atom')) ||
@ -318,10 +331,14 @@ export default {
this.setting.key === ':args' this.setting.key === ':args'
) )
}, },
renderSingleSelect(type) {
return !this.reducedSelects && (type === 'module' || (type.includes('atom') && type.includes('dropdown')))
},
update(value, group, key, parents, input, type, nested) { update(value, group, key, parents, input, type, nested) {
const updatedValue = this.renderSingleSelect(type) ? getBooleanValue(value) : value
nested nested
? this.processNestedData(value, group, key, parents) ? this.processNestedData(updatedValue, group, key, parents)
: this.updateSetting(value, group, key, input, type) : this.updateSetting(updatedValue, group, key, input, type)
}, },
updateSetting(value, group, key, input, type) { updateSetting(value, group, key, input, type) {
this.$store.dispatch('UpdateSettings', { group, key, input, value, type }) this.$store.dispatch('UpdateSettings', { group, key, input, value, type })

View file

@ -3,27 +3,27 @@
<el-form ref="instanceData" :model="instanceData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="instanceData" :model="instanceData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="instance" :data="instanceData"/> <setting :setting-group="instance" :data="instanceData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="instance" class="divider thick-line"/>
<el-form ref="adminToken" :model="adminTokenData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="adminToken" :model="adminTokenData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="adminToken" :data="adminTokenData"/> <setting :setting-group="adminToken" :data="adminTokenData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="adminToken" class="divider thick-line"/>
<el-form ref="scheduledActivity" :model="scheduledActivityData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="scheduledActivity" :model="scheduledActivityData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="scheduledActivity" :data="scheduledActivityData"/> <setting :setting-group="scheduledActivity" :data="scheduledActivityData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="scheduledActivity" class="divider thick-line"/>
<el-form ref="manifest" :model="manifestData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="manifest" :model="manifestData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="manifest" :data="manifestData"/> <setting :setting-group="manifest" :data="manifestData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="manifest" class="divider thick-line"/>
<el-form ref="pleromaUser" :model="pleromaUserData" :label-position="labelPosition" :label-width="labelWidth" data-search="Pleroma.User"> <el-form ref="pleromaUser" :model="pleromaUserData" :label-position="labelPosition" :label-width="labelWidth" data-search="Pleroma.User">
<setting :setting-group="pleromaUser" :data="pleromaUserData"/> <setting :setting-group="pleromaUser" :data="pleromaUserData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="pleromaUser" class="divider thick-line"/>
<el-form ref="uriSchemes" :model="uriSchemesData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="uriSchemes" :model="uriSchemesData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="uriSchemes" :data="uriSchemesData"/> <setting :setting-group="uriSchemes" :data="uriSchemesData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="uriSchemes" class="divider thick-line"/>
<el-form ref="feed" :model="feedData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="feed" :model="feedData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="feed" :data="feedData"/> <setting :setting-group="feed" :data="feedData"/>
</el-form> </el-form>

View file

@ -3,15 +3,15 @@
<el-form ref="loggerData" :model="loggerData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="loggerData" :model="loggerData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="logger" :data="loggerData"/> <setting :setting-group="logger" :data="loggerData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="logger" class="divider thick-line"/>
<el-form ref="consoleData" :model="consoleData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="consoleData" :model="consoleData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="console" :data="consoleData"/> <setting :setting-group="console" :data="consoleData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="console" class="divider thick-line"/>
<el-form ref="exsysloggerData" :model="exsysloggerData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="exsysloggerData" :model="exsysloggerData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="exsyslogger" :data="exsysloggerData"/> <setting :setting-group="exsyslogger" :data="exsysloggerData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="exsyslogger" class="divider thick-line"/>
<el-form ref="quackData" :model="quackData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="quackData" :model="quackData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="quack" :data="quackData"/> <setting :setting-group="quack" :data="quackData"/>
</el-form> </el-form>

View file

@ -3,15 +3,15 @@
<el-form ref="mrfSimple" :model="mrfSimpleData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfSimple" :model="mrfSimpleData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfSimple" :data="mrfSimpleData"/> <setting :setting-group="mrfSimple" :data="mrfSimpleData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfSimple" class="divider thick-line"/>
<el-form ref="mrfRejectnonpublic" :model="mrfRejectnonpublicData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfRejectnonpublic" :model="mrfRejectnonpublicData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfRejectnonpublic" :data="mrfRejectnonpublicData"/> <setting :setting-group="mrfRejectnonpublic" :data="mrfRejectnonpublicData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfRejectnonpublic" class="divider thick-line"/>
<el-form ref="mrfHellthread" :model="mrfHellthreadData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfHellthread" :model="mrfHellthreadData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfHellthread" :data="mrfHellthreadData"/> <setting :setting-group="mrfHellthread" :data="mrfHellthreadData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfHellthread" class="divider thick-line"/>
<el-form ref="mrfKeyword" :model="mrfKeywordData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfKeyword" :model="mrfKeywordData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfKeyword" :data="mrfKeywordData"/> <setting :setting-group="mrfKeyword" :data="mrfKeywordData"/>
</el-form> </el-form>
@ -21,19 +21,19 @@
<el-form ref="mrfMention" :model="mrfMentionData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfMention" :model="mrfMentionData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfMention" :data="mrfMentionData"/> <setting :setting-group="mrfMention" :data="mrfMentionData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfMention" class="divider thick-line"/>
<el-form ref="mrfNormalizeMarkup" :model="mrfNormalizeMarkupData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfNormalizeMarkup" :model="mrfNormalizeMarkupData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfNormalizeMarkup" :data="mrfNormalizeMarkupData"/> <setting :setting-group="mrfNormalizeMarkup" :data="mrfNormalizeMarkupData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfNormalizeMarkup" class="divider thick-line"/>
<el-form ref="mrfVocabulary" :model="mrfVocabularyData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfVocabulary" :model="mrfVocabularyData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfVocabulary" :data="mrfVocabularyData"/> <setting :setting-group="mrfVocabulary" :data="mrfVocabularyData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfVocabulary" class="divider thick-line"/>
<el-form ref="mrfObjectAge" :model="mrfObjectAgeData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mrfObjectAge" :model="mrfObjectAgeData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mrfObjectAge" :data="mrfObjectAgeData"/> <setting :setting-group="mrfObjectAge" :data="mrfObjectAgeData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mrfObjectAge" class="divider thick-line"/>
<el-form ref="modules" :model="modulesData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="modules" :model="modulesData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="modules" :data="modulesData"/> <setting :setting-group="modules" :data="modulesData"/>
</el-form> </el-form>

View file

@ -3,11 +3,11 @@
<el-form ref="mailer" :model="mailerData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="mailer" :model="mailerData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="mailer" :data="mailerData"/> <setting :setting-group="mailer" :data="mailerData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="mailer" class="divider thick-line"/>
<el-form ref="swoosh" :model="swooshData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="swoosh" :model="swooshData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="swoosh" :data="swooshData"/> <setting :setting-group="swoosh" :data="swooshData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="swoosh" class="divider thick-line"/>
<el-form ref="emailNotifications" :model="emailNotificationsData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="emailNotifications" :model="emailNotificationsData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="emailNotifications" :data="emailNotificationsData"/> <setting :setting-group="emailNotifications" :data="emailNotificationsData"/>
</el-form> </el-form>

View file

@ -3,7 +3,7 @@
<el-form ref="metadata" :model="metadataData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="metadata" :model="metadataData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="metadata" :data="metadataData"/> <setting :setting-group="metadata" :data="metadataData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="metadata" class="divider thick-line"/>
<el-form ref="richMedia" :model="richMediaData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="richMedia" :model="richMediaData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="richMedia" :data="richMediaData"/> <setting :setting-group="richMedia" :data="richMediaData"/>
</el-form> </el-form>

View file

@ -130,17 +130,30 @@ export default {
return marked(desc) return marked(desc)
}, },
async removeSetting(key) { async removeSetting(key) {
const config = this.settingGroup.key this.$confirm(
? [{ group: this.settingGroup.group, key: this.settingGroup.key, delete: true, subkeys: [key] }] this.$t('settings.removeSettingConfirmation'),
: [{ group: this.settingGroup.group, key, delete: true }] {
try { confirmButtonText: this.$t('users.ok'),
await this.$store.dispatch('RemoveSetting', config) cancelButtonText: this.$t('users.cancel'),
} catch (e) { type: 'warning'
return }).then(async() => {
} const config = this.settingGroup.key
this.$message({ ? [{ group: this.settingGroup.group, key: this.settingGroup.key, delete: true, subkeys: [key] }]
type: 'success', : [{ group: this.settingGroup.group, key, delete: true }]
message: i18n.t('settings.successfullyRemoved') try {
await this.$store.dispatch('RemoveSetting', config)
} catch (e) {
return
}
this.$message({
type: 'success',
message: i18n.t('settings.successfullyRemoved')
})
}).catch(() => {
this.$message({
type: 'info',
message: this.$t('users.canceled')
})
}) })
}, },
updateSetting(value, tab, input) { updateSetting(value, tab, input) {

View file

@ -4,20 +4,20 @@
<setting :setting-group="upload" :data="uploadData"/> <setting :setting-group="upload" :data="uploadData"/>
</el-form> </el-form>
<el-form v-if="showUploadersLocal" ref="uploadersLocal" :model="uploadersLocalData" :label-position="labelPosition" :label-width="labelWidth"> <el-form v-if="showUploadersLocal" ref="uploadersLocal" :model="uploadersLocalData" :label-position="labelPosition" :label-width="labelWidth">
<el-form-item class="grouped-settings-header"> <el-form-item v-if="uploadersLocal" class="grouped-settings-header">
<span class="label-font label-with-margin">Pleroma.Uploaders.Local</span> <span class="label-font label-with-margin">Pleroma.Uploaders.Local</span>
</el-form-item> </el-form-item>
<setting :setting-group="uploadersLocal" :data="uploadersLocalData"/> <setting :setting-group="uploadersLocal" :data="uploadersLocalData"/>
<el-divider class="divider thick-line"/> <el-divider v-if="uploadersLocal" class="divider thick-line"/>
</el-form> </el-form>
<el-form v-if="showUploadersS3" ref="uploadersS3" :model="uploadersS3Data" :label-position="labelPosition" :label-width="labelWidth"> <el-form v-if="showUploadersS3" ref="uploadersS3" :model="uploadersS3Data" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="uploadersS3" :data="uploadersS3Data"/> <setting :setting-group="uploadersS3" :data="uploadersS3Data"/>
<el-divider class="divider thick-line"/> <el-divider v-if="uploadersS3" class="divider thick-line"/>
</el-form> </el-form>
<el-form ref="uploadFilterMogrify" :model="uploadFilterMogrifyData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="uploadFilterMogrify" :model="uploadFilterMogrifyData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="uploadFilterMogrify" :data="uploadFilterMogrifyData"/> <setting :setting-group="uploadFilterMogrify" :data="uploadFilterMogrifyData"/>
</el-form> </el-form>
<el-divider class="divider thick-line"/> <el-divider v-if="uploadFilterMogrify" class="divider thick-line"/>
<el-form ref="uploadAnonymizeFilename" :model="uploadAnonymizeFilenameData" :label-position="labelPosition" :label-width="labelWidth"> <el-form ref="uploadAnonymizeFilename" :model="uploadAnonymizeFilenameData" :label-position="labelPosition" :label-width="labelWidth">
<setting :setting-group="uploadAnonymizeFilename" :data="uploadAnonymizeFilenameData"/> <setting :setting-group="uploadAnonymizeFilename" :data="uploadAnonymizeFilenameData"/>
</el-form> </el-form>

View file

@ -13,7 +13,7 @@
</el-select> </el-select>
<el-select <el-select
v-if="setting.type === 'module' || (setting.type.includes('atom') && setting.type.includes('dropdown'))" v-if="setting.type === 'module' || (setting.type.includes('atom') && setting.type.includes('dropdown'))"
:value="inputValue" :value="inputValue === false ? 'false' : inputValue"
:data-search="setting.key || setting.group" :data-search="setting.key || setting.group"
clearable clearable
class="input" class="input"
@ -28,6 +28,8 @@
</template> </template>
<script> <script>
import { getBooleanValue } from '@/store/modules/normalizers'
export default { export default {
name: 'SelectInputWithReducedLabels', name: 'SelectInputWithReducedLabels',
props: { props: {
@ -107,8 +109,9 @@ export default {
}) })
}, },
updateSetting(value, group, key, input, type) { updateSetting(value, group, key, input, type) {
this.$store.dispatch('UpdateSettings', { group, key, input, value, type }) const updatedValue = getBooleanValue(value)
this.$store.dispatch('UpdateState', { group, key, input, value }) this.$store.dispatch('UpdateSettings', { group, key, input, value: updatedValue, type })
this.$store.dispatch('UpdateState', { group, key, input, value: updatedValue })
} }
} }
} }

View file

@ -5,8 +5,6 @@
:value="data.value" :value="data.value"
:data-search="setting.key || setting.group" :data-search="setting.key || setting.group"
multiple multiple
filterable
allow-create
class="input" class="input"
@change="updateSetting($event, settingGroup.group, settingGroup.key, setting.key, setting.type)"> @change="updateSetting($event, settingGroup.group, settingGroup.key, setting.key, setting.type)">
<el-option value=":console" label="console"/> <el-option value=":console" label="console"/>
@ -18,8 +16,6 @@
:value="data[setting.key]" :value="data[setting.key]"
:data-search="setting.key || setting.group" :data-search="setting.key || setting.group"
multiple multiple
filterable
allow-create
class="input" class="input"
@change="updateSetting($event, settingGroup.group, settingGroup.key, setting.key, setting.type)"> @change="updateSetting($event, settingGroup.group, settingGroup.key, setting.key, setting.type)">
<el-option value="strip" label="strip"/> <el-option value="strip" label="strip"/>
@ -31,7 +27,7 @@
<script> <script>
export default { export default {
name: 'MultipleSelect', name: 'SpecificMultipleSelect',
props: { props: {
data: { data: {
type: [Object, Array], type: [Object, Array],

View file

@ -3,9 +3,9 @@ export { default as EditableKeywordInput } from './EditableKeywordInput'
export { default as CrontabInput } from './CrontabInput' export { default as CrontabInput } from './CrontabInput'
export { default as IconsInput } from './IconsInput' export { default as IconsInput } from './IconsInput'
export { default as MascotsInput } from './MascotsInput' export { default as MascotsInput } from './MascotsInput'
export { default as MultipleSelect } from './MultipleSelect'
export { default as ProxyUrlInput } from './ProxyUrlInput' export { default as ProxyUrlInput } from './ProxyUrlInput'
export { default as PruneInput } from './PruneInput' export { default as PruneInput } from './PruneInput'
export { default as RateLimitInput } from './RateLimitInput' export { default as RateLimitInput } from './RateLimitInput'
export { default as RegInvitesInput } from './RegInvitesInput' export { default as RegInvitesInput } from './RegInvitesInput'
export { default as SelectInputWithReducedLabels } from './SelectInputWithReducedLabels' export { default as SelectInputWithReducedLabels } from './SelectInputWithReducedLabels'
export { default as SpecificMultipleSelect } from './SpecificMultipleSelect'

View file

@ -29,7 +29,7 @@ export const tabs = {
}, },
'http': { 'http': {
label: 'settings.http', label: 'settings.http',
settings: [':cors_plug', ':http', ':http_security', ':http_signatures', ':web_cache_ttl'] settings: [':cors_plug', ':http', ':http_security', ':web_cache_ttl']
}, },
'instance': { 'instance': {
label: 'settings.instance', label: 'settings.instance',
@ -65,7 +65,7 @@ export const tabs = {
}, },
'relays': { 'relays': {
label: 'settings.relays', label: 'settings.relays',
settings: [] settings: ['relays']
}, },
'web-push': { 'web-push': {
label: 'settings.webPush', label: 'settings.webPush',

View file

@ -33,7 +33,7 @@
<el-tab-pane <el-tab-pane
v-for="(value, componentName) in tabs" v-for="(value, componentName) in tabs"
:label="$t(value.label)" :label="$t(value.label)"
:disabled="configDisabled" :disabled="configDisabled || settingsCantBeChanged(value.settings)"
:key="componentName" :key="componentName"
:name="componentName" :name="componentName"
lazy> lazy>
@ -227,6 +227,20 @@ export default {
: { value: `${searchObj.label} in ${searchObj.groupLabel}`, group: searchObj.groupKey, key: searchObj.key } : { value: `${searchObj.label} in ${searchObj.groupLabel}`, group: searchObj.groupKey, key: searchObj.key }
}) })
cb(results) cb(results)
},
settingsCantBeChanged(settings) {
const existingSettings = settings.filter(setting => {
if ([':esshd', ':cors_plug', ':quack', ':logger', ':swoosh', ':mime'].includes(setting)) {
return this.$store.state.settings.description.findIndex(el => el.group === setting) !== -1
} else if (setting === 'Pleroma.Web.Auth.Authenticator' || setting === ':admin_token') {
return this.$store.state.settings.description.findIndex(el => el.children[0].key === setting) !== -1
} else if (setting === 'relays') {
return [setting]
} else {
return this.$store.state.settings.description.findIndex(el => el.key === setting) !== -1
}
})
return existingSettings.length === 0
} }
} }
} }

View file

@ -55,7 +55,7 @@
padding-right: 10px; padding-right: 10px;
} }
.el-tabs__header { .el-tabs__header {
z-index: 3000; z-index: 2002;
} }
.esshd-list { .esshd-list {
margin: 0; margin: 0;

View file

@ -8,10 +8,18 @@
</div> </div>
<div class="statuses-header-container"> <div class="statuses-header-container">
<el-button-group> <el-button-group>
<el-button plain>{{ $t('statuses.direct') }}: {{ statusVisibility.direct }}</el-button> <el-button plain class="direct-button">
<el-button plain>{{ $t('statuses.private') }}: {{ statusVisibility.private }}</el-button> {{ $t('statuses.direct') }}: {{ normalizedCount(statusVisibility.direct) }}
<el-button plain>{{ $t('statuses.public') }}: {{ statusVisibility.public }}</el-button> </el-button>
<el-button plain>{{ $t('statuses.unlisted') }}: {{ statusVisibility.unlisted }}</el-button> <el-button plain class="private-button">
{{ $t('statuses.private') }}: {{ normalizedCount(statusVisibility.private) }}
</el-button>
<el-button plain class="public-button">
{{ $t('statuses.public') }}: {{ normalizedCount(statusVisibility.public) }}
</el-button>
<el-button plain class="unlisted-button">
{{ $t('statuses.unlisted') }}: {{ normalizedCount(statusVisibility.unlisted) }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
<div class="filter-container"> <div class="filter-container">
@ -61,6 +69,7 @@
import MultipleUsersMenu from '@/views/users/components/MultipleUsersMenu' import MultipleUsersMenu from '@/views/users/components/MultipleUsersMenu'
import Status from '@/components/Status' import Status from '@/components/Status'
import RebootButton from '@/components/RebootButton' import RebootButton from '@/components/RebootButton'
import numeral from 'numeral'
export default { export default {
name: 'Statuses', name: 'Statuses',
@ -142,7 +151,14 @@ export default {
this.$store.dispatch('FetchPeers') this.$store.dispatch('FetchPeers')
this.$store.dispatch('FetchStatusesCount') this.$store.dispatch('FetchStatusesCount')
}, },
destroyed() {
this.clearSelection()
this.$store.dispatch('ClearState')
},
methods: { methods: {
clearSelection() {
this.selectedUsers = []
},
handleFilterChange() { handleFilterChange() {
this.$store.dispatch('HandlePageChange', 1) this.$store.dispatch('HandlePageChange', 1)
this.$store.dispatch('FetchStatusesByInstance') this.$store.dispatch('FetchStatusesByInstance')
@ -152,14 +168,14 @@ export default {
this.$store.dispatch('FetchStatusesPageByInstance') this.$store.dispatch('FetchStatusesPageByInstance')
}, },
clearSelection() {
this.selectedUsers = []
},
handleStatusSelection(user) { handleStatusSelection(user) {
if (this.selectedUsers.find(selectedUser => user.id === selectedUser.id) !== undefined) { if (this.selectedUsers.find(selectedUser => user.id === selectedUser.id) !== undefined) {
return return
} }
this.selectedUsers = [...this.selectedUsers, user] this.selectedUsers = [...this.selectedUsers, user]
},
normalizedCount(count) {
return numeral(count).format('0a')
} }
} }
} }
@ -175,6 +191,13 @@ export default {
margin: 0 0 10px; margin: 0 0 10px;
} }
} }
.statuses-header-container {
.el-button.is-plain:focus, .el-button.is-plain:hover {
border-color: #DCDFE6;
color: #606266;
cursor: default
}
}
.checkbox-container { .checkbox-container {
margin-bottom: 15px; margin-bottom: 15px;
} }
@ -228,8 +251,26 @@ export default {
.statuses-header-container { .statuses-header-container {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
.el-button-group {
width: 100%;
}
.el-button { .el-button {
padding: 10px 6.5px; padding: 10px 6.5px;
width: 50%;
}
.el-button-group>.el-button:first-child {
border-bottom-left-radius: 0;
}
.el-button-group>.el-button:not(:first-child):not(:last-child).private-button {
border-top-right-radius: 4px;
}
.el-button-group>.el-button:not(:first-child):not(:last-child).public-button {
border-bottom-left-radius: 4px;
border-top: white;
}
.el-button-group>.el-button:last-child {
border-top-right-radius: 0;
border-top: white;
} }
.reboot-button { .reboot-button {
margin: 10px 0 0 0; margin: 10px 0 0 0;

View file

@ -0,0 +1,103 @@
import Vuex from 'vuex'
import { mount, createLocalVue, config } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import Element from 'element-ui'
import Statuses from '@/views/statuses/index'
import storeConfig from './store.conf'
import { cloneDeep } from 'lodash'
config.mocks["$t"] = () => {}
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Element)
jest.mock('@/api/app')
jest.mock('@/api/status')
jest.mock('@/api/peers')
jest.mock('@/api/nodeInfo')
describe('Statuses', () => {
let store
beforeEach(() => {
store = new Vuex.Store(cloneDeep(storeConfig))
})
it('fetches peers and statuses count', async (done) => {
mount(Statuses, {
store,
localVue
})
await flushPromises()
const statusVisibilityCount = store.state.status.statusVisibility
expect(statusVisibilityCount.direct).toEqual(4)
expect(statusVisibilityCount.private).toEqual(10)
expect(statusVisibilityCount.public).toEqual(4)
expect(statusVisibilityCount.unlisted).toEqual(10)
done()
})
it('fetches statuses from selected instance and updates the count', async (done) => {
const wrapper = mount(Statuses, {
store,
localVue
})
await flushPromises()
store.dispatch('HandleFilterChange', 'heaven.com')
wrapper.vm.handleFilterChange()
await flushPromises()
const statusVisibilityCount = store.state.status.statusVisibility
expect(statusVisibilityCount.direct).toEqual(1)
expect(statusVisibilityCount.private).toEqual(2)
expect(statusVisibilityCount.public).toEqual(3)
expect(statusVisibilityCount.unlisted).toEqual(0)
expect(store.state.status.fetchedStatuses.length).toEqual(2)
done()
})
it('handles status select', async (done) => {
const wrapper = mount(Statuses, {
store: store,
localVue
})
await flushPromises()
store.dispatch('HandleFilterChange', 'heaven.com')
wrapper.vm.handleFilterChange()
await flushPromises()
wrapper.find('.status-checkbox input').setChecked()
await flushPromises()
expect(wrapper.vm.selectedUsers.length).toEqual(1)
expect(wrapper.vm.selectedUsers[0].display_name).toBe('sky')
done()
})
it('clear state after component was destroyed', async (done) => {
const wrapper = mount(Statuses, {
store: store,
localVue
})
await flushPromises()
store.dispatch('HandleFilterChange', 'heaven.com')
wrapper.vm.handleFilterChange()
await flushPromises()
wrapper.find('.status-checkbox input').setChecked()
await flushPromises()
expect(wrapper.vm.selectedUsers.length).toEqual(1)
expect(store.state.status.statusesByInstance.selectedInstance).toBe('heaven.com')
expect(store.state.status.fetchedStatuses.length).toEqual(2)
wrapper.destroy()
expect(wrapper.vm.selectedUsers.length).toEqual(0)
expect(store.state.status.statusesByInstance.selectedInstance).toBe('')
expect(store.state.status.fetchedStatuses.length).toEqual(0)
done()
})
})

View file

@ -0,0 +1,53 @@
import Vuex from 'vuex'
import { mount, createLocalVue, config } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import Element from 'element-ui'
import Statuses from '@/views/statuses/index'
import storeConfig from './storeForPagination.conf'
import { cloneDeep } from 'lodash'
config.mocks["$t"] = () => {}
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Element)
jest.mock('@/api/app')
jest.mock('@/api/status')
jest.mock('@/api/peers')
jest.mock('@/api/nodeInfo')
describe('Statuses', () => {
let store
beforeEach(() => {
store = new Vuex.Store(cloneDeep(storeConfig))
})
it('pagination', async (done) => {
const wrapper = mount(Statuses, {
store,
localVue
})
await flushPromises()
store.dispatch('HandleFilterChange', 'heaven.com')
wrapper.vm.handleFilterChange()
await flushPromises()
expect(store.state.status.statusesByInstance.allLoaded).toBe(false)
expect(store.state.status.statusesByInstance.page).toBe(1)
wrapper.find('.statuses-pagination button').trigger('click')
await flushPromises()
expect(store.state.status.statusesByInstance.allLoaded).toBe(false)
expect(store.state.status.statusesByInstance.page).toBe(2)
wrapper.find('.statuses-pagination button').trigger('click')
await flushPromises()
expect(store.state.status.statusesByInstance.allLoaded).toBe(true)
done()
})
})

View file

@ -0,0 +1,17 @@
import app from '@/store/modules/app'
import peers from '@/store/modules/peers'
import user from '@/store/modules/user'
import settings from '@/store/modules/settings'
import status from '@/store/modules/status'
import getters from '@/store/getters'
export default {
modules: {
app,
peers,
settings,
status,
user: { ...user, state: { ...user.state, authHost: 'localhost:4000' }}
},
getters
}

View file

@ -0,0 +1,17 @@
import app from '@/store/modules/app'
import peers from '@/store/modules/peers'
import user from '@/store/modules/user'
import settings from '@/store/modules/settings'
import status from '@/store/modules/status'
import getters from '@/store/getters'
export default {
modules: {
app,
peers,
settings,
status: { ...status, state: { ...status.state, statusesByInstance: { ...status.state.statusesByInstance, pageSize: 1 }}},
user: { ...user, state: { ...user.state, authHost: 'localhost:4000' }}
},
getters
}