biome format --write

This commit is contained in:
Henry Jameson 2026-01-06 16:22:52 +02:00
commit 9262e803ec
415 changed files with 54076 additions and 17419 deletions

View file

@ -11,34 +11,36 @@ export default {
acceptTypes: {
type: String,
required: false,
default: 'image/*'
}
default: 'image/*',
},
},
components: {
...Setting.components,
MediaUpload,
Attachment
Attachment,
},
computed: {
...Setting.computed,
attachment () {
attachment() {
const path = this.realDraftMode ? this.draft : this.state
// The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage.
const url = path.includes('://') ? path : this.$store.state.instance.server + path
const url = path.includes('://')
? path
: this.$store.state.instance.server + path
return {
mimetype: fileTypeExt(url),
url
url,
}
}
},
},
methods: {
...Setting.methods,
setMediaFile (fileInfo) {
setMediaFile(fileInfo) {
if (this.realDraftMode) {
this.draft = fileInfo.url
} else {
this.configSink(this.path, fileInfo.url)
}
}
}
},
},
}

View file

@ -5,27 +5,27 @@ export default {
...Setting,
props: {
...Setting.props,
indeterminateState: [String, Object]
indeterminateState: [String, Object],
},
components: {
...Setting.components,
Checkbox
Checkbox,
},
computed: {
...Setting.computed,
isIndeterminate () {
isIndeterminate() {
return this.visibleState === this.indeterminateState
}
},
},
methods: {
...Setting.methods,
getValue (e) {
getValue(e) {
// Basic tri-state toggle implementation
if (!!this.indeterminateState && !e && this.visibleState === true) {
// If we have indeterminate state, switching from true to false first goes through indeterminate
return this.indeterminateState
}
return e
}
}
},
},
}

View file

@ -5,50 +5,50 @@ export default {
...Setting,
components: {
...Setting.components,
Select
Select,
},
props: {
...Setting.props,
overrideOptions: {
type: Boolean,
required: false
required: false,
},
options: {
type: Array,
required: false
required: false,
},
optionLabelMap: {
type: Object,
required: false,
default: {}
}
default: {},
},
},
computed: {
...Setting.computed,
realOptions () {
realOptions() {
if (this.overrideOptions) {
return this.options
}
if (this.realSource === 'admin') {
if (
!this.backendDescriptionSuggestions?.length ||
this.backendDescriptionSuggestions?.length === 0
this.backendDescriptionSuggestions?.length === 0
) {
return this.options
}
return this.backendDescriptionSuggestions.map(x => ({
return this.backendDescriptionSuggestions.map((x) => ({
key: x,
value: x,
label: this.optionLabelMap[x] || x
label: this.optionLabelMap[x] || x,
}))
}
return this.options
}
},
},
methods: {
...Setting.methods,
getValue (e) {
getValue(e) {
return e
}
}
},
},
}

View file

@ -5,12 +5,12 @@ export default {
...Setting,
components: {
...Setting.components,
ColorInput
ColorInput,
},
methods: {
...Setting.methods,
getValue (e) {
getValue(e) {
return e
}
}
},
},
}

View file

@ -61,13 +61,11 @@ import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faWrench } from '@fortawesome/free-solid-svg-icons'
library.add(
faWrench
)
library.add(faWrench)
export default {
components: { Popover },
props: ['changed']
props: ['changed'],
}
</script>

View file

@ -160,53 +160,53 @@ export default {
props: {
placement: {
type: String,
required: true
required: true,
},
newUpload: Boolean,
title: {
type: String,
required: true
required: true,
},
packName: {
type: String,
required: true
required: true,
},
shortcode: {
type: String,
// Only exists when this is not a new upload
default: ''
default: '',
},
file: {
type: String,
// Only exists when this is not a new upload
default: ''
default: '',
},
// Only exists for emojis from remote packs
remote: {
type: Object,
default: undefined
default: undefined,
},
knownLocalPacks: {
type: Object,
default: undefined
}
default: undefined,
},
},
emits: ['updatePackFiles', 'displayError'],
data () {
data() {
return {
uploadFile: [],
uploadURL: '',
editedShortcode: this.shortcode,
editedFile: this.file,
deleteModalVisible: false,
copyToPack: ''
copyToPack: '',
}
},
computed: {
emojiPreview () {
emojiPreview() {
if (this.newUpload && this.uploadFile.length > 0) {
return URL.createObjectURL(this.uploadFile[0])
} else if (this.newUpload && this.uploadURL !== '') {
@ -217,73 +217,92 @@ export default {
return null
},
isEdited () {
return !this.newUpload && (this.editedShortcode !== this.shortcode || this.editedFile !== this.file)
isEdited() {
return (
!this.newUpload &&
(this.editedShortcode !== this.shortcode ||
this.editedFile !== this.file)
)
},
saveButtonDisabled() {
if (this.remote === undefined)
return this.newUpload ? (this.uploadURL === "" && this.uploadFile.length == 0) : !this.isEdited
else
return this.copyToPack === ""
}
return this.newUpload
? this.uploadURL === '' && this.uploadFile.length == 0
: !this.isEdited
else return this.copyToPack === ''
},
},
methods: {
saveEditedEmoji () {
saveEditedEmoji() {
if (!this.isEdited) return
this.$store.state.api.backendInteractor.updateEmojiFile(
{ packName: this.packName, shortcode: this.shortcode, newShortcode: this.editedShortcode, newFilename: this.editedFile, force: false }
).then(resp => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return Promise.reject(resp.error)
}
this.$store.state.api.backendInteractor
.updateEmojiFile({
packName: this.packName,
shortcode: this.shortcode,
newShortcode: this.editedShortcode,
newFilename: this.editedFile,
force: false,
})
.then((resp) => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return Promise.reject(resp.error)
}
return resp.json()
}).then(resp => this.$emit('updatePackFiles', resp))
return resp.json()
})
.then((resp) => this.$emit('updatePackFiles', resp))
},
uploadEmoji () {
uploadEmoji() {
let packName = this.remote === undefined ? this.packName : this.copyToPack
this.$store.state.api.backendInteractor.addNewEmojiFile({
packName: packName,
file: this.remote === undefined
? (this.uploadURL !== "" ? this.uploadURL : this.uploadFile[0])
: this.emojiAddr(this.file),
shortcode: this.editedShortcode,
filename: this.editedFile
}).then(resp => resp.json()).then(resp => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return
}
this.$store.state.api.backendInteractor
.addNewEmojiFile({
packName: packName,
file:
this.remote === undefined
? this.uploadURL !== ''
? this.uploadURL
: this.uploadFile[0]
: this.emojiAddr(this.file),
shortcode: this.editedShortcode,
filename: this.editedFile,
})
.then((resp) => resp.json())
.then((resp) => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return
}
this.$emit('updatePackFiles', resp, packName)
this.$refs.emojiPopover.hidePopover()
this.$emit('updatePackFiles', resp, packName)
this.$refs.emojiPopover.hidePopover()
this.editedFile = ''
this.editedShortcode = ''
this.uploadFile = []
})
this.editedFile = ''
this.editedShortcode = ''
this.uploadFile = []
})
},
revertEmoji () {
revertEmoji() {
this.editedFile = this.file
this.editedShortcode = this.shortcode
},
deleteEmoji () {
deleteEmoji() {
this.deleteModalVisible = false
this.$store.state.api.backendInteractor.deleteEmojiFile(
{ packName: this.packName, shortcode: this.shortcode }
).then(resp => resp.json()).then(resp => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return
}
this.$store.state.api.backendInteractor
.deleteEmojiFile({ packName: this.packName, shortcode: this.shortcode })
.then((resp) => resp.json())
.then((resp) => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return
}
this.$emit('updatePackFiles', resp, this.packName)
})
}
}
this.$emit('updatePackFiles', resp, this.packName)
})
},
},
}
</script>

View file

@ -10,7 +10,7 @@
import NumberSetting from './number_setting.vue'
export default {
components: {
NumberSetting
}
NumberSetting,
},
}
</script>

View file

@ -22,12 +22,10 @@ import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleQuestion } from '@fortawesome/free-solid-svg-icons'
library.add(
faCircleQuestion
)
library.add(faCircleQuestion)
export default {
components: { Popover }
components: { Popover },
}
</script>

View file

@ -11,7 +11,7 @@
import NumberSetting from './number_setting.vue'
export default {
components: {
NumberSetting
}
NumberSetting,
},
}
</script>

View file

@ -3,43 +3,43 @@ import Setting from './setting.js'
export default {
...Setting,
data () {
data() {
return {
newValue: '',
}
},
components: {
...Setting.components,
Checkbox
Checkbox,
},
props: {
...Setting.props,
ignoreSuggestions: {
required: false,
type: Boolean
type: Boolean,
},
overrideAvailableOptions: {
required: false,
type: Boolean
type: Boolean,
},
options: {
required: false,
type: Set
type: Set,
},
allowNew: {
required: false,
type: Boolean,
default: true
default: true,
},
forceNew: {
required: false,
type: Boolean,
default: false
}
default: false,
},
},
computed: {
...Setting.computed,
showNew () {
showNew() {
if (this.forceNew) return true
if (!this.allowNew) return false
@ -52,10 +52,10 @@ export default {
return true
}
},
valueSet () {
valueSet() {
return new Set(this.visibleState)
},
suggestionsSet () {
suggestionsSet() {
const suggestions = this.backendDescriptionSuggestions
if (suggestions) {
return new Set(suggestions)
@ -63,14 +63,14 @@ export default {
return new Set()
}
},
extraEntries () {
extraEntries() {
if (this.ignoreSuggestions) return [...this.valueSet.values()]
if (!this.suggestionsSet) return []
return [...this.valueSet.values()].filter((x) => {
return !this.builtinEntriesValueSet.has(x)
})
},
builtinEntries () {
builtinEntries() {
if (this.ignoreSuggestions) return []
if (this.overrideAvailableOptions) {
return [...this.options]
@ -80,19 +80,19 @@ export default {
const builtins = [...this.suggestionsSet.values()]
return builtins.map((option) => ({
label: option,
value: option
value: option,
}))
},
builtinEntriesValueSet () {
return new Set(this.builtinEntries.map(x => x.value))
}
builtinEntriesValueSet() {
return new Set(this.builtinEntries.map((x) => x.value))
},
},
methods: {
...Setting.methods,
optionPresent (option) {
optionPresent(option) {
return this.valueSet.has(option)
},
getValue ({ event, value, index, eventType }) {
getValue({ event, value, index, eventType }) {
switch (eventType) {
case 'toggle': {
this.newValue = ''
@ -128,6 +128,6 @@ export default {
return [...pre, string, ...post]
}
}
}
}
},
},
}

View file

@ -2,14 +2,14 @@ import ListSetting from './list_setting.js'
export default {
...ListSetting,
data () {
data() {
return {
newValue: ['','']
newValue: ['', ''],
}
},
methods: {
...ListSetting.methods,
getValue ({ event, index, eventType, tuple }) {
getValue({ event, index, eventType, tuple }) {
switch (eventType) {
case 'add': {
if (!this.newValue[0] || !this.newValue[1]) return this.visibleState
@ -39,6 +39,6 @@ export default {
}
}
}
}
}
},
},
}

View file

@ -7,28 +7,31 @@ export default {
allowNew: {
required: false,
type: Boolean,
default: true
}
default: true,
},
},
data () {
data() {
return {
newValue: ['',''] // avoiding extra complexity by just using an array instead of an object
newValue: ['', ''], // avoiding extra complexity by just using an array instead of an object
}
},
computed: {
...Setting.computed,
// state that we'll show in the UI, i.e. transforming map into list
displayState () {
displayState() {
return Object.entries(this.visibleState)
}
},
},
methods: {
...Setting.methods,
getValue ({ event, key, eventType, isKey }) {
getValue({ event, key, eventType, isKey }) {
switch (eventType) {
case 'add': {
if (key === '') return this.visibleState
const res = {...this.visibleState, ...Object.fromEntries([this.newValue])}
const res = {
...this.visibleState,
...Object.fromEntries([this.newValue]),
}
this.newValue = ['', '']
return res
}
@ -36,35 +39,35 @@ export default {
case 'remove': {
// initial state for this type is empty array
if (Array.isArray(this.visibleState)) return this.visibleState
const newEntries = Object.entries(this.visibleState).filter(([k]) => k !== key)
const newEntries = Object.entries(this.visibleState).filter(
([k]) => k !== key,
)
if (newEntries.length === 0 ) return []
if (newEntries.length === 0) return []
return Object.fromEntries(newEntries)
}
case 'edit': {
const string = event.target.value
const newEntries = Object
.entries(this.visibleState)
.map(([k, v]) => {
if (isKey) {
if (k === key) {
return [string, v]
} else {
return [k, v]
}
const newEntries = Object.entries(this.visibleState).map(([k, v]) => {
if (isKey) {
if (k === key) {
return [string, v]
} else {
if (k === key) {
return [k, string]
} else {
return [k, v]
}
return [k, v]
}
})
} else {
if (k === key) {
return [k, string]
} else {
return [k, v]
}
}
})
return Object.fromEntries(newEntries)
}
}
}
}
},
},
}

View file

@ -27,9 +27,7 @@ import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faWrench } from '@fortawesome/free-solid-svg-icons'
library.add(
faWrench
)
library.add(faWrench)
export default {
components: { Popover },
@ -37,9 +35,9 @@ export default {
changed: Boolean,
messageKey: {
type: String,
default: 'settings.setting_changed'
}
}
default: 'settings.setting_changed',
},
},
}
</script>

View file

@ -7,33 +7,33 @@ export default {
min: {
type: Number,
required: false,
default: 1
default: 1,
},
max: {
type: Number,
required: false,
default: 1
default: 1,
},
step: {
type: Number,
required: false,
default: 1
default: 1,
},
truncate: {
type: Number,
required: false,
default: 1
}
default: 1,
},
},
methods: {
...Setting.methods,
getValue (e) {
getValue(e) {
if (!this.truncate === 1) {
return parseInt(e.target.value)
} else if (this.truncate > 1) {
return Math.trunc(e.target.value / this.truncate) * this.truncate
}
return parseFloat(e.target.value)
}
}
},
},
}

View file

@ -27,13 +27,11 @@ import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faServer } from '@fortawesome/free-solid-svg-icons'
library.add(
faServer
)
library.add(faServer)
export default {
components: { Popover },
props: ['isProfile']
props: ['isProfile'],
}
</script>

View file

@ -1,18 +1,19 @@
import Checkbox from 'src/components/checkbox/checkbox.vue'
import Setting from './setting.js'
const getUrl = state => state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state
const getSocks = state => state?.tuple
const getUrl = (state) =>
state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state
const getSocks = (state) => state?.tuple
export default {
...Setting,
data () {
data() {
return {
urlField: '',
socksField: false
socksField: false,
}
},
created () {
created() {
Setting.created()
this.urlField = getUrl(this.realDraftMode ? this.draft : this.state)
this.socksField = getSocks(this.realDraftMode ? this.draft : this.state)
@ -20,23 +21,23 @@ export default {
computed: {
...Setting.computed,
// state that we'll show in the UI, i.e. transforming map into list
displayState () {
displayState() {
if (this.visibleState?.tuple) {
return this.visibleState.tuple[1] + ':' + this.visibleState.tuple[2]
}
return this.visibleState
},
socksState () {
socksState() {
return getSocks(this.visibleState)
}
},
},
components: {
...Setting.components,
Checkbox
Checkbox,
},
methods: {
...Setting.methods,
getValue ({ event, isProxy}) {
getValue({ event, isProxy }) {
if (isProxy) {
this.socksField = event
} else {
@ -44,10 +45,10 @@ export default {
}
if (this.socksField) {
return { tuple: [ ':socks5', ...this.urlField.split(':') ] }
return { tuple: [':socks5', ...this.urlField.split(':')] }
} else {
return this.urlField
}
}
}
},
},
}

View file

@ -12,60 +12,62 @@ export default {
...Setting.components,
Select,
Attachment,
MediaUpload
MediaUpload,
},
computed: {
...Setting.computed,
purposeOptions () {
return ['any','monochrome','maskable'].map(value => ({
purposeOptions() {
return ['any', 'monochrome', 'maskable'].map((value) => ({
value,
key: value,
label: this.$t('admin_dash.instance.pwa.icon.' + value)
label: this.$t('admin_dash.instance.pwa.icon.' + value),
}))
}
},
},
methods: {
...Setting.methods,
attachment (e) {
attachment(e) {
const path = e[':src']
if (!path) {
return {
mimetype: '',
url: ''
url: '',
}
}
const url = path.includes('://') ? path : this.$store.state.instance.server + path
const url = path.includes('://')
? path
: this.$store.state.instance.server + path
return {
mimetype: fileTypeExt(url),
url
url,
}
},
setMediaFile ({ event, index }) {
setMediaFile({ event, index }) {
this.update({
event: {
target: {
value: event.url
value: event.url,
},
},
index,
eventType: 'edit',
field: ':src'
field: ':src',
})
},
setPurpose ({ event, index }) {
setPurpose({ event, index }) {
this.update({
event: {
target: {
value: event
value: event,
},
},
index,
eventType: 'edit',
field: ':purpose'
field: ':purpose',
})
},
getValue ({ event, field, index, eventType }) {
getValue({ event, field, index, eventType }) {
switch (eventType) {
case 'add': {
const res = [...this.visibleState, {}]
@ -85,7 +87,7 @@ export default {
const item = clone(this.visibleState[index])
const string = event.target.value
if (!string) {
if (!string) {
delete item[field]
} else {
item[field] = string
@ -94,6 +96,6 @@ export default {
return [...pre, item, ...post]
}
}
}
}
},
},
}

View file

@ -3,40 +3,40 @@ import Setting from './setting.js'
export default {
...Setting,
data () {
data() {
return {
newValue: '',
}
},
components: {
...Setting.components,
Checkbox
Checkbox,
},
props: {
...Setting.props
...Setting.props,
},
computed: {
...Setting.computed,
isSeparate () {
isSeparate() {
// [[a1, b1], [a2, b2]] vs [a, b]
return Array.isArray(this.visibleState[0])
},
normalizedState () {
normalizedState() {
if (this.isSeparate) {
return this.visibleState.map(y => y.map(x => Number(x) || 0))
return this.visibleState.map((y) => y.map((x) => Number(x) || 0))
} else {
return [this.visibleState.map(x => Number(x) || 0)]
return [this.visibleState.map((x) => Number(x) || 0)]
}
}
},
},
methods: {
...Setting.methods,
getValue ({ event, side, index, eventType }) {
getValue({ event, side, index, eventType }) {
if (eventType === 'edit') {
const value = Number(event.target.value)
if (Number.isNaN(value)) return this.visibleState
const newVal = [...this.normalizedState.map(x => [...x])]
const newVal = [...this.normalizedState.map((x) => [...x])]
newVal[side][index] = value
return newVal
}
@ -48,6 +48,6 @@ export default {
return [this.normalizedState[0]]
}
}
}
}
},
},
}

View file

@ -7,119 +7,126 @@ export default {
components: {
ModifiedIndicator,
DraftButtons,
ProfileSettingIndicator
ProfileSettingIndicator,
},
props: {
modelValue: {
type: String,
default: null
default: null,
},
path: {
type: [String, Array],
required: false
required: false,
},
showDescription: {
type: Boolean,
required: false
required: false,
},
descriptionPathOverride: {
type: [String, Array],
required: false
required: false,
},
suggestions: {
type: [String, Array],
required: false
required: false,
},
subgroup: {
type: String,
required: false
required: false,
},
disabled: {
type: Boolean,
default: false
default: false,
},
parentPath: {
type: [String, Array]
type: [String, Array],
},
parentInvert: {
type: Boolean,
default: false
default: false,
},
expert: {
type: [Number, String],
default: 0
default: 0,
},
source: {
type: String,
default: undefined
default: undefined,
},
hideDraftButtons: { // this is for the weird backend hybrid (Boolean|String or Boolean|Number) settings
hideDraftButtons: {
// this is for the weird backend hybrid (Boolean|String or Boolean|Number) settings
required: false,
type: Boolean
type: Boolean,
},
hideLabel: {
type: Boolean
type: Boolean,
},
hideDescription: {
type: Boolean
type: Boolean,
},
swapDescriptionAndLabel: {
type: Boolean
type: Boolean,
},
backendDescriptionPath: {
type: [String, Array]
type: [String, Array],
},
overrideBackendDescription: {
type: Boolean
type: Boolean,
},
overrideBackendDescriptionLabel: {
type: [Boolean, String]
type: [Boolean, String],
},
draftMode: {
type: Boolean,
default: undefined
default: undefined,
},
timedApplyMode: {
type: Boolean,
default: false
}
default: false,
},
},
inject: {
defaultSource: {
default: 'default'
default: 'default',
},
defaultDraftMode: {
default: false
}
default: false,
},
},
data () {
data() {
return {
localDraft: null
localDraft: null,
}
},
created () {
if (this.realDraftMode && (this.realSource !== 'admin' || this.path == null)) {
created() {
if (
this.realDraftMode &&
(this.realSource !== 'admin' || this.path == null)
) {
this.draft = cloneDeep(this.state)
}
},
computed: {
draft: {
get () {
get() {
if (this.realSource === 'admin' || this.path == null) {
return get(this.$store.state.adminSettings.draft, this.canonPath)
} else {
return this.localDraft
}
},
set (value) {
set(value) {
if (this.realSource === 'admin' || this.path == null) {
this.$store.commit('updateAdminDraft', { path: this.canonPath, value })
this.$store.commit('updateAdminDraft', {
path: this.canonPath,
value,
})
} else {
this.localDraft = value
}
}
},
},
state () {
state() {
if (this.path == null) {
return this.modelValue
}
@ -130,71 +137,93 @@ export default {
return value
}
},
visibleState () {
visibleState() {
return this.realDraftMode ? this.draft : this.state
},
realSource () {
realSource() {
return this.source || this.defaultSource
},
realDraftMode () {
return typeof this.draftMode === 'undefined' ? this.defaultDraftMode : this.draftMode
realDraftMode() {
return typeof this.draftMode === 'undefined'
? this.defaultDraftMode
: this.draftMode
},
backendDescription () {
return get(this.$store.state.adminSettings.descriptions, this.descriptionPath)
backendDescription() {
return get(
this.$store.state.adminSettings.descriptions,
this.descriptionPath,
)
},
backendDescriptionLabel () {
backendDescriptionLabel() {
if (this.realSource !== 'admin') return ''
if (this.overrideBackendDescriptionLabel !== '' && typeof this.overrideBackendDescriptionLabel === 'string') {
if (
this.overrideBackendDescriptionLabel !== '' &&
typeof this.overrideBackendDescriptionLabel === 'string'
) {
return this.overrideBackendDescriptionLabel
}
if (!this.backendDescription || this.overrideBackendDescriptionLabel) {
return this.$t([
'admin_dash',
'temp_overrides',
...this.canonPath.map(p => p.replace(/\./g, '_DOT_')),
'label'
].join('.'))
return this.$t(
[
'admin_dash',
'temp_overrides',
...this.canonPath.map((p) => p.replace(/\./g, '_DOT_')),
'label',
].join('.'),
)
} else {
return this.swapDescriptionAndLabel
? this.backendDescription?.description
: this.backendDescription?.label
}
},
backendDescriptionDescription () {
backendDescriptionDescription() {
if (this.description) return this.description
if (this.realSource !== 'admin') return ''
if (this.hideDescription) return null
if (!this.backendDescription || this.overrideBackendDescription) {
return this.$t([
'admin_dash',
'temp_overrides',
...this.canonPath.map(p => p.replace(/\./g, '_DOT_')),
'description'
].join('.'))
return this.$t(
[
'admin_dash',
'temp_overrides',
...this.canonPath.map((p) => p.replace(/\./g, '_DOT_')),
'description',
].join('.'),
)
} else {
return this.swapDescriptionAndLabel
? this.backendDescription?.label
: this.backendDescription?.description
}
},
backendDescriptionSuggestions () {
backendDescriptionSuggestions() {
return this.backendDescription?.suggestions || this.suggestions
},
shouldBeDisabled () {
shouldBeDisabled() {
if (this.path == null) {
return this.disabled
}
let parentValue = null
if (this.parentPath !== undefined && this.realSource === 'admin') {
if (this.realDraftMode) {
parentValue = get(this.$store.state.adminSettings.draft, this.parentPath)
parentValue = get(
this.$store.state.adminSettings.draft,
this.parentPath,
)
} else {
parentValue = get(this.configSource, this.parentPath)
}
}
return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false)
return (
this.disabled ||
(parentValue !== null
? this.parentInvert
? parentValue
: !parentValue
: false)
)
},
configSource () {
configSource() {
switch (this.realSource) {
case 'profile':
return this.$store.state.profileConfig
@ -204,24 +233,31 @@ export default {
return this.$store.getters.mergedConfig
}
},
configSink () {
configSink() {
if (this.path == null) {
return (k, v) => this.$emit('update:modelValue', v)
}
switch (this.realSource) {
case 'profile':
return (k, v) => this.$store.dispatch('setProfileOption', { name: k, value: v })
return (k, v) =>
this.$store.dispatch('setProfileOption', { name: k, value: v })
case 'admin':
return (k, v) => this.$store.dispatch('pushAdminSetting', { path: k, value: v })
return (k, v) =>
this.$store.dispatch('pushAdminSetting', { path: k, value: v })
default:
if (this.timedApplyMode) {
return (k, v) => this.$store.dispatch('setOptionTemporarily', { name: k, value: v })
return (k, v) =>
this.$store.dispatch('setOptionTemporarily', {
name: k,
value: v,
})
} else {
return (k, v) => this.$store.dispatch('setOption', { name: k, value: v })
return (k, v) =>
this.$store.dispatch('setOption', { name: k, value: v })
}
}
},
defaultState () {
defaultState() {
switch (this.realSource) {
case 'profile':
return {}
@ -229,10 +265,10 @@ export default {
return get(this.$store.getters.defaultConfig, this.path)
}
},
isProfileSetting () {
isProfileSetting() {
return this.realSource === 'profile'
},
isChanged () {
isChanged() {
if (this.path == null) return false
switch (this.realSource) {
case 'profile':
@ -242,24 +278,24 @@ export default {
return this.state !== this.defaultState
}
},
canonPath () {
canonPath() {
if (this.path == null) return null
return Array.isArray(this.path) ? this.path : this.path.split('.')
},
descriptionPath () {
descriptionPath() {
if (this.path == null) return null
if (this.descriptionPathOverride) return this.descriptionPathOverride
const path = Array.isArray(this.path) ? this.path : this.path.split('.')
if (this.subgroup) {
return [
...path.slice(0, path.length - 1),
':subgroup,' + this.subgroup,
...path.slice(path.length - 1)
...path.slice(0, path.length - 1),
':subgroup,' + this.subgroup,
...path.slice(path.length - 1),
]
}
return path
},
isDirty () {
isDirty() {
if (this.path == null) return false
if (this.realSource === 'admin' && this.canonPath.length > 3) {
return false // should not show draft buttons for "grouped" values
@ -267,47 +303,59 @@ export default {
return this.realDraftMode && !isEqual(this.draft, this.state)
}
},
canHardReset () {
return this.realSource === 'admin' && this.$store.state.adminSettings.modifiedPaths?.has(this.canonPath.join(' -> '))
canHardReset() {
return (
this.realSource === 'admin' &&
this.$store.state.adminSettings.modifiedPaths?.has(
this.canonPath.join(' -> '),
)
)
},
matchesExpertLevel () {
matchesExpertLevel() {
const settingExpertLevel = this.expert || 0
const userToggleExpert = this.$store.state.config.expertLevel || 0
return settingExpertLevel <= userToggleExpert
}
},
},
methods: {
getValue (e) {
getValue(e) {
return e.target.value
},
update (e) {
update(e) {
if (this.realDraftMode) {
this.draft = this.getValue(e)
} else {
this.configSink(this.path, this.getValue(e))
}
},
commitDraft () {
commitDraft() {
if (this.realDraftMode) {
this.configSink(this.path, this.draft)
}
},
reset () {
reset() {
if (this.realDraftMode) {
this.draft = cloneDeep(this.state)
} else {
set(this.$store.getters.mergedConfig, this.path, cloneDeep(this.defaultState))
set(
this.$store.getters.mergedConfig,
this.path,
cloneDeep(this.defaultState),
)
}
},
hardReset () {
hardReset() {
switch (this.realSource) {
case 'admin':
return this.$store.dispatch('resetAdminSetting', { path: this.path })
.then(() => { this.draft = this.state })
return this.$store
.dispatch('resetAdminSetting', { path: this.path })
.then(() => {
this.draft = this.state
})
default:
console.warn('Hard reset not implemented yet!')
}
}
}
},
},
}

View file

@ -1,19 +1,19 @@
const SharedComputedObject = () => ({
user () {
user() {
return this.$store.state.users.currentUser
},
expertLevel () {
expertLevel() {
return this.$store.getters.mergedConfig.expertLevel > 0
},
mergedConfig () {
mergedConfig() {
return this.$store.getters.mergedConfig
},
adminConfig () {
adminConfig() {
return this.$store.state.adminSettings.config
},
adminDraft () {
adminDraft() {
return this.$store.state.adminSettings.draft
}
},
})
export default SharedComputedObject

View file

@ -1,5 +1,5 @@
import Setting from './setting.js'
export default {
...Setting
...Setting,
}

View file

@ -4,13 +4,13 @@ export default {
...Setting,
methods: {
...Setting.methods,
getValue ({ e, side }) {
getValue({ e, side }) {
const [a, b] = this.visibleState || []
if (side === 0) {
return { tuple: [e.target.value, b]}
return { tuple: [e.target.value, b] }
} else {
return { tuple: [a, e.target.value]}
return { tuple: [a, e.target.value] }
}
}
}
},
},
}

View file

@ -1,7 +1,23 @@
import Select from 'src/components/select/select.vue'
import Setting from './setting.js'
export const allCssUnits = ['cm', 'mm', 'in', 'px', 'pt', 'pc', 'em', 'ex', 'ch', 'rem', 'vw', 'vh', 'vmin', 'vmax', '%']
export const allCssUnits = [
'cm',
'mm',
'in',
'px',
'pt',
'pc',
'em',
'ex',
'ch',
'rem',
'vw',
'vh',
'vmin',
'vmax',
'%',
]
export const defaultHorizontalUnits = ['px', 'rem', 'vw']
export const defaultVerticalUnits = ['px', 'rem', 'vh']
@ -9,47 +25,51 @@ export default {
...Setting,
components: {
...Setting.components,
Select
Select,
},
props: {
...Setting.props,
min: Number,
units: {
type: Array,
default: () => allCssUnits
default: () => allCssUnits,
},
unitSet: {
type: String,
default: 'none'
default: 'none',
},
step: {
type: Number,
default: 1
default: 1,
},
resetDefault: {
type: Object,
default: null
}
default: null,
},
},
computed: {
...Setting.computed,
stateUnit () {
return typeof this.state === 'string' ? this.state.replace(/[0-9,.]+/, '') : ''
stateUnit() {
return typeof this.state === 'string'
? this.state.replace(/[0-9,.]+/, '')
: ''
},
stateValue() {
return typeof this.state === 'string'
? this.state.replace(/[^0-9,.]+/, '')
: ''
},
stateValue () {
return typeof this.state === 'string' ? this.state.replace(/[^0-9,.]+/, '') : ''
}
},
methods: {
...Setting.methods,
getUnitString (value) {
getUnitString(value) {
if (this.unitSet === 'none') return value
return this.$t(['settings', 'units', this.unitSet, value].join('.'))
},
updateValue (e) {
updateValue(e) {
this.configSink(this.path, parseFloat(e.target.value) + this.stateUnit)
},
updateUnit (e) {
updateUnit(e) {
let value = this.stateValue
const newUnit = e.target.value
if (this.resetDefault) {
@ -59,6 +79,6 @@ export default {
}
}
this.configSink(this.path, value + newUnit)
}
}
},
},
}

View file

@ -8,7 +8,7 @@ import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
import './vertical_tab_switcher.scss'
import { useInterfaceStore } from 'src/stores/interface'
const findFirstUsable = (slots) => slots.findIndex(_ => _.props)
const findFirstUsable = (slots) => slots.findIndex((_) => _.props)
export default {
name: 'VerticalTabSwitcher',
@ -16,30 +16,30 @@ export default {
renderOnlyFocused: {
required: false,
type: Boolean,
default: false
default: false,
},
onSwitch: {
required: false,
type: Function,
default: undefined
default: undefined,
},
activeTab: {
required: false,
type: String,
default: undefined
default: undefined,
},
bodyScrollLock: {
required: false,
type: Boolean,
default: false
default: false,
},
parentCollapsed: {
required: false,
type: Boolean,
default: null
}
default: null,
},
},
data () {
data() {
return {
active: findFirstUsable(this.slots()),
resizeHandler: null,
@ -47,82 +47,89 @@ export default {
}
},
computed: {
activeIndex () {
activeIndex() {
// In case of controlled component
if (this.activeTab) {
return this.slots().findIndex(slot => slot && slot.props && this.activeTab === slot.props.key)
return this.slots().findIndex(
(slot) => slot && slot.props && this.activeTab === slot.props.key,
)
} else {
return this.active
}
},
isActive () {
return tabName => {
const isWanted = slot => slot.props && slot.props['data-tab-name'] === tabName
isActive() {
return (tabName) => {
const isWanted = (slot) =>
slot.props && slot.props['data-tab-name'] === tabName
return this.$slots.default().findIndex(isWanted) === this.activeIndex
}
},
...mapPiniaState(useInterfaceStore, {
mobileLayout: store => store.layoutType === 'mobile'
mobileLayout: (store) => store.layoutType === 'mobile',
}),
},
beforeUpdate () {
beforeUpdate() {
const currentSlot = this.slots()[this.active]
if (!currentSlot.props) {
this.active = findFirstUsable(this.slots())
}
},
methods: {
clickTab (index) {
clickTab(index) {
return (e) => {
e.preventDefault()
this.setTab(index)
}
},
setTab (index) {
setTab(index) {
if (typeof this.onSwitch === 'function') {
this.onSwitch.call(null, this.slots()[index].key)
}
this.active = index
this.changeNavSide('content')
},
changeNavSide (side) {
changeNavSide(side) {
if (this.navSide !== side) {
this.navSide = side
}
},
// DO NOT put it to computed, it doesn't work (caching?)
slots () {
slots() {
if (this.$slots.default()[0].type === Fragment) {
return this.$slots.default()[0].children
}
return this.$slots.default()
}
},
},
render () {
const tabs = this.slots()
.map((slot, index) => {
const props = slot.props
if (!props) return
const classesTab = ['vertical-tab', 'menu-item']
if (this.activeIndex === index && useInterfaceStore().layoutType !== 'mobile') {
classesTab.push('-active')
}
return (
<button
disabled={props.disabled}
onClick={this.clickTab(index)}
class={classesTab.join(' ')}
type="button"
role="tab"
title={props.label}
>
{!props.icon ? '' : (<FAIcon class="tab-icon" size="1x" fixed-width icon={props.icon}/>)}
<span class="text">
{props.label}
</span>
</button>
)
})
render() {
const tabs = this.slots().map((slot, index) => {
const props = slot.props
if (!props) return
const classesTab = ['vertical-tab', 'menu-item']
if (
this.activeIndex === index &&
useInterfaceStore().layoutType !== 'mobile'
) {
classesTab.push('-active')
}
return (
<button
disabled={props.disabled}
onClick={this.clickTab(index)}
class={classesTab.join(' ')}
type="button"
role="tab"
title={props.label}
>
{!props.icon ? (
''
) : (
<FAIcon class="tab-icon" size="1x" fixed-width icon={props.icon} />
)}
<span class="text">{props.label}</span>
</button>
)
})
const contents = this.slots().map((slot, index) => {
const props = slot.props
@ -134,9 +141,8 @@ export default {
slot.props['delay-render'] = false
delayRender = false
}
const renderSlot = (!delayRender && (!this.renderOnlyFocused || active))
? slot
: ''
const renderSlot =
!delayRender && (!this.renderOnlyFocused || active) ? slot : ''
const headerClasses = ['tab-content-label']
const header = (
@ -147,17 +153,16 @@ export default {
title={this.$t('nav.back')}
class="button-unstyled"
>
<FAIcon
size="lg"
class="back-button-icon"
icon="chevron-left"
/>
<FAIcon size="lg" class="back-button-icon" icon="chevron-left" />
</button>
{props.label}
</h2>
)
const wrapperClasses = ['tab-content-wrapper', active ? '-active' : '-hidden' ]
const wrapperClasses = [
'tab-content-wrapper',
active ? '-active' : '-hidden',
]
const contentClasses = ['tab-content']
if (props['full-width'] || props['full-width'] === '') {
contentClasses.push('-full-width')
@ -168,14 +173,10 @@ export default {
wrapperClasses.push('-full-height')
}
return (
<div class={wrapperClasses} >
<div class="tab-mobile-header">
{header}
</div>
<div class={wrapperClasses}>
<div class="tab-mobile-header">{header}</div>
<div class="tab-slot-wrapper">
<div class={contentClasses} >
{renderSlot}
</div>
<div class={contentClasses}>{renderSlot}</div>
</div>
</div>
)
@ -193,12 +194,8 @@ export default {
}
return (
<div ref="root" class={ rootClasses.join(' ') }>
<div
class="tabs"
role="tablist"
ref="nav"
>
<div ref="root" class={rootClasses.join(' ')}>
<div class="tabs" role="tablist" ref="nav">
{tabs}
</div>
<div
@ -211,5 +208,5 @@ export default {
</div>
</div>
)
}
},
}