Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma-fe into feat/report-notification
This commit is contained in:
commit
18d69f93d3
217 changed files with 6246 additions and 4489 deletions
|
|
@ -9,6 +9,8 @@ const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
|
|||
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
|
||||
const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
|
||||
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
||||
const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
|
||||
const ALIASES_URL = '/api/pleroma/aliases'
|
||||
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
||||
const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
|
||||
const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
|
||||
|
|
@ -88,6 +90,7 @@ const PLEROMA_CHAT_MESSAGES_URL = id => `/api/v1/pleroma/chats/${id}/messages`
|
|||
const PLEROMA_CHAT_READ_URL = id => `/api/v1/pleroma/chats/${id}/read`
|
||||
const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) => `/api/v1/pleroma/chats/${chatId}/messages/${messageId}`
|
||||
const PLEROMA_ADMIN_REPORTS = '/api/pleroma/admin/reports'
|
||||
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
|
||||
|
||||
const oldfetch = window.fetch
|
||||
|
||||
|
|
@ -152,9 +155,15 @@ const updateNotificationSettings = ({ credentials, settings }) => {
|
|||
}).then((data) => data.json())
|
||||
}
|
||||
|
||||
const updateProfileImages = ({ credentials, avatar = null, banner = null, background = null }) => {
|
||||
const updateProfileImages = ({ credentials, avatar = null, avatarName = null, banner = null, background = null }) => {
|
||||
const form = new FormData()
|
||||
if (avatar !== null) form.append('avatar', avatar)
|
||||
if (avatar !== null) {
|
||||
if (avatarName !== null) {
|
||||
form.append('avatar', avatar, avatarName)
|
||||
} else {
|
||||
form.append('avatar', avatar)
|
||||
}
|
||||
}
|
||||
if (banner !== null) form.append('header', banner)
|
||||
if (background !== null) form.append('pleroma_background_image', background)
|
||||
return fetch(MASTODON_PROFILE_UPDATE_URL, {
|
||||
|
|
@ -192,6 +201,7 @@ const updateProfile = ({ credentials, params }) => {
|
|||
// homepage
|
||||
// location
|
||||
// token
|
||||
// language
|
||||
const register = ({ params, credentials }) => {
|
||||
const { nickname, ...rest } = params
|
||||
return fetch(MASTODON_REGISTRATION_URL, {
|
||||
|
|
@ -789,6 +799,49 @@ const changeEmail = ({ credentials, email, password }) => {
|
|||
.then((response) => response.json())
|
||||
}
|
||||
|
||||
const moveAccount = ({ credentials, password, targetAccount }) => {
|
||||
const form = new FormData()
|
||||
|
||||
form.append('password', password)
|
||||
form.append('target_account', targetAccount)
|
||||
|
||||
return fetch(MOVE_ACCOUNT_URL, {
|
||||
body: form,
|
||||
method: 'POST',
|
||||
headers: authHeaders(credentials)
|
||||
})
|
||||
.then((response) => response.json())
|
||||
}
|
||||
|
||||
const addAlias = ({ credentials, alias }) => {
|
||||
return promisedRequest({
|
||||
url: ALIASES_URL,
|
||||
method: 'PUT',
|
||||
credentials,
|
||||
payload: { alias }
|
||||
})
|
||||
}
|
||||
|
||||
const deleteAlias = ({ credentials, alias }) => {
|
||||
return promisedRequest({
|
||||
url: ALIASES_URL,
|
||||
method: 'DELETE',
|
||||
credentials,
|
||||
payload: { alias }
|
||||
})
|
||||
}
|
||||
|
||||
const listAliases = ({ credentials }) => {
|
||||
return promisedRequest({
|
||||
url: ALIASES_URL,
|
||||
method: 'GET',
|
||||
credentials,
|
||||
params: {
|
||||
_cacheBooster: (new Date()).getTime()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const changePassword = ({ credentials, password, newPassword, newPasswordConfirmation }) => {
|
||||
const form = new FormData()
|
||||
|
||||
|
|
@ -875,6 +928,25 @@ const fetchBlocks = ({ credentials }) => {
|
|||
.then((users) => users.map(parseUser))
|
||||
}
|
||||
|
||||
const addBackup = ({ credentials }) => {
|
||||
return promisedRequest({
|
||||
url: PLEROMA_BACKUP_URL,
|
||||
method: 'POST',
|
||||
credentials
|
||||
})
|
||||
}
|
||||
|
||||
const listBackups = ({ credentials }) => {
|
||||
return promisedRequest({
|
||||
url: PLEROMA_BACKUP_URL,
|
||||
method: 'GET',
|
||||
credentials,
|
||||
params: {
|
||||
_cacheBooster: (new Date()).getTime()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const fetchOAuthTokens = ({ credentials }) => {
|
||||
const url = '/api/oauth_tokens.json'
|
||||
|
||||
|
|
@ -1358,12 +1430,18 @@ const apiService = {
|
|||
importFollows,
|
||||
deleteAccount,
|
||||
changeEmail,
|
||||
moveAccount,
|
||||
addAlias,
|
||||
deleteAlias,
|
||||
listAliases,
|
||||
changePassword,
|
||||
settingsMFA,
|
||||
mfaDisableOTP,
|
||||
generateMfaBackupCodes,
|
||||
mfaSetupOTP,
|
||||
mfaConfirmOTP,
|
||||
addBackup,
|
||||
listBackups,
|
||||
fetchFollowRequests,
|
||||
approveUser,
|
||||
denyUser,
|
||||
|
|
|
|||
|
|
@ -10,31 +10,29 @@ export const relativeTime = (date, nowThreshold = 1) => {
|
|||
if (typeof date === 'string') date = Date.parse(date)
|
||||
const round = Date.now() > date ? Math.floor : Math.ceil
|
||||
const d = Math.abs(Date.now() - date)
|
||||
let r = { num: round(d / YEAR), key: 'time.years' }
|
||||
let r = { num: round(d / YEAR), key: 'time.unit.years' }
|
||||
if (d < nowThreshold * SECOND) {
|
||||
r.num = 0
|
||||
r.key = 'time.now'
|
||||
} else if (d < MINUTE) {
|
||||
r.num = round(d / SECOND)
|
||||
r.key = 'time.seconds'
|
||||
r.key = 'time.unit.seconds'
|
||||
} else if (d < HOUR) {
|
||||
r.num = round(d / MINUTE)
|
||||
r.key = 'time.minutes'
|
||||
r.key = 'time.unit.minutes'
|
||||
} else if (d < DAY) {
|
||||
r.num = round(d / HOUR)
|
||||
r.key = 'time.hours'
|
||||
r.key = 'time.unit.hours'
|
||||
} else if (d < WEEK) {
|
||||
r.num = round(d / DAY)
|
||||
r.key = 'time.days'
|
||||
r.key = 'time.unit.days'
|
||||
} else if (d < MONTH) {
|
||||
r.num = round(d / WEEK)
|
||||
r.key = 'time.weeks'
|
||||
r.key = 'time.unit.weeks'
|
||||
} else if (d < YEAR) {
|
||||
r.num = round(d / MONTH)
|
||||
r.key = 'time.months'
|
||||
r.key = 'time.unit.months'
|
||||
}
|
||||
// Remove plural form when singular
|
||||
if (r.num === 1) r.key = r.key.slice(0, -1)
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import utf8 from 'utf8'
|
||||
|
||||
export const newExporter = ({
|
||||
filename = 'data',
|
||||
getExportedObject
|
||||
}) => ({
|
||||
exportData () {
|
||||
const stringified = JSON.stringify(getExportedObject(), null, 2) // Pretty-print and indent with 2 spaces
|
||||
const stringified = utf8.encode(JSON.stringify(getExportedObject(), null, 2)) // Pretty-print and indent with 2 spaces
|
||||
|
||||
// Create an invisible link with a data url and simulate a click
|
||||
const e = document.createElement('a')
|
||||
|
|
|
|||
|
|
@ -1,12 +1,35 @@
|
|||
import languagesObject from '../../i18n/messages'
|
||||
import ISO6391 from 'iso-639-1'
|
||||
import _ from 'lodash'
|
||||
|
||||
const specialLanguageCodes = {
|
||||
'ja_easy': 'ja',
|
||||
'zh_Hant': 'zh-HANT'
|
||||
'zh_Hant': 'zh-HANT',
|
||||
'zh': 'zh-Hans'
|
||||
}
|
||||
|
||||
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
|
||||
|
||||
const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_', '-')
|
||||
|
||||
const getLanguageName = (code) => {
|
||||
const specialLanguageNames = {
|
||||
'ja_easy': 'やさしいにほんご',
|
||||
'zh': '简体中文',
|
||||
'zh_Hant': '繁體中文'
|
||||
}
|
||||
const languageName = specialLanguageNames[code] || ISO6391.getNativeName(code)
|
||||
const browserLocale = internalToBrowserLocale(code)
|
||||
return languageName.charAt(0).toLocaleUpperCase(browserLocale) + languageName.slice(1)
|
||||
}
|
||||
|
||||
const languages = _.map(languagesObject.languages, (code) => ({ code: code, name: getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
const localeService = {
|
||||
internalToBrowserLocale
|
||||
internalToBrowserLocale,
|
||||
internalToBackendLocale,
|
||||
languages,
|
||||
getLanguageName
|
||||
}
|
||||
|
||||
export default localeService
|
||||
|
|
|
|||
|
|
@ -15,11 +15,12 @@ export const visibleTypes = store => {
|
|||
rootState.config.notificationVisibility.followRequest && 'follow_request',
|
||||
rootState.config.notificationVisibility.moves && 'move',
|
||||
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction',
|
||||
rootState.config.notificationVisibility.reports && 'pleroma:report'
|
||||
rootState.config.notificationVisibility.reports && 'pleroma:report',
|
||||
rootState.config.notificationVisibility.polls && 'poll'
|
||||
].filter(_ => _))
|
||||
}
|
||||
|
||||
const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction']
|
||||
const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction', 'poll']
|
||||
|
||||
export const isStatusNotification = (type) => includes(statusNotifications, type)
|
||||
|
||||
|
|
@ -102,6 +103,9 @@ export const prepareNotificationObject = (notification, i18n) => {
|
|||
case 'pleroma:report':
|
||||
i18nString = 'submitted_report'
|
||||
break
|
||||
case 'poll':
|
||||
i18nString = 'poll_ended'
|
||||
break
|
||||
}
|
||||
|
||||
if (notification.type === 'pleroma:emoji_reaction') {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export const findOffset = (child, parent, { top = 0, left = 0 } = {}, ignorePadd
|
|||
result.left += ignorePadding ? 0 : leftPadding
|
||||
}
|
||||
|
||||
if (child.offsetParent && (parent === window || parent.contains(child.offsetParent) || parent === child.offsetParent)) {
|
||||
if (child.offsetParent && window.getComputedStyle(child.offsetParent).position !== 'sticky' && (parent === window || parent.contains(child.offsetParent) || parent === child.offsetParent)) {
|
||||
return findOffset(child.offsetParent, parent, result, false)
|
||||
} else {
|
||||
if (parent !== window) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Vue from 'vue'
|
||||
import { defineAsyncComponent, shallowReactive, h } from 'vue'
|
||||
|
||||
/* By default async components don't have any way to recover, if component is
|
||||
* failed, it is failed forever. This helper tries to remedy that by recreating
|
||||
|
|
@ -8,23 +8,21 @@ import Vue from 'vue'
|
|||
* actual target component itself if needs to be.
|
||||
*/
|
||||
function getResettableAsyncComponent (asyncComponent, options) {
|
||||
const asyncComponentFactory = () => () => ({
|
||||
component: asyncComponent(),
|
||||
const asyncComponentFactory = () => () => defineAsyncComponent({
|
||||
loader: asyncComponent,
|
||||
...options
|
||||
})
|
||||
|
||||
const observe = Vue.observable({ c: asyncComponentFactory() })
|
||||
const observe = shallowReactive({ c: asyncComponentFactory() })
|
||||
|
||||
return {
|
||||
functional: true,
|
||||
render (createElement, { data, children }) {
|
||||
render () {
|
||||
// emit event resetAsyncComponent to reloading
|
||||
data.on = {}
|
||||
data.on.resetAsyncComponent = () => {
|
||||
observe.c = asyncComponentFactory()
|
||||
// parent.$forceUpdate()
|
||||
}
|
||||
return createElement(observe.c, data, children)
|
||||
return h(observe.c(), {
|
||||
onResetAsyncComponent () {
|
||||
observe.c = asyncComponentFactory()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ export const applyTheme = (input) => {
|
|||
const styleSheet = styleEl.sheet
|
||||
|
||||
styleSheet.toString()
|
||||
styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max')
|
||||
styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max')
|
||||
styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
|
||||
styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
|
||||
styleSheet.insertRule(`:root { ${rules.radii} }`, 'index-max')
|
||||
styleSheet.insertRule(`:root { ${rules.colors} }`, 'index-max')
|
||||
styleSheet.insertRule(`:root { ${rules.shadows} }`, 'index-max')
|
||||
styleSheet.insertRule(`:root { ${rules.fonts} }`, 'index-max')
|
||||
body.classList.remove('hidden')
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue