parent
de6e55075b
commit
44763576b1
@ -0,0 +1,78 @@ |
||||
<!-- |
||||
- @copyright 2021, Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @author Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @license GNU AGPL version 3 or any later version |
||||
- |
||||
- This program is free software: you can redistribute it and/or modify |
||||
- it under the terms of the GNU Affero General Public License as |
||||
- published by the Free Software Foundation, either version 3 of the |
||||
- License, or (at your option) any later version. |
||||
- |
||||
- This program is distributed in the hope that it will be useful, |
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
- GNU Affero General Public License for more details. |
||||
- |
||||
- You should have received a copy of the GNU Affero General Public License |
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
|
||||
<template> |
||||
<button |
||||
:disabled="disabled" |
||||
@click.stop.prevent="onClick"> |
||||
<span class="icon icon-add" /> |
||||
{{ t('settings', 'Add') }} |
||||
</button> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: 'AddButton', |
||||
|
||||
props: { |
||||
disabled: { |
||||
type: Boolean, |
||||
default: true, |
||||
}, |
||||
}, |
||||
|
||||
methods: { |
||||
onClick(e) { |
||||
this.$emit('click', e) |
||||
}, |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
button { |
||||
height: 44px; |
||||
padding: 0 16px; |
||||
border: none; |
||||
background-color: transparent; |
||||
|
||||
&:hover { |
||||
background-color: rgba(127, 127, 127, .15); |
||||
} |
||||
|
||||
&:enabled { |
||||
opacity: 0.4 !important; |
||||
|
||||
.icon { |
||||
opacity: 0.8 !important; |
||||
} |
||||
} |
||||
|
||||
&:enabled:hover { |
||||
background-color: rgba(127, 127, 127, .25); |
||||
opacity: 0.8 !important; |
||||
} |
||||
|
||||
.icon { |
||||
margin-right: 8px; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,323 @@ |
||||
<!-- |
||||
- @copyright 2021, Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @author Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @license GNU AGPL version 3 or any later version |
||||
- |
||||
- This program is free software: you can redistribute it and/or modify |
||||
- it under the terms of the GNU Affero General Public License as |
||||
- published by the Free Software Foundation, either version 3 of the |
||||
- License, or (at your option) any later version. |
||||
- |
||||
- This program is distributed in the hope that it will be useful, |
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
- GNU Affero General Public License for more details. |
||||
- |
||||
- You should have received a copy of the GNU Affero General Public License |
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
|
||||
<template> |
||||
<div> |
||||
<div class="email-container"> |
||||
<input |
||||
ref="email" |
||||
type="email" |
||||
:name="inputName" |
||||
:placeholder="inputPlaceholder" |
||||
:value="email" |
||||
autocapitalize="none" |
||||
autocomplete="on" |
||||
autocorrect="off" |
||||
required="true" |
||||
@input="onEmailChange"> |
||||
|
||||
<div class="email-actions-container"> |
||||
<transition name="fade"> |
||||
<span v-if="showCheckmarkIcon" class="icon-checkmark" /> |
||||
<span v-else-if="showErrorIcon" class="icon-error" /> |
||||
</transition> |
||||
|
||||
<FederationControl v-if="!primary" |
||||
class="federation-control" |
||||
:disabled="federationDisabled" |
||||
:email="email" |
||||
:scope.sync="localScope" |
||||
@update:scope="onScopeChange" /> |
||||
|
||||
<Actions |
||||
class="actions-email" |
||||
:aria-label="t('settings', 'Email options')" |
||||
:disabled="deleteDisabled" |
||||
:force-menu="true"> |
||||
<ActionButton |
||||
:aria-label="deleteEmailLabel" |
||||
:close-after-click="true" |
||||
icon="icon-delete" |
||||
@click.stop.prevent="deleteEmail"> |
||||
{{ deleteEmailLabel }} |
||||
</ActionButton> |
||||
</Actions> |
||||
</div> |
||||
</div> |
||||
|
||||
<em v-if="primary"> |
||||
{{ t('settings', 'Primary email for password reset and notifications') }} |
||||
</em> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Actions from '@nextcloud/vue/dist/Components/Actions' |
||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' |
||||
import { showError } from '@nextcloud/dialogs' |
||||
import debounce from 'debounce' |
||||
|
||||
import FederationControl from './FederationControl' |
||||
import { savePrimaryEmail, saveAdditionalEmail, updateAdditionalEmail, removeAdditionalEmail } from '../../../service/PersonalInfoService' |
||||
|
||||
export default { |
||||
name: 'Email', |
||||
|
||||
components: { |
||||
Actions, |
||||
ActionButton, |
||||
FederationControl, |
||||
}, |
||||
|
||||
props: { |
||||
email: { |
||||
type: String, |
||||
required: true, |
||||
}, |
||||
scope: { |
||||
type: String, |
||||
required: true, |
||||
}, |
||||
primary: { |
||||
type: Boolean, |
||||
default: false, |
||||
}, |
||||
index: { |
||||
type: Number, |
||||
default: 0, |
||||
}, |
||||
}, |
||||
|
||||
data() { |
||||
return { |
||||
initialEmail: this.email, |
||||
localScope: this.scope, |
||||
showCheckmarkIcon: false, |
||||
showErrorIcon: false, |
||||
} |
||||
}, |
||||
|
||||
computed: { |
||||
inputName() { |
||||
if (this.primary) { |
||||
return 'email' |
||||
} |
||||
return 'additionalEmail[]' |
||||
}, |
||||
|
||||
inputPlaceholder() { |
||||
if (this.primary) { |
||||
return t('settings', 'Your email address') |
||||
} |
||||
return t('settings', 'Additional email address {index}', { index: this.index + 1 }) |
||||
}, |
||||
|
||||
federationDisabled() { |
||||
return !this.initialEmail |
||||
}, |
||||
|
||||
deleteDisabled() { |
||||
return !this.containsNoWhitespace(this.email) |
||||
}, |
||||
|
||||
deleteEmailLabel() { |
||||
if (this.primary) { |
||||
return t('settings', 'Remove primary email') |
||||
} |
||||
return t('settings', 'Delete email') |
||||
}, |
||||
}, |
||||
|
||||
methods: { |
||||
onEmailChange(e) { |
||||
this.$emit('update:email', e.target.value) |
||||
// $nextTick() ensures that references to this.email further down the chain give the correct non-outdated value |
||||
this.$nextTick(() => this.debounceEmailChange()) |
||||
}, |
||||
|
||||
debounceEmailChange: debounce(async function() { |
||||
if ((this.$refs.email?.checkValidity() && this.containsNoWhitespace(this.email)) || this.email === '') { |
||||
if (this.primary) { |
||||
await this.updatePrimaryEmail() |
||||
} else { |
||||
if (this.initialEmail && this.email === '') { |
||||
await this.deleteAdditionalEmail() |
||||
} else if (this.initialEmail === '') { |
||||
await this.addAdditionalEmail() |
||||
} else { |
||||
await this.updateAdditionalEmail() |
||||
} |
||||
} |
||||
} |
||||
}, 500), |
||||
|
||||
async deleteEmail() { |
||||
if (this.primary) { |
||||
this.$emit('update:email', '') |
||||
this.$nextTick(async() => await this.updatePrimaryEmail()) |
||||
} else { |
||||
await this.deleteAdditionalEmail() |
||||
} |
||||
}, |
||||
|
||||
async updatePrimaryEmail() { |
||||
try { |
||||
const responseData = await savePrimaryEmail(this.email) |
||||
this.handleResponse(responseData.ocs?.meta?.status) |
||||
} catch (e) { |
||||
if (this.email === '') { |
||||
this.handleResponse('error', 'Unable to delete primary email address', e) |
||||
} else { |
||||
this.handleResponse('error', 'Unable to update primary email address', e) |
||||
} |
||||
} |
||||
}, |
||||
|
||||
async addAdditionalEmail() { |
||||
try { |
||||
const responseData = await saveAdditionalEmail(this.email) |
||||
this.handleResponse(responseData.ocs?.meta?.status) |
||||
} catch (e) { |
||||
this.handleResponse('error', 'Unable to add additional email address', e) |
||||
} |
||||
}, |
||||
|
||||
async updateAdditionalEmail() { |
||||
try { |
||||
const responseData = await updateAdditionalEmail(this.initialEmail, this.email) |
||||
this.handleResponse(responseData.ocs?.meta?.status) |
||||
} catch (e) { |
||||
this.handleResponse('error', 'Unable to update additional email address', e) |
||||
} |
||||
}, |
||||
|
||||
async deleteAdditionalEmail() { |
||||
try { |
||||
const responseData = await removeAdditionalEmail(this.initialEmail) |
||||
this.handleDeleteAdditionalEmail(responseData.ocs?.meta?.status) |
||||
} catch (e) { |
||||
this.handleResponse('error', 'Unable to delete additional email address', e) |
||||
} |
||||
}, |
||||
|
||||
containsNoWhitespace(string) { |
||||
return /^\S+$/.test(string) |
||||
}, |
||||
|
||||
handleDeleteAdditionalEmail(status) { |
||||
if (status === 'ok') { |
||||
this.$emit('deleteAdditionalEmail') |
||||
} else { |
||||
this.handleResponse('error', 'Unable to delete additional email address', {}) |
||||
} |
||||
}, |
||||
|
||||
handleResponse(status, errorMessage, error) { |
||||
if (status === 'ok') { |
||||
// Ensure that local initialEmail state reflects server state |
||||
this.initialEmail = this.email |
||||
this.showCheckmarkIcon = true |
||||
setTimeout(() => { this.showCheckmarkIcon = false }, 2000) |
||||
} else { |
||||
showError(t('settings', errorMessage)) |
||||
this.logger.error(errorMessage, error) |
||||
this.showErrorIcon = true |
||||
setTimeout(() => { this.showErrorIcon = false }, 2000) |
||||
} |
||||
}, |
||||
|
||||
onScopeChange(scope) { |
||||
this.$emit('update:scope', scope) |
||||
}, |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.email-container { |
||||
display: grid; |
||||
align-items: center; |
||||
|
||||
input[type=email] { |
||||
grid-area: 1 / 1; |
||||
} |
||||
|
||||
.email-actions-container { |
||||
grid-area: 1 / 1; |
||||
justify-self: flex-end; |
||||
height: 30px; |
||||
|
||||
display: flex; |
||||
gap: 0 2px; |
||||
margin-right: 5px; |
||||
|
||||
.actions-email { |
||||
opacity: 0.4 !important; |
||||
|
||||
&:hover { |
||||
opacity: 0.8 !important; |
||||
} |
||||
|
||||
&::v-deep button { |
||||
height: 30px !important; |
||||
min-height: 30px !important; |
||||
width: 30px !important; |
||||
min-width: 30px !important; |
||||
} |
||||
} |
||||
|
||||
.federation-control { |
||||
&::v-deep button { |
||||
// TODO remove this hack |
||||
padding-bottom: 7px; |
||||
height: 30px !important; |
||||
min-height: 30px !important; |
||||
width: 30px !important; |
||||
min-width: 30px !important; |
||||
} |
||||
} |
||||
|
||||
.icon-checkmark, |
||||
.icon-error { |
||||
height: 30px !important; |
||||
min-height: 30px !important; |
||||
width: 30px !important; |
||||
min-width: 30px !important; |
||||
top: 0; |
||||
right: 0; |
||||
float: none; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.fade-enter-active { |
||||
transition: opacity 200ms ease-out; |
||||
} |
||||
|
||||
.fade-leave-active { |
||||
transition: opacity 300ms ease-out; |
||||
} |
||||
|
||||
.fade-enter, |
||||
.fade-leave-to { |
||||
opacity: 0; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,117 @@ |
||||
<!-- |
||||
- @copyright 2021, Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @author Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @license GNU AGPL version 3 or any later version |
||||
- |
||||
- This program is free software: you can redistribute it and/or modify |
||||
- it under the terms of the GNU Affero General Public License as |
||||
- published by the Free Software Foundation, either version 3 of the |
||||
- License, or (at your option) any later version. |
||||
- |
||||
- This program is distributed in the hope that it will be useful, |
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
- GNU Affero General Public License for more details. |
||||
- |
||||
- You should have received a copy of the GNU Affero General Public License |
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
|
||||
<template> |
||||
<form |
||||
ref="form" |
||||
class="section" |
||||
@submit.stop.prevent="() => {}"> |
||||
<HeaderBar |
||||
:can-edit-emails="isDisplayNameChangeSupported" |
||||
:is-valid-form="isValidForm" |
||||
:scope.sync="primaryEmail.scope" |
||||
@addAdditionalEmail="onAddAdditionalEmail" /> |
||||
|
||||
<template v-if="isDisplayNameChangeSupported"> |
||||
<Email |
||||
:primary="true" |
||||
:scope.sync="primaryEmail.scope" |
||||
:email.sync="primaryEmail.value" |
||||
@update:email="updateFormValidity" /> |
||||
<Email v-for="(additionalEmail, index) in additionalEmails" |
||||
:key="index" |
||||
:index="index" |
||||
:scope.sync="additionalEmail.scope" |
||||
:email.sync="additionalEmail.value" |
||||
@update:email="updateFormValidity" |
||||
@deleteAdditionalEmail="onDeleteAdditionalEmail(index)" /> |
||||
</template> |
||||
|
||||
<span v-else> |
||||
{{ primaryEmail.value || t('settings', 'No email address set') }} |
||||
</span> |
||||
</form> |
||||
</template> |
||||
|
||||
<script> |
||||
import { loadState } from '@nextcloud/initial-state' |
||||
import '@nextcloud/dialogs/styles/toast.scss' |
||||
|
||||
import HeaderBar from './HeaderBar' |
||||
import Email from './Email' |
||||
import { DEFAULT_ADDITIONAL_EMAIL_SCOPE } from '../../../constants/AccountPropertyConstants' |
||||
|
||||
const { additionalEmails, primaryEmail } = loadState('settings', 'emails', {}) |
||||
const accountParams = loadState('settings', 'accountParameters', {}) |
||||
|
||||
export default { |
||||
name: 'EmailSection', |
||||
|
||||
components: { |
||||
HeaderBar, |
||||
Email, |
||||
}, |
||||
|
||||
data() { |
||||
return { |
||||
accountParams, |
||||
additionalEmails, |
||||
primaryEmail, |
||||
isValidForm: true, |
||||
} |
||||
}, |
||||
|
||||
computed: { |
||||
isDisplayNameChangeSupported() { |
||||
return this.accountParams.displayNameChangeSupported |
||||
}, |
||||
}, |
||||
|
||||
mounted() { |
||||
this.$nextTick(() => this.updateFormValidity()) |
||||
}, |
||||
|
||||
methods: { |
||||
onAddAdditionalEmail() { |
||||
if (this.$refs.form?.checkValidity()) { |
||||
this.additionalEmails.push({ value: '', scope: DEFAULT_ADDITIONAL_EMAIL_SCOPE }) |
||||
this.$nextTick(() => this.updateFormValidity()) |
||||
} |
||||
}, |
||||
|
||||
onDeleteAdditionalEmail(index) { |
||||
this.$delete(this.additionalEmails, index) |
||||
}, |
||||
|
||||
updateFormValidity() { |
||||
this.isValidForm = this.$refs.form?.checkValidity() |
||||
}, |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
form::v-deep button { |
||||
&:disabled { |
||||
cursor: default; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,160 @@ |
||||
<!-- |
||||
- @copyright 2021, Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @author Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @license GNU AGPL version 3 or any later version |
||||
- |
||||
- This program is free software: you can redistribute it and/or modify |
||||
- it under the terms of the GNU Affero General Public License as |
||||
- published by the Free Software Foundation, either version 3 of the |
||||
- License, or (at your option) any later version. |
||||
- |
||||
- This program is distributed in the hope that it will be useful, |
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
- GNU Affero General Public License for more details. |
||||
- |
||||
- You should have received a copy of the GNU Affero General Public License |
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
|
||||
<template> |
||||
<Actions |
||||
class="actions-federation" |
||||
:aria-label="t('settings', 'Change privacy level of email')" |
||||
:default-icon="scopeIcon" |
||||
:disabled="disabled"> |
||||
<ActionButton v-for="federationScope in federationScopes" |
||||
:key="federationScope.name" |
||||
class="forced-action" |
||||
:class="{ 'forced-active': scope === federationScope.name }" |
||||
:aria-label="federationScope.tooltip" |
||||
:close-after-click="true" |
||||
:icon="federationScope.iconClass" |
||||
:title="federationScope.displayName" |
||||
@click.stop.prevent="changeScope(federationScope.name)"> |
||||
{{ federationScope.tooltip }} |
||||
</ActionButton> |
||||
</Actions> |
||||
</template> |
||||
|
||||
<script> |
||||
import Actions from '@nextcloud/vue/dist/Components/Actions' |
||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' |
||||
import { showError } from '@nextcloud/dialogs' |
||||
|
||||
import { SCOPE_ENUM, SCOPE_PROPERTY_ENUM } from '../../../constants/AccountPropertyConstants' |
||||
import { savePrimaryEmailScope, saveAdditionalEmailScope } from '../../../service/PersonalInfoService' |
||||
|
||||
// TODO hardcoded for email, should abstract this for other sections |
||||
const excludedScopes = [SCOPE_ENUM.PRIVATE] |
||||
|
||||
export default { |
||||
name: 'FederationControl', |
||||
|
||||
components: { |
||||
Actions, |
||||
ActionButton, |
||||
}, |
||||
|
||||
props: { |
||||
primary: { |
||||
type: Boolean, |
||||
default: false, |
||||
}, |
||||
email: { |
||||
type: String, |
||||
default: '', |
||||
}, |
||||
scope: { |
||||
type: String, |
||||
required: true, |
||||
}, |
||||
disabled: { |
||||
type: Boolean, |
||||
default: false, |
||||
}, |
||||
}, |
||||
|
||||
data() { |
||||
return { |
||||
initialScope: this.scope, |
||||
federationScopes: Object.values(SCOPE_PROPERTY_ENUM).filter(({ name }) => !excludedScopes.includes(name)), |
||||
} |
||||
}, |
||||
|
||||
computed: { |
||||
scopeIcon() { |
||||
return SCOPE_PROPERTY_ENUM[this.scope].iconClass |
||||
}, |
||||
}, |
||||
|
||||
methods: { |
||||
async changeScope(scope) { |
||||
this.$emit('update:scope', scope) |
||||
|
||||
this.$nextTick(async() => { |
||||
if (this.primary) { |
||||
await this.updatePrimaryEmailScope() |
||||
} else { |
||||
await this.updateAdditionalEmailScope() |
||||
} |
||||
}) |
||||
}, |
||||
|
||||
async updatePrimaryEmailScope() { |
||||
try { |
||||
const responseData = await savePrimaryEmailScope(this.scope) |
||||
this.handleResponse(responseData.ocs?.meta?.status) |
||||
} catch (e) { |
||||
this.handleResponse('error', 'Unable to update federation scope of the primary email', e) |
||||
} |
||||
}, |
||||
|
||||
async updateAdditionalEmailScope() { |
||||
try { |
||||
const responseData = await saveAdditionalEmailScope(this.email, this.scope) |
||||
this.handleResponse(responseData.ocs?.meta?.status) |
||||
} catch (e) { |
||||
this.handleResponse('error', 'Unable to update federation scope of additional email', e) |
||||
} |
||||
}, |
||||
|
||||
handleResponse(status, errorMessage, error) { |
||||
if (status === 'ok') { |
||||
this.initialScope = this.scope |
||||
} else { |
||||
this.$emit('update:scope', this.initialScope) |
||||
showError(t('settings', errorMessage)) |
||||
this.logger.error(errorMessage, error) |
||||
} |
||||
}, |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.actions-federation { |
||||
opacity: 0.4 !important; |
||||
|
||||
&:hover { |
||||
opacity: 0.8 !important; |
||||
} |
||||
} |
||||
|
||||
.forced-active { |
||||
background-color: var(--color-primary-light) !important; |
||||
box-shadow: inset 2px 0 var(--color-primary) !important; |
||||
} |
||||
|
||||
.forced-action { |
||||
&::v-deep p { |
||||
width: 150px !important; |
||||
padding: 8px 0 !important; |
||||
color: var(--color-main-text) !important; |
||||
font-size: 12.8px !important; |
||||
line-height: 1.5em !important; |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,94 @@ |
||||
<!-- |
||||
- @copyright 2021, Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @author Christopher Ng <chrng8@gmail.com> |
||||
- |
||||
- @license GNU AGPL version 3 or any later version |
||||
- |
||||
- This program is free software: you can redistribute it and/or modify |
||||
- it under the terms of the GNU Affero General Public License as |
||||
- published by the Free Software Foundation, either version 3 of the |
||||
- License, or (at your option) any later version. |
||||
- |
||||
- This program is distributed in the hope that it will be useful, |
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
- GNU Affero General Public License for more details. |
||||
- |
||||
- You should have received a copy of the GNU Affero General Public License |
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
|
||||
<template> |
||||
<h3> |
||||
<label for="email"> |
||||
{{ t('settings', 'Email') }} |
||||
</label> |
||||
|
||||
<FederationControl |
||||
class="federation-control" |
||||
:primary="true" |
||||
:scope.sync="localScope" |
||||
@update:scope="onScopeChange" /> |
||||
|
||||
<AddButton v-if="canEditEmails" |
||||
class="add-button" |
||||
:disabled="!isValidForm" |
||||
@click.stop.prevent="addAdditionalEmail" /> |
||||
</h3> |
||||
</template> |
||||
|
||||
<script> |
||||
import FederationControl from './FederationControl' |
||||
import AddButton from './AddButton' |
||||
|
||||
export default { |
||||
name: 'HeaderBar', |
||||
|
||||
components: { |
||||
FederationControl, |
||||
AddButton, |
||||
}, |
||||
|
||||
props: { |
||||
canEditEmails: { |
||||
type: Boolean, |
||||
default: true, |
||||
}, |
||||
isValidForm: { |
||||
type: Boolean, |
||||
default: true, |
||||
}, |
||||
scope: { |
||||
type: String, |
||||
required: true, |
||||
}, |
||||
}, |
||||
|
||||
data() { |
||||
return { |
||||
localScope: this.scope, |
||||
} |
||||
}, |
||||
|
||||
methods: { |
||||
addAdditionalEmail() { |
||||
this.$emit('addAdditionalEmail') |
||||
}, |
||||
|
||||
onScopeChange(scope) { |
||||
this.$emit('update:scope', scope) |
||||
}, |
||||
}, |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.federation-control { |
||||
margin: -12px 0 0 8px; |
||||
} |
||||
|
||||
.add-button { |
||||
margin: -12px 0 0 auto !important; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,38 @@ |
||||
/** |
||||
* @copyright 2021, Christopher Ng <chrng8@gmail.com> |
||||
* |
||||
* @author Christopher Ng <chrng8@gmail.com> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
import Vue from 'vue' |
||||
|
||||
import logger from './logger' |
||||
|
||||
import EmailSection from './components/PersonalInfo/EmailSection/EmailSection' |
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
__webpack_nonce__ = btoa(OC.requestToken) |
||||
|
||||
Vue.prototype.t = t |
||||
Vue.prototype.logger = logger |
||||
|
||||
const View = Vue.extend(EmailSection) |
||||
export default new View({ |
||||
el: '#vue-emailsection', |
||||
}) |
||||
Loading…
Reference in new issue