diff --git a/modules/account/front/descriptor-popover/index.html b/modules/account/front/descriptor-popover/index.html
new file mode 100644
index 000000000..f3131a84b
--- /dev/null
+++ b/modules/account/front/descriptor-popover/index.html
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/modules/account/front/descriptor-popover/index.js b/modules/account/front/descriptor-popover/index.js
new file mode 100644
index 000000000..d7b052473
--- /dev/null
+++ b/modules/account/front/descriptor-popover/index.js
@@ -0,0 +1,9 @@
+import ngModule from '../module';
+import DescriptorPopover from 'salix/components/descriptor-popover';
+
+class Controller extends DescriptorPopover {}
+
+ngModule.vnComponent('vnAccountDescriptorPopover', {
+ slotTemplate: require('./index.html'),
+ controller: Controller
+});
diff --git a/modules/account/front/descriptor/index.html b/modules/account/front/descriptor/index.html
new file mode 100644
index 000000000..86e78dfce
--- /dev/null
+++ b/modules/account/front/descriptor/index.html
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+ Delete
+
+
+ Change password
+
+
+ Set password
+
+
+ Enable account
+
+
+ Disable account
+
+
+ Activate user
+
+
+ Deactivate user
+
+
+ Synchronize
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Do you want to synchronize user?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/account/front/descriptor/index.js b/modules/account/front/descriptor/index.js
new file mode 100644
index 000000000..de41d619d
--- /dev/null
+++ b/modules/account/front/descriptor/index.js
@@ -0,0 +1,145 @@
+import ngModule from '../module';
+import Descriptor from 'salix/components/descriptor';
+import UserError from 'core/lib/user-error';
+
+class Controller extends Descriptor {
+ get user() {
+ return this.entity;
+ }
+
+ set user(value) {
+ this.entity = value;
+ }
+
+ get entity() {
+ return super.entity;
+ }
+
+ set entity(value) {
+ super.entity = value;
+ this.hasAccount = null;
+ if (!value) return;
+
+ this.$http.get(`Accounts/${value.id}/exists`)
+ .then(res => this.hasAccount = res.data.exists);
+ }
+
+ loadData() {
+ const filter = {
+ where: {id: this.$params.id},
+ include: {
+ relation: 'role',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ };
+
+ return Promise.all([
+ this.$http.get(`VnUsers/preview`, {filter})
+ .then(res => {
+ const [user] = res.data;
+ this.user = user;
+ }),
+ this.$http.get(`Accounts/${this.$params.id}/exists`)
+ .then(res => this.hasAccount = res.data.exists)
+ ]);
+ }
+
+ onDelete() {
+ return this.$http.delete(`VnUsers/${this.id}`)
+ .then(() => this.$state.go('account.index'))
+ .then(() => this.vnApp.showSuccess(this.$t('User removed')));
+ }
+
+ onChangePassClick(askOldPass) {
+ this.$http.get('UserPasswords/findOne')
+ .then(res => {
+ this.passRequirements = res.data;
+ this.askOldPass = askOldPass;
+ this.$.changePass.show();
+ });
+ }
+
+ onPassChange() {
+ if (!this.newPassword)
+ throw new UserError(`You must enter a new password`);
+ if (this.newPassword != this.repeatPassword)
+ throw new UserError(`Passwords don't match`);
+
+ let method;
+ const params = {newPassword: this.newPassword};
+
+ if (this.askOldPass) {
+ method = 'change-password';
+ params.oldPassword = this.oldPassword;
+ } else
+ method = 'setPassword';
+
+ return this.$http.patch(`Accounts/${this.id}/${method}`, params)
+ .then(() => {
+ this.emit('change');
+ this.vnApp.showSuccess(this.$t('Password changed succesfully!'));
+ });
+ }
+
+ onPassClose() {
+ this.oldPassword = '';
+ this.newPassword = '';
+ this.repeatPassword = '';
+ this.$.$apply();
+ }
+
+ onEnableAccount() {
+ return this.$http.post(`Accounts`, {id: this.id})
+ .then(() => this.onSwitchAccount(true));
+ }
+
+ onDisableAccount() {
+ return this.$http.delete(`Accounts/${this.id}`)
+ .then(() => this.onSwitchAccount(false));
+ }
+
+ onSwitchAccount(enable) {
+ this.hasAccount = enable;
+ const message = enable
+ ? 'Account enabled!'
+ : 'Account disabled!';
+ this.emit('change');
+ this.vnApp.showSuccess(this.$t(message));
+ }
+
+ onSetActive(active) {
+ return this.$http.patch(`VnUsers/${this.id}`, {active})
+ .then(() => {
+ this.user.active = active;
+ const message = active
+ ? 'User activated!'
+ : 'User deactivated!';
+ this.emit('change');
+ this.vnApp.showSuccess(this.$t(message));
+ });
+ }
+
+ onSync() {
+ const params = {force: true};
+ if (this.shouldSyncPassword)
+ params.password = this.syncPassword;
+
+ return this.$http.patch(`Accounts/${this.user.name}/sync`, params)
+ .then(() => this.vnApp.showSuccess(this.$t('User synchronized!')));
+ }
+
+ onSyncClose() {
+ this.shouldSyncPassword = false;
+ this.syncPassword = undefined;
+ }
+}
+
+ngModule.component('vnUserDescriptor', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ user: '<'
+ }
+});
diff --git a/modules/account/front/descriptor/locale/es.yml b/modules/account/front/descriptor/locale/es.yml
new file mode 100644
index 000000000..98ced7694
--- /dev/null
+++ b/modules/account/front/descriptor/locale/es.yml
@@ -0,0 +1,35 @@
+User will be removed: El usuario será eliminado
+User removed: Usuario eliminado
+Are you sure you want to continue?: ¿Seguro que quieres continuar?
+Account will be enabled: La cuenta será habilitada
+Account will be disabled: La cuenta será deshabilitada
+Account enabled!: ¡Cuenta habilitada!
+Account disabled!: ¡Cuenta deshabilitada!
+User will activated: El usuario será activado
+User will be deactivated: El usuario será desactivado
+User activated!: ¡Usuario activado!
+User deactivated!: ¡Usuario desactivado!
+Account enabled: Cuenta habilitada
+User deactivated: Usuario desactivado
+Change role: Modificar rol
+Change password: Cambiar contraseña
+Set password: Establecer contraseña
+Enable account: Habilitar cuenta
+Disable account: Deshabilitar cuenta
+Activate user: Activar usuario
+Deactivate user: Desactivar usuario
+Old password: Contraseña antigua
+New password: Nueva contraseña
+Repeat password: Repetir contraseña
+Password changed succesfully!: ¡Contraseña modificada correctamente!
+Synchronize: Sincronizar
+Do you want to synchronize user?: ¿Quieres sincronizar el usuario?
+Synchronize password: Sincronizar contraseña
+User synchronized!: ¡Usuario sincronizado!
+Role changed succesfully!: ¡Rol modificado correctamente!
+Password requirements: >
+ La contraseña debe tener al menos {{ length }} caracteres de longitud,
+ {{nAlpha}} caracteres alfabéticos, {{nUpper}} letras mayúsculas, {{nDigits}}
+ dígitos y {{nPunct}} símbolos (Ej: $%&.)
+You must enter a new password: Debes introducir la nueva contraseña
+Passwords don't match: Las contraseñas no coinciden
diff --git a/modules/account/front/index.js b/modules/account/front/index.js
index a7209a0bd..0f2208862 100644
--- a/modules/account/front/index.js
+++ b/modules/account/front/index.js
@@ -1,3 +1,6 @@
export * from './module';
import './main';
+import './descriptor';
+import './descriptor-popover';
+import './summary';
diff --git a/modules/account/front/summary/index.html b/modules/account/front/summary/index.html
new file mode 100644
index 000000000..f3c11f25f
--- /dev/null
+++ b/modules/account/front/summary/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ {{summary.id}} - {{summary.nickname}}
+
+
+
+
+
+ Basic Data
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/account/front/summary/index.js b/modules/account/front/summary/index.js
new file mode 100644
index 000000000..53b66dbe2
--- /dev/null
+++ b/modules/account/front/summary/index.js
@@ -0,0 +1,40 @@
+import ngModule from '../module';
+import Summary from 'salix/components/summary';
+
+class Controller extends Summary {
+ set user(value) {
+ this._user = value;
+ this.$.summary = null;
+ if (!value) return;
+
+ const filter = {
+ where: {id: value.id},
+ include: {
+ relation: 'role',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ };
+ this.$http.get(`VnUsers/preview`, {filter})
+ .then(res => {
+ const [summary] = res.data;
+ this.$.summary = summary;
+ });
+ }
+ get isHr() {
+ return this.aclService.hasAny(['hr']);
+ }
+
+ get user() {
+ return this._user;
+ }
+}
+
+ngModule.component('vnUserSummary', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ user: '<'
+ }
+});