Add user edit/new dialog
This commit is contained in:
@@ -26,6 +26,7 @@ const allApps = ref([]);
|
||||
|
||||
async function onSubmit() {
|
||||
busy.value = true;
|
||||
formError.value = '';
|
||||
|
||||
if (group.value) {
|
||||
const [error] = await groupsModel.update(group.value.id, name.value, users.value.map(u => u.id), apps.value.map(u => u.id));
|
||||
@@ -82,12 +83,12 @@ defineExpose({
|
||||
@confirm="onSubmit()"
|
||||
>
|
||||
<p class="text-warning" v-if="group?.source">{{ $t('users.editGroupDialog.externalLdapWarning') }}</p>
|
||||
<form @submit.prevent="onSubmit()">
|
||||
<form @submit.prevent="onSubmit()" autocomplete="off">
|
||||
<fieldset :disabled="busy">
|
||||
<input type="submit" style="display: none;" />
|
||||
|
||||
<FormGroup>
|
||||
<label for="">{{ $t('users.group.name') }}</label>
|
||||
<label for="nameInput">{{ $t('users.group.name') }}</label>
|
||||
<TextInput id="nameInput" v-model="name" />
|
||||
</FormGroup>
|
||||
|
||||
|
||||
220
dashboard/src/components/UserDialog.vue
Normal file
220
dashboard/src/components/UserDialog.vue
Normal file
@@ -0,0 +1,220 @@
|
||||
<script setup>
|
||||
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const i18n = useI18n();
|
||||
const t = i18n.t;
|
||||
|
||||
import { ref, useTemplateRef } from 'vue';
|
||||
import { Dialog, TextInput, FormGroup, Checkbox, MultiSelect, SingleSelect } from 'pankow';
|
||||
import { ROLES } from '../constants.js';
|
||||
import ProfileModel from '../models/ProfileModel.js';
|
||||
import UsersModel from '../models/UsersModel.js';
|
||||
import GroupsModel from '../models/GroupsModel.js';
|
||||
|
||||
const profileModel = ProfileModel.create();
|
||||
const usersModel = UsersModel.create();
|
||||
const groupsModel = GroupsModel.create();
|
||||
|
||||
const emit = defineEmits([ 'success' ]);
|
||||
|
||||
const dialog = useTemplateRef('dialog');
|
||||
|
||||
// also determines if new or edit mode
|
||||
const user = ref(null);
|
||||
const roles = ref([]);
|
||||
const profile = ref({});
|
||||
const busy = ref(false);
|
||||
const profileLocked = ref(false); // TODO
|
||||
const formError = ref({});
|
||||
const displayName = ref('');
|
||||
const email = ref('');
|
||||
const fallbackEmail = ref('');
|
||||
const username = ref('');
|
||||
const role = ref('');
|
||||
const groups = ref([]);
|
||||
const localGroups = ref([]);
|
||||
const allGroups = ref([]);
|
||||
const allLocalGroups = ref([]);
|
||||
const active = ref(true);
|
||||
const sendInvite = ref(false);
|
||||
|
||||
async function onSubmit() {
|
||||
busy.value = true;
|
||||
formError.value = {};
|
||||
|
||||
const data = {
|
||||
email: email.value,
|
||||
fallbackEmail: fallbackEmail.value,
|
||||
displayName: displayName.value,
|
||||
role: role.value
|
||||
};
|
||||
|
||||
// can only be set not updated
|
||||
if (!user.value) data.username = username.value || null;
|
||||
|
||||
let error, result;
|
||||
if (user.value) [error, result] = await usersModel.update(user.value.id, data);
|
||||
else [error, result] = await usersModel.add(data);
|
||||
if (error) {
|
||||
const message = error.body ? error.body.message : '';
|
||||
if (error.status === 409) {
|
||||
if (message.toLowerCase().indexOf('email') !== -1) {
|
||||
formError.value.email = 'Email already taken';
|
||||
} else if (message.toLowerCase().indexOf('username') !== -1 || message.toLowerCase().indexOf('mailbox') !== -1) {
|
||||
formError.value.username = 'Username already taken';
|
||||
} else {
|
||||
// should not happen!!
|
||||
console.error(message);
|
||||
}
|
||||
} else if (error.status === 400) {
|
||||
if (message.toLowerCase().indexOf('email') !== -1) {
|
||||
formError.value.email = 'Invalid Email';
|
||||
formError.value.emailAttempted = email.value;
|
||||
} else if (message.toLowerCase().indexOf('username') !== -1) {
|
||||
formError.value.username = message;
|
||||
} else {
|
||||
// should not happen!!
|
||||
console.error(error);
|
||||
}
|
||||
} else {
|
||||
console.error(error);
|
||||
}
|
||||
busy.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = user.value ? user.value.id : result.id;
|
||||
|
||||
// TODO edit does not support role setting for some reason
|
||||
if (user.value) {
|
||||
const [error] = await usersModel.setRole(userId, role.value);
|
||||
if (error) {
|
||||
busy.value = false;
|
||||
return console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
const [activeError] = await usersModel.setActive(userId, active.value);
|
||||
if (activeError) {
|
||||
busy.value = false;
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
const [groupError] = await usersModel.setLocalGroups(userId, localGroups.value.map(g => g.id));
|
||||
if (groupError) {
|
||||
busy.value = false;
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
if (sendInvite.value) {
|
||||
const [error] = await usersModel.sendInviteEmail(userId, email.value);
|
||||
if (error) {
|
||||
busy.value = false;
|
||||
return console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
emit('success');
|
||||
dialog.value.close();
|
||||
busy.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
async open(u = null) {
|
||||
busy.value = false;
|
||||
formError.value = {};
|
||||
user.value = u;
|
||||
displayName.value = u ? u.displayName : '';
|
||||
email.value = u ? u.email : '';
|
||||
fallbackEmail.value = u ? u.fallbackEmail : '';
|
||||
username.value = u ? u.username : '';
|
||||
role.value = u ? u.role : ROLES.USER;
|
||||
sendInvite.value = false;
|
||||
active.value = u ? u.active : true;
|
||||
|
||||
let [error, result] = await groupsModel.list();
|
||||
if (error) return console.error(error);
|
||||
result.forEach(g => g.label = g.name);
|
||||
allGroups.value = result;
|
||||
allLocalGroups.value = result.filter(g => !g.source);
|
||||
groups.value = u ? u.groupIds.map(id => { return result.find(g => g.id === id); }) : [];
|
||||
localGroups.value = (u ? u.groupIds.map(id => { return result.find(g => g.id === id); }) : []).filter(g => !g.source);
|
||||
|
||||
[error, result] = await profileModel.get();
|
||||
if (error) return console.error(error);
|
||||
profile.value = result;
|
||||
|
||||
roles.value = [
|
||||
{ id: ROLES.USER, name: t('users.role.user'), disabled: false },
|
||||
{ id: ROLES.USER_MANAGER, name: t('users.role.usermanager'), disabled: false },
|
||||
{ id: ROLES.MAIL_MANAGER, name: t('users.role.mailmanager'), disabled: false },
|
||||
{ id: ROLES.ADMIN, name: t('users.role.admin'), disabled: !profile.value.isAtLeastAdmin },
|
||||
{ id: ROLES.OWNER, name: t('users.role.owner'), disabled: !profile.value.isAtLeastOwner }
|
||||
];
|
||||
|
||||
dialog.value.open();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog ref="dialog"
|
||||
:title="user ? $t('users.editUserDialog.title', { username: (user.username || user.email) }) : $t('users.addUserDialog.title')"
|
||||
:confirm-label="user ? $t('main.dialog.save') : $t('users.addUserDialog.addUserAction')"
|
||||
:confirm-busy="busy"
|
||||
:confirm-active="!busy"
|
||||
reject-style="secondary"
|
||||
:reject-label="busy ? null : $t('main.dialog.cancel')"
|
||||
@confirm="onSubmit()"
|
||||
>
|
||||
<div v-if="user && user.source">
|
||||
<p class="text-warning">{{ $t('users.editUserDialog.externalLdapWarning') }}</p>
|
||||
<p><label>{{ $t('users.user.displayName') }}</label><br/><TextInput :disabled="true" v-model="user.displayName" /></p>
|
||||
<p><label>{{ $t('users.user.email') }}</label><br/><TextInput :disabled="true" v-model="user.email" /></p>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="onSubmit()" autocomplete="off">
|
||||
<fieldset :disabled="busy">
|
||||
<input type="submit" style="display: none;" />
|
||||
|
||||
<FormGroup>
|
||||
<label for="displayNameInput">{{ $t('users.user.fullName') }}</label>
|
||||
<TextInput id="displayNameInput" v-model="displayName" :placeholder="$t('users.user.displayNamePlaceholder')"/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<label for="emailInput">{{ $t('users.user.primaryEmail') }} <sup><a href="https://docs.cloudron.io/profile/#primary-email" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<TextInput id="emailInput" v-model="email" required />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<label for="fallbackEmailInput">{{ $t('users.user.recoveryEmail') }} <sup><a href="https://docs.cloudron.io/profile/#password-recovery-email" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<TextInput id="fallbackEmailInput" v-model="fallbackEmail" :placeholder="$t('users.user.fallbackEmailPlaceholder')" />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup v-if="!user">
|
||||
<label for="usernameInput">{{ $t('users.user.username') }}</label>
|
||||
<TextInput id="usernameInput" v-model="username" :placeholder="profileLocked ? '' : $t('users.user.usernamePlaceholder')" />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup v-if="profile.isAtLeastAdmin">
|
||||
<label for="roleInput">{{ $t('users.user.role') }} <sup><a href="https://docs.cloudron.io/user-management/#roles" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<SingleSelect id="roleInput" v-model="role" :options="roles" option-key="id" option-label="name" />
|
||||
</FormGroup>
|
||||
|
||||
<!-- local groups. they can have local and external users -->
|
||||
<FormGroup>
|
||||
<label for="groupsInput">{{ $t('users.user.groups') }}</label>
|
||||
<div v-if="allGroups.length === 0">{{ $t('users.user.noGroups') }}</div>
|
||||
<MultiSelect v-if="allLocalGroups.length" v-model="localGroups" :options="allLocalGroups" />
|
||||
</FormGroup>
|
||||
|
||||
<br/>
|
||||
|
||||
<Checkbox v-model="active" :label="$t('users.user.activeCheckbox')" /><sup><a href="https://docs.cloudron.io/user-management/#disable-user" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup>
|
||||
<Checkbox v-if="!user" v-model="sendInvite" :label="$t('users.addUserDialog.sendInviteCheckbox')" />
|
||||
</fieldset>
|
||||
</form>
|
||||
</Dialog>
|
||||
</template>
|
||||
Reference in New Issue
Block a user