biome format --write
This commit is contained in:
parent
8372348148
commit
9262e803ec
415 changed files with 54076 additions and 17419 deletions
|
|
@ -6,41 +6,48 @@ export const useAnnouncementsStore = defineStore('announcements', {
|
|||
state: () => ({
|
||||
announcements: [],
|
||||
supportsAnnouncements: true,
|
||||
fetchAnnouncementsTimer: undefined
|
||||
fetchAnnouncementsTimer: undefined,
|
||||
}),
|
||||
getters: {
|
||||
unreadAnnouncementCount () {
|
||||
unreadAnnouncementCount() {
|
||||
if (!window.vuex.state.users.currentUser) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const unread = this.announcements.filter(announcement => !(announcement.inactive || announcement.read))
|
||||
const unread = this.announcements.filter(
|
||||
(announcement) => !(announcement.inactive || announcement.read),
|
||||
)
|
||||
return unread.length
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
fetchAnnouncements () {
|
||||
fetchAnnouncements() {
|
||||
if (!this.supportsAnnouncements) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
const currentUser = window.vuex.state.users.currentUser
|
||||
const isAdmin = currentUser && currentUser.privileges.includes('announcements_manage_announcements')
|
||||
const isAdmin =
|
||||
currentUser &&
|
||||
currentUser.privileges.includes('announcements_manage_announcements')
|
||||
|
||||
const getAnnouncements = async () => {
|
||||
if (!isAdmin) {
|
||||
return window.vuex.state.api.backendInteractor.fetchAnnouncements()
|
||||
}
|
||||
|
||||
const all = await window.vuex.state.api.backendInteractor.adminFetchAnnouncements()
|
||||
const visible = await window.vuex.state.api.backendInteractor.fetchAnnouncements()
|
||||
const all =
|
||||
await window.vuex.state.api.backendInteractor.adminFetchAnnouncements()
|
||||
const visible =
|
||||
await window.vuex.state.api.backendInteractor.fetchAnnouncements()
|
||||
const visibleObject = visible.reduce((a, c) => {
|
||||
a[c.id] = c
|
||||
return a
|
||||
}, {})
|
||||
const getWithinVisible = announcement => visibleObject[announcement.id]
|
||||
const getWithinVisible = (announcement) =>
|
||||
visibleObject[announcement.id]
|
||||
|
||||
all.forEach(announcement => {
|
||||
all.forEach((announcement) => {
|
||||
const visibleAnnouncement = getWithinVisible(announcement)
|
||||
if (!visibleAnnouncement) {
|
||||
announcement.inactive = true
|
||||
|
|
@ -53,10 +60,10 @@ export const useAnnouncementsStore = defineStore('announcements', {
|
|||
}
|
||||
|
||||
return getAnnouncements()
|
||||
.then(announcements => {
|
||||
.then((announcements) => {
|
||||
this.announcements = announcements
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
// If and only if backend does not support announcements, it would return 404.
|
||||
// In this case, silently ignores it.
|
||||
if (error && error.statusCode === 404) {
|
||||
|
|
@ -66,10 +73,11 @@ export const useAnnouncementsStore = defineStore('announcements', {
|
|||
}
|
||||
})
|
||||
},
|
||||
markAnnouncementAsRead (id) {
|
||||
return window.vuex.state.api.backendInteractor.dismissAnnouncement({ id })
|
||||
markAnnouncementAsRead(id) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.dismissAnnouncement({ id })
|
||||
.then(() => {
|
||||
const index = this.announcements.findIndex(a => a.id === id)
|
||||
const index = this.announcements.findIndex((a) => a.id === id)
|
||||
|
||||
if (index < 0) {
|
||||
return
|
||||
|
|
@ -78,38 +86,44 @@ export const useAnnouncementsStore = defineStore('announcements', {
|
|||
this.announcements[index].read = true
|
||||
})
|
||||
},
|
||||
startFetchingAnnouncements () {
|
||||
startFetchingAnnouncements() {
|
||||
if (this.fetchAnnouncementsTimer) {
|
||||
return
|
||||
}
|
||||
|
||||
const interval = setInterval(() => this.fetchAnnouncements(), FETCH_ANNOUNCEMENT_INTERVAL_MS)
|
||||
const interval = setInterval(
|
||||
() => this.fetchAnnouncements(),
|
||||
FETCH_ANNOUNCEMENT_INTERVAL_MS,
|
||||
)
|
||||
this.fetchAnnouncementsTimer = interval
|
||||
|
||||
return this.fetchAnnouncements()
|
||||
},
|
||||
stopFetchingAnnouncements () {
|
||||
stopFetchingAnnouncements() {
|
||||
const interval = this.fetchAnnouncementsTimer
|
||||
this.fetchAnnouncementsTimer = undefined
|
||||
clearInterval(interval)
|
||||
},
|
||||
postAnnouncement ({ content, startsAt, endsAt, allDay }) {
|
||||
return window.vuex.state.api.backendInteractor.postAnnouncement({ content, startsAt, endsAt, allDay })
|
||||
postAnnouncement({ content, startsAt, endsAt, allDay }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.postAnnouncement({ content, startsAt, endsAt, allDay })
|
||||
.then(() => {
|
||||
return this.fetchAnnouncements()
|
||||
})
|
||||
},
|
||||
editAnnouncement ({ id, content, startsAt, endsAt, allDay }) {
|
||||
return window.vuex.state.api.backendInteractor.editAnnouncement({ id, content, startsAt, endsAt, allDay })
|
||||
editAnnouncement({ id, content, startsAt, endsAt, allDay }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.editAnnouncement({ id, content, startsAt, endsAt, allDay })
|
||||
.then(() => {
|
||||
return this.fetchAnnouncements()
|
||||
})
|
||||
},
|
||||
deleteAnnouncement (id) {
|
||||
return window.vuex.state.api.backendInteractor.deleteAnnouncement({ id })
|
||||
deleteAnnouncement(id) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.deleteAnnouncement({ id })
|
||||
.then(() => {
|
||||
return this.fetchAnnouncements()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const useAuthFlowStore = defineStore('authFlow', {
|
|||
state: () => ({
|
||||
settings: {},
|
||||
strategy: PASSWORD_STRATEGY,
|
||||
initStrategy: PASSWORD_STRATEGY // default strategy from config
|
||||
initStrategy: PASSWORD_STRATEGY, // default strategy from config
|
||||
}),
|
||||
// getters
|
||||
getters: {
|
||||
|
|
@ -31,39 +31,39 @@ export const useAuthFlowStore = defineStore('authFlow', {
|
|||
},
|
||||
},
|
||||
actions: {
|
||||
setInitialStrategy (strategy) {
|
||||
setInitialStrategy(strategy) {
|
||||
if (strategy) {
|
||||
this.initStrategy = strategy
|
||||
this.strategy = strategy
|
||||
}
|
||||
},
|
||||
requirePassword () {
|
||||
requirePassword() {
|
||||
this.strategy = PASSWORD_STRATEGY
|
||||
},
|
||||
requireToken () {
|
||||
requireToken() {
|
||||
this.strategy = TOKEN_STRATEGY
|
||||
},
|
||||
requireMFA ({ settings }) {
|
||||
requireMFA({ settings }) {
|
||||
this.settings = settings
|
||||
this.strategy = TOTP_STRATEGY // default strategy of MFA
|
||||
},
|
||||
requireRecovery () {
|
||||
requireRecovery() {
|
||||
this.strategy = RECOVERY_STRATEGY
|
||||
},
|
||||
requireTOTP () {
|
||||
requireTOTP() {
|
||||
this.strategy = TOTP_STRATEGY
|
||||
},
|
||||
abortMFA () {
|
||||
abortMFA() {
|
||||
this.resetState()
|
||||
},
|
||||
resetState () {
|
||||
resetState() {
|
||||
this.strategy = this.initStrategy
|
||||
this.settings = {}
|
||||
},
|
||||
async login ({ access_token: accessToken }) {
|
||||
async login({ access_token: accessToken }) {
|
||||
useOAuthStore().setToken(accessToken)
|
||||
await window.vuex.dispatch('loginUser', accessToken, { root: true })
|
||||
this.resetState()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,23 +3,23 @@ import { defineStore } from 'pinia'
|
|||
|
||||
export const useBookmarkFoldersStore = defineStore('bookmarkFolders', {
|
||||
state: () => ({
|
||||
allFolders: []
|
||||
allFolders: [],
|
||||
}),
|
||||
getters: {
|
||||
findBookmarkFolderName () {
|
||||
findBookmarkFolderName() {
|
||||
return (id) => {
|
||||
const folder = this.allFolders.find(folder => folder.id === id)
|
||||
|
||||
const folder = this.allFolders.find((folder) => folder.id === id)
|
||||
|
||||
if (!folder) return
|
||||
return folder.name
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setBookmarkFolders (value) {
|
||||
setBookmarkFolders(value) {
|
||||
this.allFolders = value
|
||||
},
|
||||
setBookmarkFolder ({ id, name, emoji, emoji_url: emojiUrl }) {
|
||||
setBookmarkFolder({ id, name, emoji, emoji_url: emojiUrl }) {
|
||||
const entry = find(this.allFolders, { id })
|
||||
if (!entry) {
|
||||
this.allFolders.push({ id, name, emoji, emoji_url: emojiUrl })
|
||||
|
|
@ -29,23 +29,25 @@ export const useBookmarkFoldersStore = defineStore('bookmarkFolders', {
|
|||
entry.emoji_url = emojiUrl
|
||||
}
|
||||
},
|
||||
createBookmarkFolder ({ name, emoji }) {
|
||||
return window.vuex.state.api.backendInteractor.createBookmarkFolder({ name, emoji })
|
||||
createBookmarkFolder({ name, emoji }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.createBookmarkFolder({ name, emoji })
|
||||
.then((folder) => {
|
||||
this.setBookmarkFolder(folder)
|
||||
return folder
|
||||
})
|
||||
},
|
||||
updateBookmarkFolder ({ folderId, name, emoji }) {
|
||||
return window.vuex.state.api.backendInteractor.updateBookmarkFolder({ folderId, name, emoji })
|
||||
updateBookmarkFolder({ folderId, name, emoji }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.updateBookmarkFolder({ folderId, name, emoji })
|
||||
.then((folder) => {
|
||||
this.setBookmarkFolder(folder)
|
||||
return folder
|
||||
})
|
||||
},
|
||||
deleteBookmarkFolder ({ folderId }) {
|
||||
deleteBookmarkFolder({ folderId }) {
|
||||
window.vuex.state.api.backendInteractor.deleteBookmarkFolder({ folderId })
|
||||
remove(this.allFolders, folder => folder.id === folderId)
|
||||
}
|
||||
}
|
||||
remove(this.allFolders, (folder) => folder.id === folderId)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@ import { defineStore } from 'pinia'
|
|||
export const useEditStatusStore = defineStore('editStatus', {
|
||||
state: () => ({
|
||||
params: null,
|
||||
modalActivated: false
|
||||
modalActivated: false,
|
||||
}),
|
||||
actions: {
|
||||
openEditStatusModal (params) {
|
||||
openEditStatusModal(params) {
|
||||
this.params = params
|
||||
this.modalActivated = true
|
||||
},
|
||||
closeEditStatusModal () {
|
||||
closeEditStatusModal() {
|
||||
this.modalActivated = false
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import { defineStore } from 'pinia'
|
|||
|
||||
export const useI18nStore = defineStore('i18n', {
|
||||
state: () => ({
|
||||
i18n: null
|
||||
i18n: null,
|
||||
}),
|
||||
actions: {
|
||||
setI18n (newI18n) {
|
||||
setI18n(newI18n) {
|
||||
this.$patch({
|
||||
i18n: newI18n.global
|
||||
i18n: newI18n.global,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
import { CURRENT_VERSION, generatePreset } from 'src/services/theme_data/theme_data.service.js'
|
||||
import { getResourcesIndex, applyTheme, tryLoadCache } from '../services/style_setter/style_setter.js'
|
||||
import {
|
||||
CURRENT_VERSION,
|
||||
generatePreset,
|
||||
} from 'src/services/theme_data/theme_data.service.js'
|
||||
import {
|
||||
getResourcesIndex,
|
||||
applyTheme,
|
||||
tryLoadCache,
|
||||
} from '../services/style_setter/style_setter.js'
|
||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||
import { deserialize } from '../services/theme_data/iss_deserializer.js'
|
||||
|
||||
|
|
@ -19,9 +26,9 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
themeNameUsed: null,
|
||||
themeDataUsed: null,
|
||||
temporaryChangesTimeoutId: null,
|
||||
temporaryChangesCountdown: -1, // used for temporary options that revert after a timeout
|
||||
temporaryChangesCountdown: -1, // used for temporary options that revert after a timeout
|
||||
temporaryChangesConfirm: () => {}, // used for applying temporary options
|
||||
temporaryChangesRevert: () => {}, // used for reverting temporary options
|
||||
temporaryChangesRevert: () => {}, // used for reverting temporary options
|
||||
settingsModalState: 'hidden',
|
||||
settingsModalLoadedUser: false,
|
||||
settingsModalLoadedAdmin: false,
|
||||
|
|
@ -30,22 +37,23 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
settings: {
|
||||
currentSaveStateNotice: null,
|
||||
noticeClearTimeout: null,
|
||||
notificationPermission: null
|
||||
notificationPermission: null,
|
||||
},
|
||||
browserSupport: {
|
||||
cssFilter: window.CSS && window.CSS.supports && (
|
||||
window.CSS.supports('filter', 'drop-shadow(0 0)') ||
|
||||
window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')
|
||||
),
|
||||
localFonts: typeof window.queryLocalFonts === 'function'
|
||||
cssFilter:
|
||||
window.CSS &&
|
||||
window.CSS.supports &&
|
||||
(window.CSS.supports('filter', 'drop-shadow(0 0)') ||
|
||||
window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')),
|
||||
localFonts: typeof window.queryLocalFonts === 'function',
|
||||
},
|
||||
layoutType: 'normal',
|
||||
globalNotices: [],
|
||||
layoutHeight: 0,
|
||||
lastTimeline: null
|
||||
lastTimeline: null,
|
||||
}),
|
||||
actions: {
|
||||
setTemporaryChanges ({ confirm, revert }) {
|
||||
setTemporaryChanges({ confirm, revert }) {
|
||||
this.temporaryChangesCountdown = 10
|
||||
this.temporaryChangesConfirm = confirm
|
||||
this.temporaryChangesRevert = revert
|
||||
|
|
@ -60,38 +68,42 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
}
|
||||
this.temporaryChangesTimeoutId = setTimeout(countdownFunc, 1000)
|
||||
},
|
||||
clearTemporaryChanges () {
|
||||
this.temporaryChangesTimeoutId ?? clearTimeout(this.temporaryChangesTimeoutId)
|
||||
clearTemporaryChanges() {
|
||||
this.temporaryChangesTimeoutId ??
|
||||
clearTimeout(this.temporaryChangesTimeoutId)
|
||||
this.temporaryChangesTimeoutId = null
|
||||
this.temporaryChangesCountdown = -1
|
||||
this.temporaryChangesConfirm = () => {}
|
||||
this.temporaryChangesRevert = () => {}
|
||||
},
|
||||
setPageTitle (option = '') {
|
||||
setPageTitle(option = '') {
|
||||
try {
|
||||
document.title = `${option} ${window.vuex.state.instance.name}`
|
||||
} catch (error) {
|
||||
console.error(`${error}`)
|
||||
}
|
||||
},
|
||||
settingsSaved ({ success, error }) {
|
||||
settingsSaved({ success, error }) {
|
||||
if (success) {
|
||||
if (this.noticeClearTimeout) {
|
||||
clearTimeout(this.noticeClearTimeout)
|
||||
}
|
||||
this.settings.currentSaveStateNotice = { error: false, data: success }
|
||||
this.settings.noticeClearTimeout = setTimeout(() => delete this.settings.currentSaveStateNotice, 2000)
|
||||
this.settings.noticeClearTimeout = setTimeout(
|
||||
() => delete this.settings.currentSaveStateNotice,
|
||||
2000,
|
||||
)
|
||||
} else {
|
||||
this.settings.currentSaveStateNotice = { error: true, errorData: error }
|
||||
}
|
||||
},
|
||||
setNotificationPermission (permission) {
|
||||
setNotificationPermission(permission) {
|
||||
this.notificationPermission = permission
|
||||
},
|
||||
closeSettingsModal () {
|
||||
closeSettingsModal() {
|
||||
this.settingsModalState = 'hidden'
|
||||
},
|
||||
openSettingsModal (value) {
|
||||
openSettingsModal(value) {
|
||||
this.settingsModalMode = value
|
||||
this.settingsModalState = 'visible'
|
||||
if (value === 'user') {
|
||||
|
|
@ -104,7 +116,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
}
|
||||
}
|
||||
},
|
||||
togglePeekSettingsModal () {
|
||||
togglePeekSettingsModal() {
|
||||
switch (this.settingsModalState) {
|
||||
case 'minimized':
|
||||
this.settingsModalState = 'visible'
|
||||
|
|
@ -116,27 +128,26 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
throw new Error('Illegal minimization state of settings modal')
|
||||
}
|
||||
},
|
||||
clearSettingsModalTargetTab () {
|
||||
clearSettingsModalTargetTab() {
|
||||
this.settingsModalTargetTab = null
|
||||
},
|
||||
openSettingsModalTab (value, mode = 'user') {
|
||||
openSettingsModalTab(value, mode = 'user') {
|
||||
this.settingsModalTargetTab = value
|
||||
this.openSettingsModal(mode)
|
||||
},
|
||||
removeGlobalNotice (notice) {
|
||||
this.globalNotices = this.globalNotices.filter(n => n !== notice)
|
||||
removeGlobalNotice(notice) {
|
||||
this.globalNotices = this.globalNotices.filter((n) => n !== notice)
|
||||
},
|
||||
pushGlobalNotice (
|
||||
{
|
||||
messageKey,
|
||||
messageArgs = {},
|
||||
level = 'error',
|
||||
timeout = 0
|
||||
}) {
|
||||
pushGlobalNotice({
|
||||
messageKey,
|
||||
messageArgs = {},
|
||||
level = 'error',
|
||||
timeout = 0,
|
||||
}) {
|
||||
const notice = {
|
||||
messageKey,
|
||||
messageArgs,
|
||||
level
|
||||
level,
|
||||
}
|
||||
|
||||
this.globalNotices.push(notice)
|
||||
|
|
@ -150,10 +161,10 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
return newNotice
|
||||
},
|
||||
setLayoutHeight (value) {
|
||||
setLayoutHeight(value) {
|
||||
this.layoutHeight = value
|
||||
},
|
||||
setLayoutWidth (value) {
|
||||
setLayoutWidth(value) {
|
||||
let width = value
|
||||
if (value !== undefined) {
|
||||
this.layoutWidth = value
|
||||
|
|
@ -171,10 +182,10 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
this.layoutType = wideLayout ? 'wide' : normalOrMobile
|
||||
}
|
||||
},
|
||||
setFontsList (value) {
|
||||
this.localFonts = [...(new Set(value.map(font => font.family))).values()]
|
||||
setFontsList(value) {
|
||||
this.localFonts = [...new Set(value.map((font) => font.family)).values()]
|
||||
},
|
||||
queryLocalFonts () {
|
||||
queryLocalFonts() {
|
||||
if (this.localFonts !== null) return
|
||||
this.setFontsList([])
|
||||
|
||||
|
|
@ -190,27 +201,33 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
this.pushGlobalNotice({
|
||||
messageKey: 'settings.style.themes3.font.font_list_unavailable',
|
||||
messageArgs: {
|
||||
error: e
|
||||
error: e,
|
||||
},
|
||||
level: 'error'
|
||||
level: 'error',
|
||||
})
|
||||
})
|
||||
},
|
||||
setLastTimeline (value) {
|
||||
setLastTimeline(value) {
|
||||
this.lastTimeline = value
|
||||
},
|
||||
async fetchPalettesIndex () {
|
||||
async fetchPalettesIndex() {
|
||||
try {
|
||||
const value = await getResourcesIndex('/static/palettes/index.json')
|
||||
window.vuex.commit('setInstanceOption', { name: 'palettesIndex', value })
|
||||
window.vuex.commit('setInstanceOption', {
|
||||
name: 'palettesIndex',
|
||||
value,
|
||||
})
|
||||
return value
|
||||
} catch (e) {
|
||||
console.error('Could not fetch palettes index', e)
|
||||
window.vuex.commit('setInstanceOption', { name: 'palettesIndex', value: { _error: e } })
|
||||
window.vuex.commit('setInstanceOption', {
|
||||
name: 'palettesIndex',
|
||||
value: { _error: e },
|
||||
})
|
||||
return Promise.resolve({})
|
||||
}
|
||||
},
|
||||
setPalette (value) {
|
||||
setPalette(value) {
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
||||
|
|
@ -218,7 +235,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
setPaletteCustom (value) {
|
||||
setPaletteCustom(value) {
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
||||
|
|
@ -226,21 +243,24 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
async fetchStylesIndex () {
|
||||
async fetchStylesIndex() {
|
||||
try {
|
||||
const value = await getResourcesIndex(
|
||||
'/static/styles/index.json',
|
||||
deserialize
|
||||
deserialize,
|
||||
)
|
||||
window.vuex.commit('setInstanceOption', { name: 'stylesIndex', value })
|
||||
return value
|
||||
} catch (e) {
|
||||
console.error('Could not fetch styles index', e)
|
||||
window.vuex.commit('setInstanceOption', { name: 'stylesIndex', value: { _error: e } })
|
||||
window.vuex.commit('setInstanceOption', {
|
||||
name: 'stylesIndex',
|
||||
value: { _error: e },
|
||||
})
|
||||
return Promise.resolve({})
|
||||
}
|
||||
},
|
||||
setStyle (value) {
|
||||
setStyle(value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV2()
|
||||
this.resetThemeV3Palette()
|
||||
|
|
@ -252,7 +272,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
this.useStylePalette = false
|
||||
})
|
||||
},
|
||||
setStyleCustom (value) {
|
||||
setStyleCustom(value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV2()
|
||||
this.resetThemeV3Palette()
|
||||
|
|
@ -264,18 +284,21 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
this.useStylePalette = false
|
||||
})
|
||||
},
|
||||
async fetchThemesIndex () {
|
||||
async fetchThemesIndex() {
|
||||
try {
|
||||
const value = await getResourcesIndex('/static/styles.json')
|
||||
window.vuex.commit('setInstanceOption', { name: 'themesIndex', value })
|
||||
return value
|
||||
} catch (e) {
|
||||
console.error('Could not fetch themes index', e)
|
||||
window.vuex.commit('setInstanceOption', { name: 'themesIndex', value: { _error: e } })
|
||||
window.vuex.commit('setInstanceOption', {
|
||||
name: 'themesIndex',
|
||||
value: { _error: e },
|
||||
})
|
||||
return Promise.resolve({})
|
||||
}
|
||||
},
|
||||
setTheme (value) {
|
||||
setTheme(value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
|
@ -284,7 +307,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
setThemeCustom (value) {
|
||||
setThemeCustom(value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
|
@ -294,22 +317,29 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
resetThemeV3 () {
|
||||
resetThemeV3() {
|
||||
window.vuex.commit('setOption', { name: 'style', value: null })
|
||||
window.vuex.commit('setOption', { name: 'styleCustomData', value: null })
|
||||
},
|
||||
resetThemeV3Palette () {
|
||||
resetThemeV3Palette() {
|
||||
window.vuex.commit('setOption', { name: 'palette', value: null })
|
||||
window.vuex.commit('setOption', { name: 'paletteCustomData', value: null })
|
||||
window.vuex.commit('setOption', {
|
||||
name: 'paletteCustomData',
|
||||
value: null,
|
||||
})
|
||||
},
|
||||
resetThemeV2 () {
|
||||
resetThemeV2() {
|
||||
window.vuex.commit('setOption', { name: 'theme', value: null })
|
||||
window.vuex.commit('setOption', { name: 'customTheme', value: null })
|
||||
window.vuex.commit('setOption', { name: 'customThemeSource', value: null })
|
||||
window.vuex.commit('setOption', {
|
||||
name: 'customThemeSource',
|
||||
value: null,
|
||||
})
|
||||
},
|
||||
async getThemeData () {
|
||||
async getThemeData() {
|
||||
const getData = async (resource, index, customData, name) => {
|
||||
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
|
||||
const capitalizedResource =
|
||||
resource[0].toUpperCase() + resource.slice(1)
|
||||
const result = {}
|
||||
|
||||
if (customData) {
|
||||
|
|
@ -331,9 +361,13 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
}
|
||||
const newName = Object.keys(index)[0]
|
||||
fetchFunc = index[newName]
|
||||
console.warn(`${capitalizedResource} with id '${this.styleNameUsed}' not found, trying back to '${newName}'`)
|
||||
console.warn(
|
||||
`${capitalizedResource} with id '${this.styleNameUsed}' not found, trying back to '${newName}'`,
|
||||
)
|
||||
if (!fetchFunc) {
|
||||
console.warn(`${capitalizedResource} doesn't have a fallback, defaulting to stock.`)
|
||||
console.warn(
|
||||
`${capitalizedResource} doesn't have a fallback, defaulting to stock.`,
|
||||
)
|
||||
fetchFunc = () => Promise.resolve(null)
|
||||
}
|
||||
}
|
||||
|
|
@ -342,52 +376,52 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
return result
|
||||
}
|
||||
|
||||
const {
|
||||
style: instanceStyleName,
|
||||
palette: instancePaletteName
|
||||
} = window.vuex.state.instance
|
||||
const { style: instanceStyleName, palette: instancePaletteName } =
|
||||
window.vuex.state.instance
|
||||
|
||||
let {
|
||||
theme: instanceThemeV2Name,
|
||||
themesIndex,
|
||||
stylesIndex,
|
||||
palettesIndex
|
||||
palettesIndex,
|
||||
} = window.vuex.state.instance
|
||||
|
||||
const {
|
||||
style: userStyleName,
|
||||
styleCustomData: userStyleCustomData,
|
||||
palette: userPaletteName,
|
||||
paletteCustomData: userPaletteCustomData
|
||||
paletteCustomData: userPaletteCustomData,
|
||||
} = window.vuex.state.config
|
||||
|
||||
let {
|
||||
theme: userThemeV2Name,
|
||||
customTheme: userThemeV2Snapshot,
|
||||
customThemeSource: userThemeV2Source
|
||||
customThemeSource: userThemeV2Source,
|
||||
} = window.vuex.state.config
|
||||
|
||||
let majorVersionUsed
|
||||
|
||||
console.debug(
|
||||
`User V3 palette: ${userPaletteName}, style: ${userStyleName} , custom: ${!!userStyleCustomData}`
|
||||
`User V3 palette: ${userPaletteName}, style: ${userStyleName} , custom: ${!!userStyleCustomData}`,
|
||||
)
|
||||
console.debug(
|
||||
`User V2 name: ${userThemeV2Name}, source: ${!!userThemeV2Source}, snapshot: ${!!userThemeV2Snapshot}`
|
||||
`User V2 name: ${userThemeV2Name}, source: ${!!userThemeV2Source}, snapshot: ${!!userThemeV2Snapshot}`,
|
||||
)
|
||||
|
||||
console.debug(`Instance V3 palette: ${instancePaletteName}, style: ${instanceStyleName}`)
|
||||
console.debug(
|
||||
`Instance V3 palette: ${instancePaletteName}, style: ${instanceStyleName}`,
|
||||
)
|
||||
console.debug('Instance V2 theme: ' + instanceThemeV2Name)
|
||||
|
||||
if (userPaletteName || userPaletteCustomData ||
|
||||
userStyleName || userStyleCustomData ||
|
||||
(
|
||||
// User V2 overrides instance V3
|
||||
(instancePaletteName ||
|
||||
instanceStyleName) &&
|
||||
instanceThemeV2Name == null &&
|
||||
userThemeV2Name == null
|
||||
)
|
||||
if (
|
||||
userPaletteName ||
|
||||
userPaletteCustomData ||
|
||||
userStyleName ||
|
||||
userStyleCustomData ||
|
||||
// User V2 overrides instance V3
|
||||
((instancePaletteName || instanceStyleName) &&
|
||||
instanceThemeV2Name == null &&
|
||||
userThemeV2Name == null)
|
||||
) {
|
||||
// Palette and/or style overrides V2 themes
|
||||
instanceThemeV2Name = null
|
||||
|
|
@ -397,10 +431,10 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
majorVersionUsed = 'v3'
|
||||
} else if (
|
||||
(userThemeV2Name ||
|
||||
userThemeV2Snapshot ||
|
||||
userThemeV2Source ||
|
||||
instanceThemeV2Name)
|
||||
userThemeV2Name ||
|
||||
userThemeV2Snapshot ||
|
||||
userThemeV2Source ||
|
||||
instanceThemeV2Name
|
||||
) {
|
||||
majorVersionUsed = 'v2'
|
||||
} else {
|
||||
|
|
@ -411,16 +445,14 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
if (majorVersionUsed === 'v3') {
|
||||
const result = await Promise.all([
|
||||
this.fetchPalettesIndex(),
|
||||
this.fetchStylesIndex()
|
||||
this.fetchStylesIndex(),
|
||||
])
|
||||
|
||||
palettesIndex = result[0]
|
||||
stylesIndex = result[1]
|
||||
} else {
|
||||
// Promise.all just to be uniform with v3
|
||||
const result = await Promise.all([
|
||||
this.fetchThemesIndex()
|
||||
])
|
||||
const result = await Promise.all([this.fetchThemesIndex()])
|
||||
|
||||
themesIndex = result[0]
|
||||
}
|
||||
|
|
@ -437,25 +469,22 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
'style',
|
||||
stylesIndex,
|
||||
userStyleCustomData,
|
||||
userStyleName || instanceStyleName
|
||||
userStyleName || instanceStyleName,
|
||||
)
|
||||
this.styleNameUsed = style.nameUsed
|
||||
this.styleDataUsed = style.dataUsed
|
||||
|
||||
let firstStylePaletteName = null
|
||||
style
|
||||
.dataUsed
|
||||
?.filter(x => x.component === '@palette')
|
||||
.map(x => {
|
||||
style.dataUsed
|
||||
?.filter((x) => x.component === '@palette')
|
||||
.map((x) => {
|
||||
const cleanDirectives = Object.fromEntries(
|
||||
Object
|
||||
.entries(x.directives)
|
||||
.filter(([k]) => k)
|
||||
Object.entries(x.directives).filter(([k]) => k),
|
||||
)
|
||||
|
||||
return { name: x.variant, ...cleanDirectives }
|
||||
})
|
||||
.forEach(palette => {
|
||||
.forEach((palette) => {
|
||||
const key = 'style.' + palette.name.toLowerCase().replace(/ /g, '_')
|
||||
if (!firstStylePaletteName) firstStylePaletteName = key
|
||||
palettesIndex[key] = () => Promise.resolve(palette)
|
||||
|
|
@ -465,19 +494,26 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
'palette',
|
||||
palettesIndex,
|
||||
userPaletteCustomData,
|
||||
this.useStylePalette ? firstStylePaletteName : (userPaletteName || instancePaletteName)
|
||||
this.useStylePalette
|
||||
? firstStylePaletteName
|
||||
: userPaletteName || instancePaletteName,
|
||||
)
|
||||
|
||||
if (this.useStylePalette) {
|
||||
window.vuex.commit('setOption', { name: 'palette', value: firstStylePaletteName })
|
||||
window.vuex.commit('setOption', {
|
||||
name: 'palette',
|
||||
value: firstStylePaletteName,
|
||||
})
|
||||
}
|
||||
|
||||
this.paletteNameUsed = palette.nameUsed
|
||||
this.paletteDataUsed = palette.dataUsed
|
||||
|
||||
if (this.paletteDataUsed) {
|
||||
this.paletteDataUsed.link = this.paletteDataUsed.link || this.paletteDataUsed.accent
|
||||
this.paletteDataUsed.accent = this.paletteDataUsed.accent || this.paletteDataUsed.link
|
||||
this.paletteDataUsed.link =
|
||||
this.paletteDataUsed.link || this.paletteDataUsed.accent
|
||||
this.paletteDataUsed.accent =
|
||||
this.paletteDataUsed.accent || this.paletteDataUsed.link
|
||||
}
|
||||
if (Array.isArray(this.paletteDataUsed)) {
|
||||
const [
|
||||
|
|
@ -489,7 +525,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
cRed = '#FF0000',
|
||||
cGreen = '#00FF00',
|
||||
cBlue = '#0000FF',
|
||||
cOrange = '#E3FF00'
|
||||
cOrange = '#E3FF00',
|
||||
] = palette.dataUsed
|
||||
this.paletteDataUsed = {
|
||||
name,
|
||||
|
|
@ -501,7 +537,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
cRed,
|
||||
cBlue,
|
||||
cGreen,
|
||||
cOrange
|
||||
cOrange,
|
||||
}
|
||||
}
|
||||
console.debug('Palette data used', palette.dataUsed)
|
||||
|
|
@ -515,23 +551,18 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
'theme',
|
||||
themesIndex,
|
||||
userThemeV2Source || userThemeV2Snapshot,
|
||||
userThemeV2Name || instanceThemeV2Name
|
||||
userThemeV2Name || instanceThemeV2Name,
|
||||
)
|
||||
this.themeNameUsed = theme.nameUsed
|
||||
this.themeDataUsed = theme.dataUsed
|
||||
}
|
||||
},
|
||||
async setThemeApplied () {
|
||||
async setThemeApplied() {
|
||||
this.themeApplied = true
|
||||
},
|
||||
async applyTheme (
|
||||
{ recompile = false } = {}
|
||||
) {
|
||||
const {
|
||||
forceThemeRecompilation,
|
||||
themeDebug,
|
||||
theme3hacks
|
||||
} = window.vuex.state.config
|
||||
async applyTheme({ recompile = false } = {}) {
|
||||
const { forceThemeRecompilation, themeDebug, theme3hacks } =
|
||||
window.vuex.state.config
|
||||
this.themeChangeInProgress = true
|
||||
// If we're not forced to recompile try using
|
||||
// cache (tryLoadCache return true if load successful)
|
||||
|
|
@ -540,7 +571,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
|
||||
await this.getThemeData()
|
||||
|
||||
if (!forceRecompile && !themeDebug && await tryLoadCache()) {
|
||||
if (!forceRecompile && !themeDebug && (await tryLoadCache())) {
|
||||
this.themeChangeInProgress = false
|
||||
return this.setThemeApplied()
|
||||
}
|
||||
|
|
@ -551,11 +582,10 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
if (!this.paletteDataUsed) return null
|
||||
const result = {
|
||||
component: 'Root',
|
||||
directives: {}
|
||||
directives: {},
|
||||
}
|
||||
|
||||
Object
|
||||
.entries(this.paletteDataUsed)
|
||||
Object.entries(this.paletteDataUsed)
|
||||
.filter(([k]) => k !== 'name')
|
||||
.forEach(([k, v]) => {
|
||||
let issRootDirectiveName
|
||||
|
|
@ -574,7 +604,9 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
return result
|
||||
})()
|
||||
|
||||
const theme2ruleset = this.themeDataUsed && convertTheme2To3(normalizeThemeData(this.themeDataUsed))
|
||||
const theme2ruleset =
|
||||
this.themeDataUsed &&
|
||||
convertTheme2To3(normalizeThemeData(this.themeDataUsed))
|
||||
const hacks = []
|
||||
|
||||
Object.entries(theme3hacks).forEach(([key, value]) => {
|
||||
|
|
@ -587,32 +619,32 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
hacks.push({
|
||||
component: 'Root',
|
||||
directives: {
|
||||
'--font': 'generic | ' + font.family
|
||||
}
|
||||
'--font': 'generic | ' + font.family,
|
||||
},
|
||||
})
|
||||
break
|
||||
case 'input':
|
||||
hacks.push({
|
||||
component: 'Input',
|
||||
directives: {
|
||||
'--font': 'generic | ' + font.family
|
||||
}
|
||||
'--font': 'generic | ' + font.family,
|
||||
},
|
||||
})
|
||||
break
|
||||
case 'post':
|
||||
hacks.push({
|
||||
component: 'RichContent',
|
||||
directives: {
|
||||
'--font': 'generic | ' + font.family
|
||||
}
|
||||
'--font': 'generic | ' + font.family,
|
||||
},
|
||||
})
|
||||
break
|
||||
case 'monospace':
|
||||
hacks.push({
|
||||
component: 'Root',
|
||||
directives: {
|
||||
'--monoFont': 'generic | ' + font.family
|
||||
}
|
||||
'--monoFont': 'generic | ' + font.family,
|
||||
},
|
||||
})
|
||||
break
|
||||
}
|
||||
|
|
@ -623,7 +655,7 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
if (value !== 'none') {
|
||||
const newRule = {
|
||||
component: 'Underlay',
|
||||
directives: {}
|
||||
directives: {},
|
||||
}
|
||||
if (value === 'opaque') {
|
||||
newRule.directives.opacity = 1
|
||||
|
|
@ -643,8 +675,8 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
theme2ruleset,
|
||||
this.styleDataUsed,
|
||||
paletteIss,
|
||||
hacks
|
||||
].filter(x => x)
|
||||
hacks,
|
||||
].filter((x) => x)
|
||||
|
||||
return applyTheme(
|
||||
rulesetArray.flat(),
|
||||
|
|
@ -652,13 +684,13 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
() => {
|
||||
this.themeChangeInProgress = false
|
||||
},
|
||||
themeDebug
|
||||
themeDebug,
|
||||
)
|
||||
} catch (e) {
|
||||
window.splashError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const normalizeThemeData = (input) => {
|
||||
|
|
@ -669,15 +701,15 @@ export const normalizeThemeData = (input) => {
|
|||
return generatePreset(input).theme
|
||||
} else if (
|
||||
Object.hasOwn(input, '_pleroma_theme_version') ||
|
||||
Object.hasOwn(input, 'source') ||
|
||||
Object.hasOwn(input, 'theme')
|
||||
Object.hasOwn(input, 'source') ||
|
||||
Object.hasOwn(input, 'theme')
|
||||
) {
|
||||
// We got passed a full theme file
|
||||
themeData = input.theme
|
||||
themeSource = input.source
|
||||
} else if (
|
||||
Object.hasOwn(input, 'themeEngineVersion') ||
|
||||
Object.hasOwn(input, 'colors')
|
||||
Object.hasOwn(input, 'colors')
|
||||
) {
|
||||
// We got passed a source/snapshot
|
||||
themeData = input
|
||||
|
|
|
|||
|
|
@ -5,36 +5,39 @@ import { remove, find } from 'lodash'
|
|||
export const useListsStore = defineStore('lists', {
|
||||
state: () => ({
|
||||
allLists: [],
|
||||
allListsObject: {}
|
||||
allListsObject: {},
|
||||
}),
|
||||
getters: {
|
||||
findListTitle () {
|
||||
findListTitle() {
|
||||
return (id) => {
|
||||
if (!this.allListsObject[id]) return
|
||||
return this.allListsObject[id].title
|
||||
}
|
||||
},
|
||||
findListAccounts () {
|
||||
findListAccounts() {
|
||||
return (id) => [...this.allListsObject[id].accountIds]
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setLists (value) {
|
||||
setLists(value) {
|
||||
this.allLists = value
|
||||
},
|
||||
createList ({ title }) {
|
||||
return window.vuex.state.api.backendInteractor.createList({ title })
|
||||
createList({ title }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.createList({ title })
|
||||
.then((list) => {
|
||||
this.setList({ listId: list.id, title })
|
||||
return list
|
||||
})
|
||||
},
|
||||
fetchList ({ listId }) {
|
||||
return window.vuex.state.api.backendInteractor.getList({ listId })
|
||||
fetchList({ listId }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.getList({ listId })
|
||||
.then((list) => this.setList({ listId: list.id, title: list.title }))
|
||||
},
|
||||
fetchListAccounts ({ listId }) {
|
||||
return window.vuex.state.api.backendInteractor.getListAccounts({ listId })
|
||||
fetchListAccounts({ listId }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.getListAccounts({ listId })
|
||||
.then((accountIds) => {
|
||||
if (!this.allListsObject[listId]) {
|
||||
this.allListsObject[listId] = { accountIds: [] }
|
||||
|
|
@ -42,7 +45,7 @@ export const useListsStore = defineStore('lists', {
|
|||
this.allListsObject[listId].accountIds = accountIds
|
||||
})
|
||||
},
|
||||
setList ({ listId, title }) {
|
||||
setList({ listId, title }) {
|
||||
window.vuex.state.api.backendInteractor.updateList({ listId, title })
|
||||
|
||||
if (!this.allListsObject[listId]) {
|
||||
|
|
@ -57,25 +60,29 @@ export const useListsStore = defineStore('lists', {
|
|||
entry.title = title
|
||||
}
|
||||
},
|
||||
setListAccounts ({ listId, accountIds }) {
|
||||
setListAccounts({ listId, accountIds }) {
|
||||
const saved = this.allListsObject[listId]?.accountIds || []
|
||||
const added = accountIds.filter(id => !saved.includes(id))
|
||||
const removed = saved.filter(id => !accountIds.includes(id))
|
||||
const added = accountIds.filter((id) => !saved.includes(id))
|
||||
const removed = saved.filter((id) => !accountIds.includes(id))
|
||||
if (!this.allListsObject[listId]) {
|
||||
this.allListsObject[listId] = { accountIds: [] }
|
||||
}
|
||||
this.allListsObject[listId].accountIds = accountIds
|
||||
if (added.length > 0) {
|
||||
window.vuex.state.api.backendInteractor.addAccountsToList({ listId, accountIds: added })
|
||||
window.vuex.state.api.backendInteractor.addAccountsToList({
|
||||
listId,
|
||||
accountIds: added,
|
||||
})
|
||||
}
|
||||
if (removed.length > 0) {
|
||||
window.vuex.state.api.backendInteractor.removeAccountsFromList({ listId, accountIds: removed })
|
||||
window.vuex.state.api.backendInteractor.removeAccountsFromList({
|
||||
listId,
|
||||
accountIds: removed,
|
||||
})
|
||||
}
|
||||
},
|
||||
addListAccount ({ listId, accountId }) {
|
||||
return window.vuex.state
|
||||
.api
|
||||
.backendInteractor
|
||||
addListAccount({ listId, accountId }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.addAccountsToList({ listId, accountIds: [accountId] })
|
||||
.then((result) => {
|
||||
if (!this.allListsObject[listId]) {
|
||||
|
|
@ -85,10 +92,8 @@ export const useListsStore = defineStore('lists', {
|
|||
return result
|
||||
})
|
||||
},
|
||||
removeListAccount ({ listId, accountId }) {
|
||||
return window.vuex.state
|
||||
.api
|
||||
.backendInteractor
|
||||
removeListAccount({ listId, accountId }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.removeAccountsFromList({ listId, accountIds: [accountId] })
|
||||
.then((result) => {
|
||||
if (!this.allListsObject[listId]) {
|
||||
|
|
@ -102,11 +107,11 @@ export const useListsStore = defineStore('lists', {
|
|||
return result
|
||||
})
|
||||
},
|
||||
deleteList ({ listId }) {
|
||||
deleteList({ listId }) {
|
||||
window.vuex.state.api.backendInteractor.deleteList({ listId })
|
||||
|
||||
delete this.allListsObject[listId]
|
||||
remove(this.allLists, list => list.id === listId)
|
||||
}
|
||||
}
|
||||
remove(this.allLists, (list) => list.id === listId)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,24 +7,24 @@ export const useMediaViewerStore = defineStore('mediaViewer', {
|
|||
state: () => ({
|
||||
media: [],
|
||||
currentIndex: 0,
|
||||
activated: false
|
||||
activated: false,
|
||||
}),
|
||||
actions: {
|
||||
setMedia (attachments) {
|
||||
const media = attachments.filter(attachment => {
|
||||
setMedia(attachments) {
|
||||
const media = attachments.filter((attachment) => {
|
||||
const type = fileTypeService.fileType(attachment.mimetype)
|
||||
return supportedTypes.has(type)
|
||||
})
|
||||
|
||||
this.media = media
|
||||
},
|
||||
setCurrentMedia (current) {
|
||||
setCurrentMedia(current) {
|
||||
const index = this.media.indexOf(current)
|
||||
this.activated = true
|
||||
this.currentIndex = index
|
||||
},
|
||||
closeMediaViewer () {
|
||||
closeMediaViewer() {
|
||||
this.activated = false
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { createApp, getClientToken, verifyAppToken } from 'src/services/new_api/oauth.js'
|
||||
import {
|
||||
createApp,
|
||||
getClientToken,
|
||||
verifyAppToken,
|
||||
} from 'src/services/new_api/oauth.js'
|
||||
|
||||
// status codes about verifyAppToken (GET /api/v1/apps/verify_credentials)
|
||||
const isAppTokenRejected = error => (
|
||||
const isAppTokenRejected = (error) =>
|
||||
// Pleroma API docs say it returns 422 when unauthorized
|
||||
error.statusCode === 422 ||
|
||||
// but it actually returns 400 (as of 2.9.0)
|
||||
|
|
@ -10,16 +14,14 @@ const isAppTokenRejected = error => (
|
|||
error.statusCode === 400 ||
|
||||
// and Mastodon docs say it returns 401
|
||||
error.statusCode === 401
|
||||
)
|
||||
|
||||
// status codes about getAppToken (GET /oauth/token)
|
||||
const isClientDataRejected = error => (
|
||||
const isClientDataRejected = (error) =>
|
||||
// Mastodon docs say it returns 401
|
||||
error.statusCode === 401 ||
|
||||
// but Pleroma actually returns 400 (as of 2.9.0)
|
||||
// NOTE: don't try to match against the error message, it is translatable
|
||||
error.statusCode === 400
|
||||
)
|
||||
|
||||
export const useOAuthStore = defineStore('oauth', {
|
||||
state: () => ({
|
||||
|
|
@ -33,31 +35,31 @@ export const useOAuthStore = defineStore('oauth', {
|
|||
/* User token is authentication for app with user, this is for every calls
|
||||
* that need authorized user to be successful (i.e. posting, liking etc)
|
||||
*/
|
||||
userToken: false
|
||||
userToken: false,
|
||||
}),
|
||||
getters: {
|
||||
getToken () {
|
||||
getToken() {
|
||||
return this.userToken || this.appToken
|
||||
},
|
||||
getUserToken () {
|
||||
getUserToken() {
|
||||
return this.userToken
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setClientData ({ clientId, clientSecret }) {
|
||||
setClientData({ clientId, clientSecret }) {
|
||||
this.clientId = clientId
|
||||
this.clientSecret = clientSecret
|
||||
},
|
||||
setAppToken (token) {
|
||||
setAppToken(token) {
|
||||
this.appToken = token
|
||||
},
|
||||
setToken (token) {
|
||||
setToken(token) {
|
||||
this.userToken = token
|
||||
},
|
||||
clearToken () {
|
||||
clearToken() {
|
||||
this.userToken = false
|
||||
},
|
||||
async createApp () {
|
||||
async createApp() {
|
||||
const { state } = window.vuex
|
||||
const instance = state.instance.server
|
||||
const app = await createApp(instance)
|
||||
|
|
@ -67,36 +69,36 @@ export const useOAuthStore = defineStore('oauth', {
|
|||
/// Use this if you want to get the client id and secret but are not interested
|
||||
/// in whether they are valid.
|
||||
/// @return {{ clientId: string, clientSecret: string }} An object representing the app
|
||||
async ensureApp () {
|
||||
async ensureApp() {
|
||||
if (this.clientId && this.clientSecret) {
|
||||
return {
|
||||
clientId: this.clientId,
|
||||
clientSecret: this.clientSecret
|
||||
clientSecret: this.clientSecret,
|
||||
}
|
||||
} else {
|
||||
return this.createApp()
|
||||
}
|
||||
},
|
||||
async getAppToken () {
|
||||
async getAppToken() {
|
||||
const { state } = window.vuex
|
||||
const instance = state.instance.server
|
||||
const res = await getClientToken({
|
||||
clientId: this.clientId,
|
||||
clientSecret: this.clientSecret,
|
||||
instance
|
||||
instance,
|
||||
})
|
||||
this.setAppToken(res.access_token)
|
||||
return res.access_token
|
||||
},
|
||||
/// Use this if you want to ensure the app is still valid to use.
|
||||
/// @return {string} The access token to the app (not attached to any user)
|
||||
async ensureAppToken () {
|
||||
async ensureAppToken() {
|
||||
const { state } = window.vuex
|
||||
if (this.appToken) {
|
||||
try {
|
||||
await verifyAppToken({
|
||||
instance: state.instance.server,
|
||||
appToken: this.appToken
|
||||
appToken: this.appToken,
|
||||
})
|
||||
return this.appToken
|
||||
} catch (e) {
|
||||
|
|
@ -133,17 +135,17 @@ export const useOAuthStore = defineStore('oauth', {
|
|||
// and re-create our app
|
||||
this.setClientData({
|
||||
clientId: false,
|
||||
clientSecret: false
|
||||
clientSecret: false,
|
||||
})
|
||||
await this.createApp()
|
||||
// try once again to get the token
|
||||
return await this.getAppToken()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
afterLoad (state) {
|
||||
afterLoad(state) {
|
||||
// state.token is userToken with older name, coming from persistent state
|
||||
if (state.token && !state.userToken) {
|
||||
state.userToken = state.token
|
||||
|
|
@ -152,6 +154,6 @@ export const useOAuthStore = defineStore('oauth', {
|
|||
delete state.token
|
||||
}
|
||||
return state
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,23 +2,27 @@ import { defineStore } from 'pinia'
|
|||
|
||||
export const useOAuthTokensStore = defineStore('oauthTokens', {
|
||||
state: () => ({
|
||||
tokens: []
|
||||
tokens: [],
|
||||
}),
|
||||
actions: {
|
||||
fetchTokens () {
|
||||
window.vuex.state.api.backendInteractor.fetchOAuthTokens().then((tokens) => {
|
||||
this.swapTokens(tokens)
|
||||
})
|
||||
fetchTokens() {
|
||||
window.vuex.state.api.backendInteractor
|
||||
.fetchOAuthTokens()
|
||||
.then((tokens) => {
|
||||
this.swapTokens(tokens)
|
||||
})
|
||||
},
|
||||
revokeToken (id) {
|
||||
window.vuex.state.api.backendInteractor.revokeOAuthToken({ id }).then((response) => {
|
||||
if (response.status === 201) {
|
||||
this.swapTokens(this.tokens.filter(token => token.id !== id))
|
||||
}
|
||||
})
|
||||
revokeToken(id) {
|
||||
window.vuex.state.api.backendInteractor
|
||||
.revokeOAuthToken({ id })
|
||||
.then((response) => {
|
||||
if (response.status === 201) {
|
||||
this.swapTokens(this.tokens.filter((token) => token.id !== id))
|
||||
}
|
||||
})
|
||||
},
|
||||
swapTokens (tokens) {
|
||||
swapTokens(tokens) {
|
||||
this.tokens = tokens
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ export const usePollsStore = defineStore('polls', {
|
|||
state: () => ({
|
||||
// Contains key = id, value = number of trackers for this poll
|
||||
trackedPolls: {},
|
||||
pollsObject: {}
|
||||
pollsObject: {},
|
||||
}),
|
||||
actions: {
|
||||
mergeOrAddPoll (poll) {
|
||||
mergeOrAddPoll(poll) {
|
||||
const existingPoll = this.pollsObject[poll.id]
|
||||
// Make expired-state change trigger re-renders properly
|
||||
poll.expired = Date.now() > Date.parse(poll.expires_at)
|
||||
|
|
@ -18,17 +18,19 @@ export const usePollsStore = defineStore('polls', {
|
|||
this.pollsObject[poll.id] = poll
|
||||
}
|
||||
},
|
||||
updateTrackedPoll (pollId) {
|
||||
window.vuex.state.api.backendInteractor.fetchPoll({ pollId }).then(poll => {
|
||||
setTimeout(() => {
|
||||
if (this.trackedPolls[pollId]) {
|
||||
this.updateTrackedPoll(pollId)
|
||||
}
|
||||
}, 30 * 1000)
|
||||
this.mergeOrAddPoll(poll)
|
||||
})
|
||||
updateTrackedPoll(pollId) {
|
||||
window.vuex.state.api.backendInteractor
|
||||
.fetchPoll({ pollId })
|
||||
.then((poll) => {
|
||||
setTimeout(() => {
|
||||
if (this.trackedPolls[pollId]) {
|
||||
this.updateTrackedPoll(pollId)
|
||||
}
|
||||
}, 30 * 1000)
|
||||
this.mergeOrAddPoll(poll)
|
||||
})
|
||||
},
|
||||
trackPoll (pollId) {
|
||||
trackPoll(pollId) {
|
||||
if (!this.trackedPolls[pollId]) {
|
||||
setTimeout(() => this.updateTrackedPoll(pollId), 30 * 1000)
|
||||
}
|
||||
|
|
@ -39,7 +41,7 @@ export const usePollsStore = defineStore('polls', {
|
|||
this.trackedPolls[pollId] = 1
|
||||
}
|
||||
},
|
||||
untrackPoll (pollId) {
|
||||
untrackPoll(pollId) {
|
||||
const currentValue = this.trackedPolls[pollId]
|
||||
if (currentValue) {
|
||||
this.trackedPolls[pollId] = currentValue - 1
|
||||
|
|
@ -47,11 +49,13 @@ export const usePollsStore = defineStore('polls', {
|
|||
this.trackedPolls[pollId] = 0
|
||||
}
|
||||
},
|
||||
votePoll ({ pollId, choices }) {
|
||||
return window.vuex.state.api.backendInteractor.vote({ pollId, choices }).then(poll => {
|
||||
this.mergeOrAddPoll(poll)
|
||||
return poll
|
||||
})
|
||||
}
|
||||
}
|
||||
votePoll({ pollId, choices }) {
|
||||
return window.vuex.state.api.backendInteractor
|
||||
.vote({ pollId, choices })
|
||||
.then((poll) => {
|
||||
this.mergeOrAddPoll(poll)
|
||||
return poll
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ import { defineStore } from 'pinia'
|
|||
export const usePostStatusStore = defineStore('postStatus', {
|
||||
state: () => ({
|
||||
params: null,
|
||||
modalActivated: false
|
||||
modalActivated: false,
|
||||
}),
|
||||
actions: {
|
||||
openPostStatusModal (params) {
|
||||
openPostStatusModal(params) {
|
||||
this.params = params
|
||||
this.modalActivated = true
|
||||
},
|
||||
closePostStatusModal () {
|
||||
closePostStatusModal() {
|
||||
this.modalActivated = false
|
||||
},
|
||||
resetPostStatusModal () {
|
||||
resetPostStatusModal() {
|
||||
this.params = null
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,18 +9,22 @@ export const useReportsStore = defineStore('reports', {
|
|||
userId: null,
|
||||
statuses: [],
|
||||
preTickedIds: [],
|
||||
activated: false
|
||||
activated: false,
|
||||
},
|
||||
reports: {}
|
||||
reports: {},
|
||||
}),
|
||||
actions: {
|
||||
openUserReportingModal ({ userId, statusIds = [] }) {
|
||||
const preTickedStatuses = statusIds.map(id => window.vuex.state.statuses.allStatusesObject[id])
|
||||
openUserReportingModal({ userId, statusIds = [] }) {
|
||||
const preTickedStatuses = statusIds.map(
|
||||
(id) => window.vuex.state.statuses.allStatusesObject[id],
|
||||
)
|
||||
const preTickedIds = statusIds
|
||||
const statuses = preTickedStatuses.concat(
|
||||
filter(window.vuex.state.statuses.allStatuses,
|
||||
status => status.user.id === userId && !preTickedIds.includes(status.id)
|
||||
)
|
||||
filter(
|
||||
window.vuex.state.statuses.allStatuses,
|
||||
(status) =>
|
||||
status.user.id === userId && !preTickedIds.includes(status.id),
|
||||
),
|
||||
)
|
||||
|
||||
this.reportModal.userId = userId
|
||||
|
|
@ -28,25 +32,27 @@ export const useReportsStore = defineStore('reports', {
|
|||
this.reportModal.preTickedIds = preTickedIds
|
||||
this.reportModal.activated = true
|
||||
},
|
||||
closeUserReportingModal () {
|
||||
closeUserReportingModal() {
|
||||
this.reportModal.activated = false
|
||||
},
|
||||
setReportState ({ id, state }) {
|
||||
setReportState({ id, state }) {
|
||||
const oldState = this.reports[id].state
|
||||
this.reports[id].state = state
|
||||
window.vuex.state.api.backendInteractor.setReportState({ id, state }).catch(e => {
|
||||
console.error('Failed to set report state', e)
|
||||
useInterfaceStore().pushGlobalNotice({
|
||||
level: 'error',
|
||||
messageKey: 'general.generic_error_message',
|
||||
messageArgs: [e.message],
|
||||
timeout: 5000
|
||||
window.vuex.state.api.backendInteractor
|
||||
.setReportState({ id, state })
|
||||
.catch((e) => {
|
||||
console.error('Failed to set report state', e)
|
||||
useInterfaceStore().pushGlobalNotice({
|
||||
level: 'error',
|
||||
messageKey: 'general.generic_error_message',
|
||||
messageArgs: [e.message],
|
||||
timeout: 5000,
|
||||
})
|
||||
this.reports[id].state = oldState
|
||||
})
|
||||
this.reports[id].state = oldState
|
||||
})
|
||||
},
|
||||
addReport (report) {
|
||||
addReport(report) {
|
||||
this.reports[report.id] = report
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
findLastIndex,
|
||||
takeRight,
|
||||
uniqWith,
|
||||
merge as _merge
|
||||
merge as _merge,
|
||||
} from 'lodash'
|
||||
import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js'
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ export const defaultState = {
|
|||
flagStorage: {
|
||||
updateCounter: 0, // Counter for most recent update notification seen
|
||||
configMigration: 0, // Counter for config -> server-side migrations
|
||||
reset: 0 // special flag that can be used to force-reset all flags, debug purposes only
|
||||
reset: 0, // special flag that can be used to force-reset all flags, debug purposes only
|
||||
// special reset codes:
|
||||
// 1000: trim keys to those known by currently running FE
|
||||
// 1001: same as above + reset everything to 0
|
||||
|
|
@ -39,22 +39,22 @@ export const defaultState = {
|
|||
simple: {
|
||||
dontShowUpdateNotifs: false,
|
||||
collapseNav: false,
|
||||
muteFilters: {}
|
||||
muteFilters: {},
|
||||
},
|
||||
collections: {
|
||||
pinnedStatusActions: ['reply', 'retweet', 'favorite', 'emoji'],
|
||||
pinnedNavItems: ['home', 'dms', 'chats']
|
||||
}
|
||||
pinnedNavItems: ['home', 'dms', 'chats'],
|
||||
},
|
||||
},
|
||||
// raw data
|
||||
raw: null,
|
||||
// local cache
|
||||
cache: null
|
||||
cache: null,
|
||||
}
|
||||
|
||||
export const newUserFlags = {
|
||||
...defaultState.flagStorage,
|
||||
updateCounter: CURRENT_UPDATE_COUNTER // new users don't need to see update notification
|
||||
updateCounter: CURRENT_UPDATE_COUNTER, // new users don't need to see update notification
|
||||
}
|
||||
|
||||
export const _moveItemInArray = (array, value, movement) => {
|
||||
|
|
@ -72,7 +72,7 @@ const _wrapData = (data, userName) => ({
|
|||
...data,
|
||||
_user: userName,
|
||||
_timestamp: Date.now(),
|
||||
_version: VERSION
|
||||
_version: VERSION,
|
||||
})
|
||||
|
||||
const _checkValidity = (data) => data._timestamp > 0 && data._version > 0
|
||||
|
|
@ -80,7 +80,7 @@ const _checkValidity = (data) => data._timestamp > 0 && data._version > 0
|
|||
const _verifyPrefs = (state) => {
|
||||
state.prefsStorage = state.prefsStorage || {
|
||||
simple: {},
|
||||
collections: {}
|
||||
collections: {},
|
||||
}
|
||||
|
||||
// Simple
|
||||
|
|
@ -95,7 +95,11 @@ const _verifyPrefs = (state) => {
|
|||
Object.entries(defaultState.prefsStorage.collections).forEach(([k, v]) => {
|
||||
if (Array.isArray(v)) return
|
||||
console.warn(`Preference collections.${k} as invalid type, reinitializing`)
|
||||
set(state.prefsStorage.collections, k, defaultState.prefsStorage.collections[k])
|
||||
set(
|
||||
state.prefsStorage.collections,
|
||||
k,
|
||||
defaultState.prefsStorage.collections[k],
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -105,21 +109,32 @@ export const _getRecentData = (cache, live, isTest) => {
|
|||
const liveValid = _checkValidity(live || {})
|
||||
if (!liveValid && cacheValid) {
|
||||
result.needUpload = true
|
||||
console.debug('Nothing valid stored on server, assuming cache to be source of truth')
|
||||
console.debug(
|
||||
'Nothing valid stored on server, assuming cache to be source of truth',
|
||||
)
|
||||
result.recent = cache
|
||||
result.stale = live
|
||||
} else if (!cacheValid && liveValid) {
|
||||
console.debug('Valid storage on server found, no local cache found, using live as source of truth')
|
||||
console.debug(
|
||||
'Valid storage on server found, no local cache found, using live as source of truth',
|
||||
)
|
||||
result.recent = live
|
||||
result.stale = cache
|
||||
} else if (cacheValid && liveValid) {
|
||||
console.debug('Both sources have valid data, figuring things out...')
|
||||
if (live._timestamp === cache._timestamp && live._version === cache._version) {
|
||||
console.debug('Same version/timestamp on both source, source of truth irrelevant')
|
||||
if (
|
||||
live._timestamp === cache._timestamp &&
|
||||
live._version === cache._version
|
||||
) {
|
||||
console.debug(
|
||||
'Same version/timestamp on both source, source of truth irrelevant',
|
||||
)
|
||||
result.recent = cache
|
||||
result.stale = live
|
||||
} else {
|
||||
console.debug('Different timestamp, figuring out which one is more recent')
|
||||
console.debug(
|
||||
'Different timestamp, figuring out which one is more recent',
|
||||
)
|
||||
if (live._timestamp < cache._timestamp) {
|
||||
result.recent = cache
|
||||
result.stale = live
|
||||
|
|
@ -139,49 +154,64 @@ export const _getRecentData = (cache, live, isTest) => {
|
|||
_timestamp: a._timestamp ?? b._timestamp,
|
||||
needUpload: b.needUpload ?? a.needUpload,
|
||||
prefsStorage: _merge(a.prefsStorage, b.prefsStorage),
|
||||
flagStorage: _merge(a.flagStorage, b.flagStorage)
|
||||
flagStorage: _merge(a.flagStorage, b.flagStorage),
|
||||
})
|
||||
result.recent = isTest ? result.recent : (result.recent && merge(defaultState, result.recent))
|
||||
result.stale = isTest ? result.stale : (result.stale && merge(defaultState, result.stale))
|
||||
result.recent = isTest
|
||||
? result.recent
|
||||
: result.recent && merge(defaultState, result.recent)
|
||||
result.stale = isTest
|
||||
? result.stale
|
||||
: result.stale && merge(defaultState, result.stale)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export const _getAllFlags = (recent, stale) => {
|
||||
return Array.from(new Set([
|
||||
...Object.keys(toRaw((recent || {}).flagStorage || {})),
|
||||
...Object.keys(toRaw((stale || {}).flagStorage || {}))
|
||||
]))
|
||||
return Array.from(
|
||||
new Set([
|
||||
...Object.keys(toRaw((recent || {}).flagStorage || {})),
|
||||
...Object.keys(toRaw((stale || {}).flagStorage || {})),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
export const _mergeFlags = (recent, stale, allFlagKeys) => {
|
||||
if (!stale.flagStorage) return recent.flagStorage
|
||||
if (!recent.flagStorage) return stale.flagStorage
|
||||
return Object.fromEntries(allFlagKeys.map(flag => {
|
||||
const recentFlag = recent.flagStorage[flag]
|
||||
const staleFlag = stale.flagStorage[flag]
|
||||
// use flag that is of higher value
|
||||
return [flag, Number((recentFlag > staleFlag ? recentFlag : staleFlag) || 0)]
|
||||
}))
|
||||
return Object.fromEntries(
|
||||
allFlagKeys.map((flag) => {
|
||||
const recentFlag = recent.flagStorage[flag]
|
||||
const staleFlag = stale.flagStorage[flag]
|
||||
// use flag that is of higher value
|
||||
return [
|
||||
flag,
|
||||
Number((recentFlag > staleFlag ? recentFlag : staleFlag) || 0),
|
||||
]
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const _mergeJournal = (...journals) => {
|
||||
// Ignore invalid journal entries
|
||||
const allJournals = flatten(
|
||||
journals.map(j => Array.isArray(j) ? j : [])
|
||||
).filter(entry =>
|
||||
Object.hasOwn(entry, 'path') &&
|
||||
Object.hasOwn(entry, 'operation') &&
|
||||
Object.hasOwn(entry, 'args') &&
|
||||
Object.hasOwn(entry, 'timestamp')
|
||||
journals.map((j) => (Array.isArray(j) ? j : [])),
|
||||
).filter(
|
||||
(entry) =>
|
||||
Object.hasOwn(entry, 'path') &&
|
||||
Object.hasOwn(entry, 'operation') &&
|
||||
Object.hasOwn(entry, 'args') &&
|
||||
Object.hasOwn(entry, 'timestamp'),
|
||||
)
|
||||
const grouped = groupBy(allJournals, 'path')
|
||||
const trimmedGrouped = Object.entries(grouped).map(([path, journal]) => {
|
||||
// side effect
|
||||
journal.sort((a, b) => a.timestamp > b.timestamp ? 1 : -1)
|
||||
journal.sort((a, b) => (a.timestamp > b.timestamp ? 1 : -1))
|
||||
|
||||
if (path.startsWith('collections')) {
|
||||
const lastRemoveIndex = findLastIndex(journal, ({ operation }) => operation === 'removeFromCollection')
|
||||
const lastRemoveIndex = findLastIndex(
|
||||
journal,
|
||||
({ operation }) => operation === 'removeFromCollection',
|
||||
)
|
||||
// everything before last remove is unimportant
|
||||
let remainder
|
||||
if (lastRemoveIndex > 0) {
|
||||
|
|
@ -191,8 +221,12 @@ const _mergeJournal = (...journals) => {
|
|||
remainder = journal
|
||||
}
|
||||
return uniqWith(remainder, (a, b) => {
|
||||
if (a.path !== b.path) { return false }
|
||||
if (a.operation !== b.operation) { return false }
|
||||
if (a.path !== b.path) {
|
||||
return false
|
||||
}
|
||||
if (a.operation !== b.operation) {
|
||||
return false
|
||||
}
|
||||
if (a.operation === 'addToCollection') {
|
||||
return a.args[0] === b.args[0]
|
||||
}
|
||||
|
|
@ -205,8 +239,9 @@ const _mergeJournal = (...journals) => {
|
|||
return journal
|
||||
}
|
||||
})
|
||||
return flatten(trimmedGrouped)
|
||||
.sort((a, b) => a.timestamp > b.timestamp ? 1 : -1)
|
||||
return flatten(trimmedGrouped).sort((a, b) =>
|
||||
a.timestamp > b.timestamp ? 1 : -1,
|
||||
)
|
||||
}
|
||||
|
||||
export const _mergePrefs = (recent, stale) => {
|
||||
|
|
@ -228,29 +263,45 @@ export const _mergePrefs = (recent, stale) => {
|
|||
const totalJournal = _mergeJournal(staleJournal, recentJournal)
|
||||
totalJournal.forEach(({ path, operation, args }) => {
|
||||
if (path.startsWith('_')) {
|
||||
throw new Error(`journal contains entry to edit internal (starts with _) field '${path}', something is incorrect here, ignoring.`)
|
||||
throw new Error(
|
||||
`journal contains entry to edit internal (starts with _) field '${path}', something is incorrect here, ignoring.`,
|
||||
)
|
||||
}
|
||||
switch (operation) {
|
||||
case 'set':
|
||||
if (path.startsWith('collections') || path.startsWith('objectCollections')) {
|
||||
if (
|
||||
path.startsWith('collections') ||
|
||||
path.startsWith('objectCollections')
|
||||
) {
|
||||
throw new Error('Illegal operation "set" on a collection')
|
||||
}
|
||||
if (path.split(/\./g).length <= 1) {
|
||||
throw new Error(`Calling set on depth <= 1 (path: ${path}) is not allowed`)
|
||||
throw new Error(
|
||||
`Calling set on depth <= 1 (path: ${path}) is not allowed`,
|
||||
)
|
||||
}
|
||||
set(resultOutput, path, args[0])
|
||||
break
|
||||
case 'unset':
|
||||
if (path.startsWith('collections') || path.startsWith('objectCollections')) {
|
||||
if (
|
||||
path.startsWith('collections') ||
|
||||
path.startsWith('objectCollections')
|
||||
) {
|
||||
throw new Error('Illegal operation "unset" on a collection')
|
||||
}
|
||||
if (path.split(/\./g).length <= 2) {
|
||||
throw new Error(`Calling unset on depth <= 2 (path: ${path}) is not allowed`)
|
||||
throw new Error(
|
||||
`Calling unset on depth <= 2 (path: ${path}) is not allowed`,
|
||||
)
|
||||
}
|
||||
unset(resultOutput, path)
|
||||
break
|
||||
case 'addToCollection':
|
||||
set(resultOutput, path, Array.from(new Set(get(resultOutput, path)).add(args[0])))
|
||||
set(
|
||||
resultOutput,
|
||||
path,
|
||||
Array.from(new Set(get(resultOutput, path)).add(args[0])),
|
||||
)
|
||||
break
|
||||
case 'removeFromCollection': {
|
||||
const newSet = new Set(get(resultOutput, path))
|
||||
|
|
@ -260,27 +311,39 @@ export const _mergePrefs = (recent, stale) => {
|
|||
}
|
||||
case 'reorderCollection': {
|
||||
const [value, movement] = args
|
||||
set(resultOutput, path, _moveItemInArray(get(resultOutput, path), value, movement))
|
||||
set(
|
||||
resultOutput,
|
||||
path,
|
||||
_moveItemInArray(get(resultOutput, path), value, movement),
|
||||
)
|
||||
break
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown journal operation: '${operation}', did we forget to run reverse migrations beforehand?`)
|
||||
throw new Error(
|
||||
`Unknown journal operation: '${operation}', did we forget to run reverse migrations beforehand?`,
|
||||
)
|
||||
}
|
||||
})
|
||||
return { ...resultOutput, _journal: totalJournal }
|
||||
}
|
||||
|
||||
export const _resetFlags = (totalFlags, knownKeys = defaultState.flagStorage) => {
|
||||
export const _resetFlags = (
|
||||
totalFlags,
|
||||
knownKeys = defaultState.flagStorage,
|
||||
) => {
|
||||
let result = { ...totalFlags }
|
||||
const allFlagKeys = Object.keys(totalFlags)
|
||||
// flag reset functionality
|
||||
if (totalFlags.reset >= COMMAND_TRIM_FLAGS && totalFlags.reset <= COMMAND_TRIM_FLAGS_AND_RESET) {
|
||||
if (
|
||||
totalFlags.reset >= COMMAND_TRIM_FLAGS &&
|
||||
totalFlags.reset <= COMMAND_TRIM_FLAGS_AND_RESET
|
||||
) {
|
||||
console.debug('Received command to trim the flags')
|
||||
const knownKeysSet = new Set(Object.keys(knownKeys))
|
||||
|
||||
// Trim
|
||||
result = {}
|
||||
allFlagKeys.forEach(flag => {
|
||||
allFlagKeys.forEach((flag) => {
|
||||
if (knownKeysSet.has(flag)) {
|
||||
result[flag] = totalFlags[flag]
|
||||
}
|
||||
|
|
@ -290,11 +353,15 @@ export const _resetFlags = (totalFlags, knownKeys = defaultState.flagStorage) =>
|
|||
if (totalFlags.reset === COMMAND_TRIM_FLAGS_AND_RESET) {
|
||||
// 1001 - and reset everything to 0
|
||||
console.debug('Received command to reset the flags')
|
||||
Object.keys(knownKeys).forEach(flag => { result[flag] = 0 })
|
||||
Object.keys(knownKeys).forEach((flag) => {
|
||||
result[flag] = 0
|
||||
})
|
||||
}
|
||||
} else if (totalFlags.reset > 0 && totalFlags.reset < 9000) {
|
||||
console.debug('Received command to reset the flags')
|
||||
allFlagKeys.forEach(flag => { result[flag] = 0 })
|
||||
allFlagKeys.forEach((flag) => {
|
||||
result[flag] = 0
|
||||
})
|
||||
}
|
||||
result.reset = 0
|
||||
return result
|
||||
|
|
@ -304,20 +371,29 @@ export const _doMigrations = (cache) => {
|
|||
if (!cache) return cache
|
||||
|
||||
if (cache._version < VERSION) {
|
||||
console.debug('Local cached data has older version, seeing if there any migrations that can be applied')
|
||||
console.debug(
|
||||
'Local cached data has older version, seeing if there any migrations that can be applied',
|
||||
)
|
||||
|
||||
// no migrations right now since we only have one version
|
||||
console.debug('No migrations found')
|
||||
}
|
||||
|
||||
if (cache._version > VERSION) {
|
||||
console.debug('Local cached data has newer version, seeing if there any reverse migrations that can be applied')
|
||||
console.debug(
|
||||
'Local cached data has newer version, seeing if there any reverse migrations that can be applied',
|
||||
)
|
||||
|
||||
// no reverse migrations right now but we leave a possibility of loading a hotpatch if need be
|
||||
if (window._PLEROMA_HOTPATCH) {
|
||||
if (window._PLEROMA_HOTPATCH.reverseMigrations) {
|
||||
console.debug('Found hotpatch migration, applying')
|
||||
return window._PLEROMA_HOTPATCH.reverseMigrations.call({}, 'serverSideStorage', { from: cache._version, to: VERSION }, cache)
|
||||
return window._PLEROMA_HOTPATCH.reverseMigrations.call(
|
||||
{},
|
||||
'serverSideStorage',
|
||||
{ from: cache._version, to: VERSION },
|
||||
cache,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -330,53 +406,77 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
|
|||
return cloneDeep(defaultState)
|
||||
},
|
||||
actions: {
|
||||
setFlag ({ flag, value }) {
|
||||
setFlag({ flag, value }) {
|
||||
this.flagStorage[flag] = value
|
||||
this.dirty = true
|
||||
},
|
||||
setPreference ({ path, value }) {
|
||||
setPreference({ path, value }) {
|
||||
if (path.startsWith('_')) {
|
||||
throw new Error(`Tried to edit internal (starts with _) field '${path}', ignoring.`)
|
||||
throw new Error(
|
||||
`Tried to edit internal (starts with _) field '${path}', ignoring.`,
|
||||
)
|
||||
}
|
||||
if (path.startsWith('collections') || path.startsWith('objectCollections')) {
|
||||
throw new Error(`Invalid operation 'set' for collection field '${path}', ignoring.`)
|
||||
if (
|
||||
path.startsWith('collections') ||
|
||||
path.startsWith('objectCollections')
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid operation 'set' for collection field '${path}', ignoring.`,
|
||||
)
|
||||
}
|
||||
if (path.split(/\./g).length <= 1) {
|
||||
throw new Error(`Calling set on depth <= 1 (path: ${path}) is not allowed`)
|
||||
throw new Error(
|
||||
`Calling set on depth <= 1 (path: ${path}) is not allowed`,
|
||||
)
|
||||
}
|
||||
if (path.split(/\./g).length > 3) {
|
||||
throw new Error(`Calling set on depth > 3 (path: ${path}) is not allowed`)
|
||||
throw new Error(
|
||||
`Calling set on depth > 3 (path: ${path}) is not allowed`,
|
||||
)
|
||||
}
|
||||
set(this.prefsStorage, path, value)
|
||||
this.prefsStorage._journal = [
|
||||
...this.prefsStorage._journal,
|
||||
{ operation: 'set', path, args: [value], timestamp: Date.now() }
|
||||
{ operation: 'set', path, args: [value], timestamp: Date.now() },
|
||||
]
|
||||
this.dirty = true
|
||||
},
|
||||
unsetPreference ({ path, value }) {
|
||||
unsetPreference({ path, value }) {
|
||||
if (path.startsWith('_')) {
|
||||
throw new Error(`Tried to edit internal (starts with _) field '${path}', ignoring.`)
|
||||
throw new Error(
|
||||
`Tried to edit internal (starts with _) field '${path}', ignoring.`,
|
||||
)
|
||||
}
|
||||
if (path.startsWith('collections') || path.startsWith('objectCollections')) {
|
||||
throw new Error(`Invalid operation 'unset' for collection field '${path}', ignoring.`)
|
||||
if (
|
||||
path.startsWith('collections') ||
|
||||
path.startsWith('objectCollections')
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid operation 'unset' for collection field '${path}', ignoring.`,
|
||||
)
|
||||
}
|
||||
if (path.split(/\./g).length <= 2) {
|
||||
throw new Error(`Calling unset on depth <= 2 (path: ${path}) is not allowed`)
|
||||
throw new Error(
|
||||
`Calling unset on depth <= 2 (path: ${path}) is not allowed`,
|
||||
)
|
||||
}
|
||||
if (path.split(/\./g).length > 3) {
|
||||
throw new Error(`Calling unset on depth > 3 (path: ${path}) is not allowed`)
|
||||
throw new Error(
|
||||
`Calling unset on depth > 3 (path: ${path}) is not allowed`,
|
||||
)
|
||||
}
|
||||
unset(this.prefsStorage, path, value)
|
||||
this.prefsStorage._journal = [
|
||||
...this.prefsStorage._journal,
|
||||
{ operation: 'unset', path, args: [], timestamp: Date.now() }
|
||||
{ operation: 'unset', path, args: [], timestamp: Date.now() },
|
||||
]
|
||||
this.dirty = true
|
||||
},
|
||||
addCollectionPreference ({ path, value }) {
|
||||
addCollectionPreference({ path, value }) {
|
||||
if (path.startsWith('_')) {
|
||||
throw new Error(`tried to edit internal (starts with _) field '${path}'`)
|
||||
throw new Error(
|
||||
`tried to edit internal (starts with _) field '${path}'`,
|
||||
)
|
||||
}
|
||||
if (path.startsWith('collections')) {
|
||||
const collection = new Set(get(this.prefsStorage, path))
|
||||
|
|
@ -394,55 +494,79 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
|
|||
}
|
||||
this.prefsStorage._journal = [
|
||||
...this.prefsStorage._journal,
|
||||
{ operation: 'addToCollection', path, args: [value], timestamp: Date.now() }
|
||||
{
|
||||
operation: 'addToCollection',
|
||||
path,
|
||||
args: [value],
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
]
|
||||
this.dirty = true
|
||||
},
|
||||
removeCollectionPreference ({ path, value }) {
|
||||
removeCollectionPreference({ path, value }) {
|
||||
if (path.startsWith('_')) {
|
||||
throw new Error(`tried to edit internal (starts with _) field '${path}', ignoring.`)
|
||||
throw new Error(
|
||||
`tried to edit internal (starts with _) field '${path}', ignoring.`,
|
||||
)
|
||||
}
|
||||
const collection = new Set(get(this.prefsStorage, path))
|
||||
collection.delete(value)
|
||||
set(this.prefsStorage, path, [...collection])
|
||||
this.prefsStorage._journal = [
|
||||
...this.prefsStorage._journal,
|
||||
{ operation: 'removeFromCollection', path, args: [value], timestamp: Date.now() }
|
||||
{
|
||||
operation: 'removeFromCollection',
|
||||
path,
|
||||
args: [value],
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
]
|
||||
this.dirty = true
|
||||
},
|
||||
reorderCollectionPreference ({ path, value, movement }) {
|
||||
reorderCollectionPreference({ path, value, movement }) {
|
||||
if (path.startsWith('_')) {
|
||||
throw new Error(`tried to edit internal (starts with _) field '${path}', ignoring.`)
|
||||
throw new Error(
|
||||
`tried to edit internal (starts with _) field '${path}', ignoring.`,
|
||||
)
|
||||
}
|
||||
const collection = get(this.prefsStorage, path)
|
||||
const newCollection = _moveItemInArray(collection, value, movement)
|
||||
set(this.prefsStorage, path, newCollection)
|
||||
this.prefsStorage._journal = [
|
||||
...this.prefsStorage._journal,
|
||||
{ operation: 'arrangeCollection', path, args: [value], timestamp: Date.now() }
|
||||
{
|
||||
operation: 'arrangeCollection',
|
||||
path,
|
||||
args: [value],
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
]
|
||||
this.dirty = true
|
||||
},
|
||||
updateCache ({ username }) {
|
||||
updateCache({ username }) {
|
||||
this.prefsStorage._journal = _mergeJournal(this.prefsStorage._journal)
|
||||
this.cache = _wrapData({
|
||||
flagStorage: toRaw(this.flagStorage),
|
||||
prefsStorage: toRaw(this.prefsStorage)
|
||||
}, username)
|
||||
this.cache = _wrapData(
|
||||
{
|
||||
flagStorage: toRaw(this.flagStorage),
|
||||
prefsStorage: toRaw(this.prefsStorage),
|
||||
},
|
||||
username,
|
||||
)
|
||||
},
|
||||
clearServerSideStorage () {
|
||||
clearServerSideStorage() {
|
||||
const blankState = { ...cloneDeep(defaultState) }
|
||||
Object.keys(this).forEach(k => {
|
||||
Object.keys(this).forEach((k) => {
|
||||
this[k] = blankState[k]
|
||||
})
|
||||
},
|
||||
setServerSideStorage (userData) {
|
||||
setServerSideStorage(userData) {
|
||||
const live = userData.storage
|
||||
this.raw = live
|
||||
let cache = this.cache
|
||||
if (cache && cache._user !== userData.fqn) {
|
||||
console.warn('Cache belongs to another user! reinitializing local cache!')
|
||||
console.warn(
|
||||
'Cache belongs to another user! reinitializing local cache!',
|
||||
)
|
||||
cache = null
|
||||
}
|
||||
|
||||
|
|
@ -455,10 +579,12 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
|
|||
let dirty = false
|
||||
|
||||
if (recent === null) {
|
||||
console.debug(`Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`)
|
||||
console.debug(
|
||||
`Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`,
|
||||
)
|
||||
recent = _wrapData({
|
||||
flagStorage: { ...flagsTemplate },
|
||||
prefsStorage: { ...defaultState.prefsStorage }
|
||||
prefsStorage: { ...defaultState.prefsStorage },
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -470,7 +596,7 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
|
|||
const { _timestamp: _2, _version: _3, ...staleData } = stale
|
||||
/* eslint-enable no-unused-vars */
|
||||
dirty = !isEqual(recentData, staleData)
|
||||
console.debug(`Data ${dirty ? 'needs' : 'doesn\'t need'} merging`)
|
||||
console.debug(`Data ${dirty ? 'needs' : "doesn't need"} merging`)
|
||||
}
|
||||
|
||||
const allFlagKeys = _getAllFlags(recent, stale)
|
||||
|
|
@ -502,7 +628,7 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
|
|||
this.flagStorage = this.cache.flagStorage
|
||||
this.prefsStorage = this.cache.prefsStorage
|
||||
},
|
||||
pushServerSideStorage ({ force = false } = {}) {
|
||||
pushServerSideStorage({ force = false } = {}) {
|
||||
const needPush = this.dirty || force
|
||||
if (!needPush) return
|
||||
this.updateCache({ username: window.vuex.state.users.currentUser.fqn })
|
||||
|
|
@ -513,6 +639,6 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
|
|||
this.setServerSideStorage(user)
|
||||
this.dirty = false
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ export const useShoutStore = defineStore('shout', {
|
|||
state: () => ({
|
||||
messages: [],
|
||||
channel: { state: '' },
|
||||
joined: false
|
||||
joined: false,
|
||||
}),
|
||||
actions: {
|
||||
initializeShout (socket) {
|
||||
initializeShout(socket) {
|
||||
const channel = socket.channel('chat:public')
|
||||
channel.joinPush.receive('ok', () => {
|
||||
this.joined = true
|
||||
|
|
@ -27,6 +27,6 @@ export const useShoutStore = defineStore('shout', {
|
|||
})
|
||||
channel.join()
|
||||
this.channel = channel
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@ import { defineStore } from 'pinia'
|
|||
export const useStatusHistoryStore = defineStore('statusHistory', {
|
||||
state: () => ({
|
||||
params: {},
|
||||
modalActivated: false
|
||||
modalActivated: false,
|
||||
}),
|
||||
actions: {
|
||||
openStatusHistoryModal (params) {
|
||||
openStatusHistoryModal(params) {
|
||||
this.params = params
|
||||
this.modalActivated = true
|
||||
},
|
||||
closeStatusHistoryModal () {
|
||||
closeStatusHistoryModal() {
|
||||
this.modalActivated = false
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue