Add 'settings/' from commit '230545a4a75b0611988fbcea51336a6c316d6a3d'

git-subtree-dir: settings
git-subtree-mainline: c26f7b390a
git-subtree-split: 230545a4a7
This commit is contained in:
A.Unger
2020-09-18 12:43:43 +02:00
140 changed files with 28757 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
<template>
<div>
<div v-if="initialized" class="uk-width-3-4@m uk-container uk-padding">
<oc-alert v-if="extensions.length === 0" variation="primary" no-close>
<p class="uk-flex uk-flex-middle">
<oc-icon name="info" class="uk-margin-xsmall-right" />
<translate>No settings available</translate>
</p>
</oc-alert>
<template v-else>
<template v-if="selectedExtensionName">
<div class="uk-flex uk-flex-between uk-flex-middle">
<h1 class="oc-page-title">
{{ selectedExtensionName }}
</h1>
</div>
<hr />
</template>
<template v-if="settingsValuesLoaded">
<settings-bundle
v-for="bundle in selectedBundles"
:key="'bundle-' + bundle.id"
:bundle="bundle"
class="uk-margin-top"
/>
</template>
<div class="uk-margin-top" v-else>
<oc-loader :aria-label="$gettext('Loading personal settings')" />
<oc-alert :aria-hidden="true" varition="primary" no-close>
<p v-translate>Loading personal settings...</p>
</oc-alert>
</div>
</template>
</div>
<oc-loader v-else />
</div>
</template>
<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import SettingsBundle from './SettingsBundle.vue'
export default {
name: 'SettingsApp',
components: { SettingsBundle },
data () {
return {
loading: true,
selectedExtension: undefined
}
},
computed: {
...mapGetters(['settingsValuesLoaded', 'getNavItems']),
...mapGetters('Settings', [
'extensions',
'initialized',
'getBundlesByExtension'
]),
extensionRouteParam () {
return this.$route.params.extension
},
selectedExtensionName () {
return this.getExtensionName(this.selectedExtension)
},
selectedBundles () {
if (this.selectedExtension) {
return this.getBundlesByExtension(this.selectedExtension)
}
return []
}
},
methods: {
...mapActions('Settings', ['initialize']),
...mapMutations(['ADD_NAV_ITEM']),
resetSelectedExtension () {
if (this.extensions.length > 0) {
if (this.extensionRouteParam && this.extensions.includes(this.extensionRouteParam)) {
this.selectedExtension = this.extensionRouteParam
} else {
this.selectedExtension = this.extensions[0]
}
}
},
resetMenuItems () {
this.extensions.forEach(extension => {
/*
* TODO:
* a) set up a map with possible extensions and icons?
* or b) let extensions register app info like displayName + icon?
* https://github.com/owncloud/ocis-settings/issues/27
*/
const navItem = {
name: this.getExtensionName(extension),
iconMaterial: this.getExtensionIcon(extension),
route: {
name: 'settings',
path: `/settings/${extension}`
}
}
this.ADD_NAV_ITEM({
extension: 'settings',
navItem
})
})
},
getExtensionName (extension) {
extension = extension || ''
switch (extension) {
case 'ocis-accounts': return this.$gettext('Account')
case 'ocis-hello': return this.$gettext('Hello')
default: {
const shortenedName = extension.replace('ocis-', '')
return shortenedName.charAt(0).toUpperCase() + shortenedName.slice(1)
}
}
},
getExtensionIcon (extension) {
extension = extension || ''
switch (extension) {
case 'ocis-accounts': return 'account_circle'
case 'ocis-hello': return 'tag_faces'
default: return 'application'
}
}
},
async created () {
await this.initialize()
this.resetMenuItems()
this.resetSelectedExtension()
},
watch: {
initialized () {
this.resetMenuItems()
this.resetSelectedExtension()
},
extensionRouteParam () {
this.resetSelectedExtension()
}
}
}
</script>
+73
View File
@@ -0,0 +1,73 @@
<template>
<div class="uk-width-1-1 uk-width-2-3@m uk-width-1-2@l">
<div class="uk-text-bold uk-margin-small-bottom">
<translate>{{ bundle.displayName }}</translate>
</div>
<oc-grid gutter="small">
<template>
<div class="uk-width-1-1" v-for="setting in bundle.settings" :key="setting.id">
<label class="oc-label" :for="setting.id">{{ setting.displayName }}</label>
<div class="uk-position-relative"
:is="getSettingComponent(setting)"
:id="setting.id"
:bundle="bundle"
:setting="setting"
:persisted-value="getValue(setting)"
@onSave="onSaveValue"
/>
</div>
</template>
</oc-grid>
</div>
</template>
<script>
import assign from 'lodash/assign'
import { mapGetters, mapActions } from 'vuex'
import SettingBoolean from './settings/SettingBoolean.vue'
import SettingMultiChoice from './settings/SettingMultiChoice.vue'
import SettingNumber from './settings/SettingNumber.vue'
import SettingSingleChoice from './settings/SettingSingleChoice.vue'
import SettingString from './settings/SettingString.vue'
import SettingUnknown from './settings/SettingUnknown.vue'
export default {
name: 'SettingsBundle',
props: {
bundle: {
type: Object,
required: true
}
},
computed: mapGetters(['getSettingsValue']),
methods: {
...mapActions('Settings', ['saveValue']),
getSettingComponent (setting) {
return 'Setting' + setting.type[0].toUpperCase() + setting.type.substr(1)
},
getValue (setting) {
return this.getSettingsValue({ settingId: setting.id })
},
async onSaveValue ({ bundle, setting, payload }) {
payload = assign({}, payload, {
bundleId: bundle.id,
settingId: setting.id,
accountUuid: 'me',
resource: setting.resource
})
await this.saveValue({
bundle,
setting,
payload
})
}
},
components: {
SettingBoolean,
SettingMultiChoice,
SettingNumber,
SettingSingleChoice,
SettingString,
SettingUnknown
}
}
</script>
@@ -0,0 +1,55 @@
<template>
<div>
<oc-checkbox v-model="value" :label="setting.boolValue.label" @change="applyValue" />
</div>
</template>
<script>
import isNil from 'lodash/isNil'
export default {
name: 'SettingBoolean',
props: {
bundle: {
type: Object,
required: true
},
setting: {
type: Object,
required: true
},
persistedValue: {
type: Object,
required: false
}
},
data () {
return {
value: null
}
},
methods: {
async applyValue () {
const payload = {
boolValue: this.value
}
if (!isNil(this.persistedValue)) {
payload.id = this.persistedValue.id
}
await this.$emit('onSave', {
bundle: this.bundle,
setting: this.setting,
payload
})
// TODO: show a spinner while the request for saving the value is running!
}
},
mounted () {
if (!isNil(this.persistedValue)) {
this.value = this.persistedValue.boolValue
}
if (isNil(this.value) && !isNil(this.setting.boolValue.default)) {
this.value = this.setting.boolValue.default
}
}
}
</script>
@@ -0,0 +1,140 @@
<template>
<div>
<oc-button :id="buttonElementId" class="uk-width-expand">
<span v-if="selectedOptions !== null && selectedOptions.length > 0">
{{ selectedOptionsDisplayValues }}
</span>
<span v-else>
{{ setting.placeholder || $gettext('Please select') }}
</span>
</oc-button>
<oc-drop
:drop-id="dropElementId"
:toggle="`#${buttonElementId}`"
mode="click"
position="bottom-justify"
:options="{ offset: 0, delayHide: 200, flip: false }"
>
<ul class="uk-list">
<li
v-for="(option, index) in setting.multiChoiceValue.options"
:key="getOptionElementId(index)"
>
<label :for="getOptionElementId(index)">
<input
:id="getOptionElementId(index)"
type="checkbox"
class="oc-checkbox"
:value="option"
v-model="selectedOptions"
@change="onSelectedOption"
/>
{{ option.displayValue }}
</label>
</li>
</ul>
</oc-drop>
</div>
</template>
<script>
import isNil from 'lodash/isNil'
export default {
name: 'SettingMultiChoice',
props: {
bundle: {
type: Object,
required: true
},
setting: {
type: Object,
required: true
},
persistedValue: {
type: Object,
required: false
}
},
data () {
return {
selectedOptions: null
}
},
computed: {
selectedOptionsDisplayValues () {
return Array.from(this.selectedOptions).map(option => option.displayValue).join(', ')
},
dropElementId () {
return `multi-choice-drop-${this.setting.id}`
},
buttonElementId () {
return `multi-choice-toggle-${this.setting.id}`
}
},
methods: {
getOptionElementId (index) {
return `${this.setting.id}-${index}`
},
async onSelectedOption () {
const values = []
if (!isNil(this.selectedOptions)) {
this.selectedOptions.forEach(option => {
if (option.value.intValue) {
values.push({ intValue: option.value.intValue })
}
if (option.value.stringValue) {
values.push({ stringValue: option.value.stringValue })
}
})
}
const payload = {
listValue: {
values
}
}
if (!isNil(this.persistedValue)) {
payload.id = this.persistedValue.id
}
await this.$emit('onSave', {
bundle: this.bundle,
setting: this.setting,
payload
})
// TODO: show a spinner while the request for saving the value is running!
}
},
mounted () {
if (!isNil(this.persistedValue) && !isNil(this.persistedValue.listValue)) {
const selectedValues = []
if (this.persistedValue.listValue.values) {
this.persistedValue.listValue.values.forEach(value => {
if (value.intValue) {
selectedValues.push(value.intValue)
}
if (value.stringValue) {
selectedValues.push(value.stringValue)
}
})
}
if (selectedValues.length === 0) {
this.selectedOptions = []
} else {
this.selectedOptions = this.setting.multiChoiceValue.options.filter(option => {
if (option.value.intValue) {
return selectedValues.includes(option.value.intValue)
}
if (option.value.stringValue) {
return selectedValues.includes(option.value.stringValue)
}
return false
})
}
}
// TODO: load the settings value of the authenticated user and set it in `selectedOptions`
// if not set, yet, apply defaults from settings bundle definition
if (this.selectedOptions === null) {
this.selectedOptions = this.setting.multiChoiceValue.options.filter(option => option.default)
}
}
}
</script>
@@ -0,0 +1,97 @@
<template>
<oc-grid flex>
<div class="uk-width-expand">
<oc-text-input
type="number"
v-model="value"
v-bind="inputAttributes"
:placeholder="setting.intValue.placeholder"
:label="setting.description"
@keydown.enter="applyValue"
@keydown.esc="cancel"
/>
</div>
<div v-if="isChanged">
<oc-button @click="cancel" class="uk-margin-xsmall-left">
<translate>Cancel</translate>
</oc-button>
<oc-button @click="applyValue" class="uk-margin-xsmall-left" variation="primary">
<translate>Save</translate>
</oc-button>
</div>
</oc-grid>
</template>
<script>
import isNil from 'lodash/isNil'
export default {
name: 'SettingNumber',
props: {
bundle: {
type: Object,
required: true
},
setting: {
type: Object,
required: true
},
persistedValue: {
type: Object,
required: false
}
},
data () {
return {
initialValue: null,
value: null
}
},
computed: {
isChanged () {
return this.initialValue !== this.value
},
inputAttributes () {
const attributes = {}
if (!isNil(this.setting.intValue.min)) {
attributes.min = this.setting.intValue.min
}
if (!isNil(this.setting.intValue.max)) {
attributes.max = this.setting.intValue.max
}
if (!isNil(this.setting.intValue.step)) {
attributes.step = this.setting.intValue.step
}
return attributes
}
},
methods: {
cancel () {
this.value = this.initialValue
},
async applyValue () {
const payload = {
intValue: this.value
}
if (!isNil(this.persistedValue)) {
payload.id = this.persistedValue.id
}
await this.$emit('onSave', {
bundle: this.bundle,
setting: this.setting,
payload
})
// TODO: show a spinner while the request for saving the value is running!
this.initialValue = this.value
}
},
mounted () {
if (!isNil(this.persistedValue)) {
this.value = this.persistedValue.intValue
}
if (isNil(this.value) && !isNil(this.setting.intValue.default)) {
this.value = this.setting.intValue.default
}
this.initialValue = this.value
}
}
</script>
@@ -0,0 +1,125 @@
<template>
<div>
<oc-button :id="buttonElementId" class="uk-width-expand">
<span v-if="selectedOption">
{{ selectedOption.displayValue }}
</span>
<span v-else>
{{ setting.placeholder || $gettext('Please select') }}
</span>
</oc-button>
<oc-drop
:drop-id="dropElementId"
:toggle="`#${buttonElementId}`"
mode="click"
close-on-click
position="bottom-justify"
:options="{ offset: 0, delayHide: 200, flip: false }"
>
<ul class="uk-list">
<li
v-for="(option, index) in setting.singleChoiceValue.options"
:key="getOptionElementId(index)"
>
<label :for="getOptionElementId(index)">
<input
:id="getOptionElementId(index)"
type="radio"
class="oc-radiobutton"
v-model="selectedOption"
:value="option"
@change="onSelectedOption"
/>
{{ option.displayValue }}
</label>
</li>
</ul>
</oc-drop>
</div>
</template>
<script>
import isNil from 'lodash/isNil'
export default {
name: 'SettingSingleChoice',
props: {
bundle: {
type: Object,
required: true
},
setting: {
type: Object,
required: true
},
persistedValue: {
type: Object,
required: false
}
},
data () {
return {
selectedOption: null
}
},
computed: {
dropElementId () {
return `single-choice-drop-${this.setting.id}`
},
buttonElementId () {
return `single-choice-toggle-${this.setting.id}`
}
},
methods: {
getOptionElementId (index) {
return `${this.setting.id}-${index}`
},
async onSelectedOption () {
const values = []
if (!isNil(this.selectedOption)) {
if (this.selectedOption.value.intValue) {
values.push({ intValue: this.selectedOption.value.intValue })
}
if (this.selectedOption.value.stringValue) {
values.push({ stringValue: this.selectedOption.value.stringValue })
}
}
const payload = {
listValue: {
values
}
}
if (!isNil(this.persistedValue)) {
payload.id = this.persistedValue.id
}
await this.$emit('onSave', {
bundle: this.bundle,
setting: this.setting,
payload
})
// TODO: show a spinner while the request for saving the value is running!
}
},
mounted () {
if (!isNil(this.persistedValue) && !isNil(this.persistedValue.listValue)) {
const selected = this.persistedValue.listValue.values[0]
const filtered = this.setting.singleChoiceValue.options.filter(option => {
if (selected.intValue) {
return option.value.intValue === selected.intValue
} else {
return option.value.stringValue === selected.stringValue
}
})
if (filtered.length > 0) {
this.selectedOption = filtered[0]
}
}
// if not set, yet, apply default from settings bundle definition
if (isNil(this.selectedOption)) {
const defaults = this.setting.singleChoiceValue.options.filter(option => option.default)
if (defaults.length === 1) {
this.selectedOption = defaults[0]
}
}
}
}
</script>
@@ -0,0 +1,82 @@
<template>
<oc-grid flex>
<div class="uk-width-expand">
<oc-text-input
v-model="value"
:placeholder="setting.stringValue.placeholder"
:label="setting.description"
@keydown.enter="applyValue"
@keydown.esc="cancel"
/>
</div>
<div v-if="isChanged">
<oc-button @click="cancel" class="uk-margin-xsmall-left">
<translate>Cancel</translate>
</oc-button>
<oc-button @click="applyValue" class="uk-margin-xsmall-left" variation="primary">
<translate>Save</translate>
</oc-button>
</div>
</oc-grid>
</template>
<script>
import isNil from 'lodash/isNil'
export default {
name: 'SettingString',
props: {
bundle: {
type: Object,
required: true
},
setting: {
type: Object,
required: true
},
persistedValue: {
type: Object,
required: false
}
},
data () {
return {
initialValue: null,
value: null
}
},
computed: {
isChanged () {
return this.initialValue !== this.value
}
},
methods: {
async applyValue () {
const payload = {
stringValue: this.value
}
if (!isNil(this.persistedValue)) {
payload.id = this.persistedValue.id
}
await this.$emit('onSave', {
bundle: this.bundle,
setting: this.setting,
payload
})
// TODO: show a spinner while the request for saving the value is running!
this.initialValue = this.value
},
cancel () {
this.value = this.initialValue
}
},
mounted () {
if (!isNil(this.persistedValue)) {
this.value = this.persistedValue.stringValue
}
if (isNil(this.value) && !isNil(this.setting.stringValue.default)) {
this.value = this.setting.stringValue.default
}
this.initialValue = this.value
}
}
</script>
@@ -0,0 +1,25 @@
<template>
<div>
<translate :translate-params="{ type: setting.type }">Settings type not implemented: %{type}</translate>
</div>
</template>
<script>
export default {
name: 'SettingUnknown',
props: {
bundle: {
type: Object,
required: true
},
setting: {
type: Object,
required: true
},
persistedValue: {
type: Object,
required: false
}
}
}
</script>