Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • pleroma/admin-fe
  • linafilippova/admin-fe
  • Exilat_a_Tolosa/admin-fe
  • mkljczk/admin-fe
  • maxf/admin-fe
  • kphrx/admin-fe
  • vaartis/admin-fe
  • ELR/admin-fe
  • eugenijm/admin-fe
  • jp/admin-fe
  • mkfain/admin-fe
  • lorenzoancora/admin-fe
  • alexgleason/admin-fe
  • seanking/admin-fe
  • ilja/admin-fe
15 results
Show changes
Commits on Source (19)
Showing with 279 additions and 45 deletions
......@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased
### Added
- Ability to see local statuses in Statuses by instance section
- Ability to configure Oban.Cron settings and settings for notifications streamer
## [2.0] - 2020-02-27
### Added
......
......@@ -21,6 +21,15 @@ export async function deleteStatus(id, authHost, token) {
})
}
export async function fetchStatuses({ godmode, localOnly, authHost, token, pageSize, page }) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/statuses?godmode=${godmode}&local_only=${localOnly}&page=${page}&page_size=${pageSize}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function fetchStatusesByInstance({ instance, authHost, token, pageSize, page }) {
return await request({
baseURL: baseName(authHost),
......
......@@ -244,7 +244,9 @@ export default {
statuses: 'Statuses by instance',
instanceFilter: 'Instance filter',
loadMore: 'Load more',
noInstances: 'No other instances found'
noInstances: 'No other instances found',
onlyLocalStatuses: 'Show only local statuses',
showPrivateStatuses: 'Show private statuses'
},
userProfile: {
tags: 'Tags',
......@@ -255,7 +257,6 @@ export default {
localUppercase: 'Local',
nickname: 'Nickname',
recentStatuses: 'Recent Statuses',
showPrivateStatuses: 'Show private statuses',
roles: 'Roles',
activeUppercase: 'Active',
active: 'active',
......
......@@ -17,8 +17,6 @@ const getters = {
errorLogs: state => state.errorLog.logs,
users: state => state.users.fetchedUsers,
authHost: state => state.user.authHost,
settings: state => state.settings,
instances: state => state.peers.fetchedPeers,
statuses: state => state.status.fetchedStatuses
settings: state => state.settings
}
export default getters
......@@ -80,10 +80,15 @@ export const parseTuples = (tuples, key) => {
accum[item.tuple[0]] = item.tuple[1].reduce((acc, mascot) => {
return [...acc, { [mascot.tuple[0]]: { ...mascot.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
}, [])
} else if (item.tuple[0] === ':groups' || item.tuple[0] === ':replace' || item.tuple[0] === ':retries') {
} else if (
item.tuple[0] === ':groups' || item.tuple[0] === ':replace' || item.tuple[0] === ':retries') {
accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => {
return [...acc, { [group.tuple[0]]: { value: group.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
}, [])
} else if (item.tuple[0] === ':crontab') {
accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => {
return { ...acc, [group.tuple[1]]: group.tuple[0] }
}, {})
} else if (item.tuple[0] === ':match_actor') {
accum[item.tuple[0]] = Object.keys(item.tuple[1]).reduce((acc, regex) => {
return [...acc, { [regex]: { value: item.tuple[1][regex], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
......@@ -218,7 +223,12 @@ export const wrapUpdatedSettings = (group, settings, currentState) => {
const wrapValues = (settings, currentState) => {
return Object.keys(settings).map(setting => {
const [type, value] = settings[setting]
if (type === 'keyword' || type.includes('keyword') || setting === ':replace') {
if (
type === 'keyword' ||
type.includes('keyword') ||
type.includes('tuple') && type.includes('list') ||
setting === ':replace'
) {
return { 'tuple': [setting, wrapValues(value, currentState)] }
} else if (type === 'atom' && value.length > 0) {
return { 'tuple': [setting, `:${value}`] }
......@@ -226,8 +236,8 @@ const wrapValues = (settings, currentState) => {
return typeof value === 'string'
? { 'tuple': [setting, value] }
: { 'tuple': [setting, { 'tuple': value }] }
} else if (type.includes('tuple') && type.includes('list')) {
return { 'tuple': [setting, value] }
} else if (type === 'reversed_tuple') {
return { 'tuple': [value, setting] }
} else if (type === 'map') {
const mapValue = Object.keys(value).reduce((acc, key) => {
acc[key] = setting === ':match_actor' ? value[key] : value[key][1]
......
import { changeStatusScope, deleteStatus, fetchStatusesByInstance } from '@/api/status'
import { changeStatusScope, deleteStatus, fetchStatuses, fetchStatusesByInstance } from '@/api/status'
const status = {
state: {
......@@ -6,11 +6,21 @@ const status = {
loading: false,
statusesByInstance: {
selectedInstance: '',
showLocal: false,
showPrivate: false,
page: 1,
pageSize: 30
pageSize: 20,
buttonLoading: false,
allLoaded: false
}
},
mutations: {
CHANGE_GODMODE_CHECKBOX_VALUE: (state, value) => {
state.statusesByInstance.showPrivate = value
},
CHANGE_LOCAL_CHECKBOX_VALUE: (state, value) => {
state.statusesByInstance.showLocal = value
},
CHANGE_PAGE: (state, page) => {
state.statusesByInstance.page = page
},
......@@ -23,6 +33,12 @@ const status = {
PUSH_STATUSES: (state, statuses) => {
state.fetchedStatuses = [...state.fetchedStatuses, ...statuses]
},
SET_ALL_LOADED: (state, status) => {
state.statusesByInstance.allLoaded = status
},
SET_BUTTON_LOADING: (state, status) => {
state.statusesByInstance.buttonLoading = status
},
SET_LOADING: (state, status) => {
state.loading = status
}
......@@ -48,10 +64,48 @@ const status = {
dispatch('FetchStatusesByInstance')
}
},
async FetchStatusesByInstance({ commit, getters, state }) {
async FetchStatusesByInstance({ commit, getters, state, rootState }) {
commit('SET_LOADING', true)
const statuses = state.statusesByInstance.selectedInstance === ''
? { data: [] }
if (state.statusesByInstance.selectedInstance === '') {
commit('SET_STATUSES_BY_INSTANCE', [])
} else {
const statuses = state.statusesByInstance.selectedInstance === rootState.user.authHost
? await fetchStatuses(
{
godmode: state.statusesByInstance.showPrivate,
localOnly: state.statusesByInstance.showLocal,
authHost: getters.authHost,
token: getters.token,
pageSize: state.statusesByInstance.pageSize,
page: state.statusesByInstance.page
})
: await fetchStatusesByInstance(
{
instance: state.statusesByInstance.selectedInstance,
authHost: getters.authHost,
token: getters.token,
pageSize: state.statusesByInstance.pageSize,
page: state.statusesByInstance.page
})
commit('SET_STATUSES_BY_INSTANCE', statuses.data)
if (statuses.data.length < state.statusesByInstance.pageSize) {
commit('SET_ALL_LOADED', true)
}
}
commit('SET_LOADING', false)
},
async FetchStatusesPageByInstance({ commit, getters, rootState, state }) {
commit('SET_BUTTON_LOADING', true)
const statuses = state.statusesByInstance.selectedInstance === rootState.user.authHost
? await fetchStatuses(
{
godmode: state.statusesByInstance.showPrivate,
localOnly: state.statusesByInstance.showLocal,
authHost: getters.authHost,
token: getters.token,
pageSize: state.statusesByInstance.pageSize,
page: state.statusesByInstance.page
})
: await fetchStatusesByInstance(
{
instance: state.statusesByInstance.selectedInstance,
......@@ -60,26 +114,29 @@ const status = {
pageSize: state.statusesByInstance.pageSize,
page: state.statusesByInstance.page
})
commit('PUSH_STATUSES', statuses.data)
commit('SET_BUTTON_LOADING', false)
if (statuses.data.length < state.statusesByInstance.pageSize) {
commit('SET_ALL_LOADED', true)
}
},
HandleGodmodeCheckboxChange({ commit, dispatch }, value) {
dispatch('HandlePageChange', 1)
commit('SET_ALL_LOADED', false)
commit('SET_STATUSES_BY_INSTANCE', statuses.data)
commit('SET_LOADING', false)
commit('CHANGE_GODMODE_CHECKBOX_VALUE', value)
dispatch('FetchStatusesByInstance')
},
async FetchStatusesPageByInstance({ commit, getters, state }) {
commit('SET_LOADING', true)
const statuses = await fetchStatusesByInstance(
{
instance: state.statusesByInstance.selectedInstance,
authHost: getters.authHost,
token: getters.token,
pageSize: state.statusesByInstance.pageSize,
page: state.statusesByInstance.page
})
HandleLocalCheckboxChange({ commit, dispatch }, value) {
dispatch('HandlePageChange', 1)
commit('SET_ALL_LOADED', false)
commit('PUSH_STATUSES', statuses.data)
commit('SET_LOADING', false)
commit('CHANGE_LOCAL_CHECKBOX_VALUE', value)
dispatch('FetchStatusesByInstance')
},
HandleFilterChange({ commit }, instance) {
commit('CHANGE_SELECTED_INSTANCE', instance)
commit('SET_ALL_LOADED', false)
},
HandlePageChange({ commit }, page) {
commit('CHANGE_PAGE', page)
......
......@@ -84,11 +84,12 @@
</el-input>
<!-- special inputs -->
<auto-linker-input v-if="settingGroup.group === ':auto_linker'" :data="data" :setting-group="settingGroup" :setting="setting"/>
<mascots-input v-if="setting.key === ':mascots'" :data="keywordData" :setting-group="settingGroup" :setting="setting"/>
<crontab-input v-if="setting.key === ':crontab'" :data="data[setting.key]" :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"/>
<proxy-url-input v-if="setting.key === ':proxy_url'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting" :parents="settingParent"/>
<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"/>
<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"/>
<!-------------------->
......@@ -106,7 +107,7 @@
<script>
import i18n from '@/lang'
import { AutoLinkerInput, EditableKeywordInput, IconsInput, MascotsInput, MultipleSelect, ProxyUrlInput, PruneInput, RateLimitInput } from './inputComponents'
import { AutoLinkerInput, CrontabInput, EditableKeywordInput, IconsInput, MascotsInput, MultipleSelect, ProxyUrlInput, PruneInput, RateLimitInput } from './inputComponents'
import { processNested } from '@/store/modules/normalizers'
import _ from 'lodash'
import marked from 'marked'
......@@ -115,6 +116,7 @@ export default {
name: 'Inputs',
components: {
AutoLinkerInput,
CrontabInput,
EditableKeywordInput,
IconsInput,
MascotsInput,
......@@ -238,8 +240,8 @@ export default {
methods: {
editableKeyword(key, type) {
return key === ':replace' ||
(Array.isArray(type) && type.includes('keyword') && type.includes('integer')) ||
type === 'map' ||
(Array.isArray(type) && type.includes('keyword') && type.includes('integer')) ||
(Array.isArray(type) && type.includes('keyword') && type.findIndex(el => el.includes('list') && el.includes('string')) !== -1)
},
getFormattedDescription(desc) {
......
......@@ -31,6 +31,9 @@
<el-form ref="feed" :model="feedData" :label-width="labelWidth">
<setting :setting-group="feed" :data="feedData"/>
</el-form>
<el-form ref="streamer" :model="streamerData" :label-width="labelWidth">
<setting :setting-group="streamer" :data="streamerData"/>
</el-form>
<div class="submit-button-container">
<el-button class="submit-button" type="primary" @click="onSubmit">Submit</el-button>
</div>
......@@ -112,6 +115,12 @@ export default {
scheduledActivityData() {
return _.get(this.settings.settings, [':pleroma', 'Pleroma.ScheduledActivity']) || {}
},
streamer() {
return this.$store.state.settings.description.find(setting => setting.key === ':streamer')
},
streamerData() {
return _.get(this.settings.settings, [':pleroma', ':streamer']) || {}
},
uriSchemes() {
return this.settings.description.find(setting => setting.key === ':uri_schemes')
},
......
<template>
<el-form :label-width="labelWidth" :label-position="isMobile ? 'top' : 'right'" class="crontab">
<el-form-item v-for="worker in workers" :key="worker" :label="worker" class="crontab-container">
<el-input
:value="data[worker]"
:placeholder="getSuggestion(worker) || null"
class="input setting-input"
@input="update($event, worker)"/>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: 'CrontabInput',
props: {
data: {
type: Object,
default: function() {
return {}
}
},
setting: {
type: Object,
default: function() {
return {}
}
},
settingGroup: {
type: Object,
default: function() {
return {}
}
}
},
computed: {
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isTablet() {
return this.$store.state.app.device === 'tablet'
},
labelWidth() {
if (this.isMobile) {
return '100%'
} else {
return '380px'
}
},
workers() {
return this.setting.suggestions.map(worker => worker[1])
}
},
methods: {
getSuggestion(worker) {
return this.setting.suggestions.find(suggestion => suggestion[1] === worker)[0]
},
update(value, worker) {
const currentValue = this.$store.state.settings.settings[this.settingGroup.group][this.settingGroup.key][this.setting.key]
const updatedValue = { ...currentValue, [worker]: value }
const updatedValueWithType = Object.keys(currentValue).reduce((acc, key) => {
if (key === worker) {
return { ...acc, [key]: ['reversed_tuple', value] }
} else {
return { ...acc, [key]: ['reversed_tuple', currentValue[key]] }
}
}, {})
this.$store.dispatch('UpdateSettings',
{ group: this.settingGroup.group, key: this.settingGroup.key, input: this.setting.key, value: updatedValueWithType, type: this.setting.type }
)
this.$store.dispatch('UpdateState',
{ group: this.settingGroup.group, key: this.settingGroup.key, input: this.setting.key, value: updatedValue }
)
}
}
}
</script>
<style rel='stylesheet/scss' lang='scss'>
@import '../../styles/main';
@include settings
</style>
......@@ -96,15 +96,18 @@ export default {
this.updateSetting(updatedValue, this.settingGroup.group, this.settingGroup.key, this.setting.key, this.setting.type)
},
updateSetting(value, group, key, input, type) {
const updatedSettings = type !== 'map'
const updatedSettings = this.wrapUpdatedSettings(value, input, type)
this.$store.dispatch('UpdateSettings', { group, key, input, value: updatedSettings, type })
this.$store.dispatch('UpdateState', { group, key, input, value })
},
wrapUpdatedSettings(value, input, type) {
return type === 'map'
? value.reduce((acc, element) => {
return { ...acc, [Object.keys(element)[0]]: ['list', Object.values(element)[0].value] }
return { ...acc, [Object.keys(element)[0]]: Object.values(element)[0].value }
}, {})
: value.reduce((acc, element) => {
return { ...acc, [Object.keys(element)[0]]: Object.values(element)[0].value }
return { ...acc, [Object.keys(element)[0]]: ['list', Object.values(element)[0].value] }
}, {})
this.$store.dispatch('UpdateSettings', { group, key, input, value: updatedSettings, type })
this.$store.dispatch('UpdateState', { group, key, input, value })
}
}
}
......
export { default as AutoLinkerInput } from './AutoLinkerInput'
export { default as EditableKeywordInput } from './EditableKeywordInput'
export { default as CrontabInput } from './CrontabInput'
export { default as IconsInput } from './IconsInput'
export { default as MascotsInput } from './MascotsInput'
export { default as MultipleSelect } from './MultipleSelect'
......
......@@ -335,6 +335,12 @@
}
@media only screen and (max-width:480px) {
.crontab {
width: 100%;
label {
width: 100%;
}
}
.delete-setting-button {
margin: 4px 0 0 5px;
height: 28px;
......@@ -378,6 +384,10 @@
margin: 0;
padding: 0 15px 10px 0;
}
.el-form-item.crontab-container:first-child {
margin: 0;
padding: 0 ;
}
.el-form-item:first-child .mascot-form-item {
padding: 0;
}
......
......@@ -22,6 +22,15 @@
:selected-users="selectedUsers"
@apply-action="clearSelection"/>
</div>
<div v-if="currentInstance" class="checkbox-container">
<el-checkbox v-model="showLocal" class="show-private-statuses">
{{ $t('statuses.onlyLocalStatuses') }}
</el-checkbox>
<el-checkbox v-model="showPrivate" class="show-private-statuses">
{{ $t('statuses.showPrivateStatuses') }}
</el-checkbox>
</div>
<p v-if="statuses.length === 0" class="no-statuses">{{ $t('userProfile.noStatuses') }}</p>
<div v-for="status in statuses" :key="status.id" class="status-container">
<status
:status="status"
......@@ -30,13 +39,13 @@
@status-selection="handleStatusSelection" />
</div>
<div v-if="statuses.length > 0" class="statuses-pagination">
<el-button @click="handleLoadMore">{{ $t('statuses.loadMore') }}</el-button>
<el-button v-if="!allLoaded" :loading="buttonLoading" @click="handleLoadMore">{{ $t('statuses.loadMore') }}</el-button>
<el-button v-else icon="el-icon-check" circle/>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import MultipleUsersMenu from '@/views/users/components/MultipleUsersMenu'
import Status from '@/components/Status'
......@@ -52,10 +61,18 @@ export default {
}
},
computed: {
...mapGetters([
'instances',
'statuses'
]),
allLoaded() {
return this.$store.state.status.statusesByInstance.allLoaded
},
buttonLoading() {
return this.$store.state.status.statusesByInstance.buttonLoading
},
currentInstance() {
return this.selectedInstance === this.$store.state.user.authHost
},
instances() {
return [this.$store.state.user.authHost, ...this.$store.state.peers.fetchedPeers]
},
isDesktop() {
return this.$store.state.app.device === 'desktop'
},
......@@ -75,6 +92,25 @@ export default {
set(instance) {
this.$store.dispatch('HandleFilterChange', instance)
}
},
showLocal: {
get() {
return this.$store.state.status.statusesByInstance.showLocal
},
set(value) {
this.$store.dispatch('HandleLocalCheckboxChange', value)
}
},
showPrivate: {
get() {
return this.$store.state.status.statusesByInstance.showPrivate
},
set(value) {
this.$store.dispatch('HandleGodmodeCheckboxChange', value)
}
},
statuses() {
return this.$store.state.status.fetchedStatuses
}
},
mounted() {
......@@ -97,7 +133,6 @@ export default {
if (this.selectedUsers.find(selectedUser => user.id === selectedUser.id) !== undefined) {
return
}
this.selectedUsers = [...this.selectedUsers, user]
}
}
......@@ -111,6 +146,9 @@ export default {
margin: 0 0 10px;
}
}
.checkbox-container {
margin-bottom: 15px;
}
.filter-container {
display: flex;
height: 36px;
......@@ -130,6 +168,9 @@ h1 {
}
@media only screen and (max-width:480px) {
.checkbox-container {
margin-bottom: 10px;
}
.filter-container {
display: flex;
height: 36px;
......
......@@ -80,7 +80,7 @@
<div class="recent-statuses-container">
<h2 class="recent-statuses">{{ $t('userProfile.recentStatuses') }}</h2>
<el-checkbox v-model="showPrivate" class="show-private-statuses" @change="onTogglePrivate">
{{ $t('userProfile.showPrivateStatuses') }}
{{ $t('statuses.showPrivateStatuses') }}
</el-checkbox>
<el-timeline v-if="!statusesLoading" class="statuses">
<el-timeline-item v-for="status in statuses" :key="status.id">
......