Add showing and modifying user name (#306)
Make sure to use the user name field everywhere Add showing and modifying user name Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/306 Co-Authored-By: konrad <konrad@kola-entertainments.de> Co-Committed-By: konrad <konrad@kola-entertainments.de>
This commit is contained in:
parent
c536707f3a
commit
3343b1c240
14 changed files with 92 additions and 10 deletions
|
@ -45,7 +45,7 @@
|
||||||
<div class="dropdown is-right is-active">
|
<div class="dropdown is-right is-active">
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<button @click.stop="userMenuActive = !userMenuActive" class="button noshadow">
|
<button @click.stop="userMenuActive = !userMenuActive" class="button noshadow">
|
||||||
<span class="username">{{ userInfo.username }}</span>
|
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<icon icon="chevron-down"/>
|
<icon icon="chevron-down"/>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
:width="avatarSize"
|
:width="avatarSize"
|
||||||
alt=""
|
alt=""
|
||||||
class="avatar"
|
class="avatar"
|
||||||
v-tooltip="user.username"/>
|
v-tooltip="user.getDisplayName()"/>
|
||||||
<span class="username" v-if="showUsername">{{ user.username }}</span>
|
<span class="username" v-if="showUsername">{{ user.getDisplayName() }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ s.sharedBy.username }}
|
{{ s.sharedBy.getDisplayName() }}
|
||||||
</td>
|
</td>
|
||||||
<td class="type">
|
<td class="type">
|
||||||
<template v-if="s.right === rights.ADMIN">
|
<template v-if="s.right === rights.ADMIN">
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr :key="s.id" v-for="s in sharables">
|
<tr :key="s.id" v-for="s in sharables">
|
||||||
<template v-if="shareType === 'user'">
|
<template v-if="shareType === 'user'">
|
||||||
<td>{{ s.username }}</td>
|
<td>{{ s.getDisplayName() }}</td>
|
||||||
<td>
|
<td>
|
||||||
<template v-if="s.id === userInfo.id">
|
<template v-if="s.id === userInfo.id">
|
||||||
<b class="is-success">You</b>
|
<b class="is-success">You</b>
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
<label class="label" for="">Assignees</label>
|
<label class="label" for="">Assignees</label>
|
||||||
<ul class="assingees">
|
<ul class="assingees">
|
||||||
<li :key="a.id" v-for="(a, index) in taskEditTask.assignees">
|
<li :key="a.id" v-for="(a, index) in taskEditTask.assignees">
|
||||||
{{ a.username }}
|
{{ a.getDisplayName() }}
|
||||||
<a @click="deleteAssigneeByIndex(index)">
|
<a @click="deleteAssigneeByIndex(index)">
|
||||||
<icon icon="times"/>
|
<icon icon="times"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<div class="media-content">
|
<div class="media-content">
|
||||||
<div class="comment-info">
|
<div class="comment-info">
|
||||||
<img :src="c.author.getAvatarUrl(20)" alt="" class="image is-avatar" height="20" width="20"/>
|
<img :src="c.author.getAvatarUrl(20)" alt="" class="image is-avatar" height="20" width="20"/>
|
||||||
<strong>{{ c.author.username }}</strong>
|
<strong>{{ c.author.getDisplayName() }}</strong>
|
||||||
<span v-tooltip="formatDate(c.created)">{{ formatDateSince(c.created) }}</span>
|
<span v-tooltip="formatDate(c.created)">{{ formatDateSince(c.created) }}</span>
|
||||||
<span v-if="+new Date(c.created) !== +new Date(c.updated)" v-tooltip="formatDate(c.updated)">
|
<span v-if="+new Date(c.created) !== +new Date(c.updated)" v-tooltip="formatDate(c.updated)">
|
||||||
· edited {{ formatDateSince(c.updated) }}
|
· edited {{ formatDateSince(c.updated) }}
|
||||||
|
|
|
@ -12,6 +12,7 @@ export default class UserModel extends AbstractModel {
|
||||||
id: 0,
|
id: 0,
|
||||||
email: '',
|
email: '',
|
||||||
username: '',
|
username: '',
|
||||||
|
name: '',
|
||||||
created: null,
|
created: null,
|
||||||
updated: null,
|
updated: null,
|
||||||
}
|
}
|
||||||
|
@ -20,4 +21,12 @@ export default class UserModel extends AbstractModel {
|
||||||
getAvatarUrl(size = 50) {
|
getAvatarUrl(size = 50) {
|
||||||
return `${window.API_URL}/${this.username}/avatar?size=${size}`
|
return `${window.API_URL}/${this.username}/avatar?size=${size}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDisplayName() {
|
||||||
|
if (this.name !== '') {
|
||||||
|
return this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.username
|
||||||
|
}
|
||||||
}
|
}
|
10
src/models/userName.js
Normal file
10
src/models/userName.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
import AbstractModel from './abstractModel'
|
||||||
|
|
||||||
|
export default class UserNameModel extends AbstractModel {
|
||||||
|
defaults() {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/services/userName.js
Normal file
10
src/services/userName.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
import AbstractService from './abstractService'
|
||||||
|
|
||||||
|
export default class UserNameService extends AbstractService {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
update: '/user/settings/name',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,9 @@ export default {
|
||||||
state.info = info
|
state.info = info
|
||||||
state.avatarUrl = info.getAvatarUrl()
|
state.avatarUrl = info.getAvatarUrl()
|
||||||
},
|
},
|
||||||
|
setUserName(state, name) {
|
||||||
|
state.info.name = name
|
||||||
|
},
|
||||||
authenticated(state, authenticated) {
|
authenticated(state, authenticated) {
|
||||||
state.authenticated = authenticated
|
state.authenticated = authenticated
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content has-text-centered">
|
<div class="content has-text-centered">
|
||||||
<h2>Hi {{ userInfo.username }}!</h2>
|
<h2>Hi {{ userInfo.name !== '' ? userInfo.name : userInfo.username }}!</h2>
|
||||||
<template v-if="!hasTasks">
|
<template v-if="!hasTasks">
|
||||||
<p>Click on a list or namespace on the left to get started.</p>
|
<p>Click on a list or namespace on the left to get started.</p>
|
||||||
<router-link
|
<router-link
|
||||||
|
|
|
@ -346,7 +346,7 @@
|
||||||
|
|
||||||
<!-- Created / Updated [by] -->
|
<!-- Created / Updated [by] -->
|
||||||
<p class="created">
|
<p class="created">
|
||||||
Created <span v-tooltip="formatDate(task.created)">{{ formatDateSince(task.created) }}</span> by {{ task.createdBy.username }}
|
Created <span v-tooltip="formatDate(task.created)">{{ formatDateSince(task.created) }}</span> by {{ task.createdBy.getDisplayName() }}
|
||||||
<template v-if="+new Date(task.created) !== +new Date(task.updated)">
|
<template v-if="+new Date(task.created) !== +new Date(task.updated)">
|
||||||
<br/>
|
<br/>
|
||||||
<!-- Computed properties to show the actual date every time it gets updated -->
|
<!-- Computed properties to show the actual date every time it gets updated -->
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
<table class="table is-striped is-hoverable is-fullwidth">
|
<table class="table is-striped is-hoverable is-fullwidth">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr :key="m.id" v-for="m in team.members">
|
<tr :key="m.id" v-for="m in team.members">
|
||||||
<td>{{ m.username }}</td>
|
<td>{{ m.getDisplayName() }}</td>
|
||||||
<td>
|
<td>
|
||||||
<template v-if="m.id === userInfo.id">
|
<template v-if="m.id === userInfo.id">
|
||||||
<b class="is-success">You</b>
|
<b class="is-success">You</b>
|
||||||
|
|
|
@ -106,6 +106,38 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="card">
|
||||||
|
<header class="card-header">
|
||||||
|
<p class="card-header-title">
|
||||||
|
Update your name
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="content">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label" for="newEmail">Name</label>
|
||||||
|
<div class="control">
|
||||||
|
<input
|
||||||
|
@keyup.enter="updateName"
|
||||||
|
class="input"
|
||||||
|
id="newEmail"
|
||||||
|
placeholder="The new name"
|
||||||
|
type="text"
|
||||||
|
v-model="name"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bigbuttons">
|
||||||
|
<button :class="{ 'is-loading': userNameService.loading}" @click="updateName()"
|
||||||
|
class="button is-primary is-fullwidth">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Avatar -->
|
<!-- Avatar -->
|
||||||
<avatar-settings/>
|
<avatar-settings/>
|
||||||
|
|
||||||
|
@ -234,6 +266,8 @@ import EmailUpdateService from '../../services/emailUpdate'
|
||||||
import EmailUpdateModel from '../../models/emailUpdate'
|
import EmailUpdateModel from '../../models/emailUpdate'
|
||||||
import TotpModel from '../../models/totp'
|
import TotpModel from '../../models/totp'
|
||||||
import TotpService from '../../services/totp'
|
import TotpService from '../../services/totp'
|
||||||
|
import UserNameService from '../../services/userName'
|
||||||
|
import UserNameModel from '../../models/userName'
|
||||||
|
|
||||||
import {mapState} from 'vuex'
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
|
@ -260,6 +294,9 @@ export default {
|
||||||
totpDisablePassword: '',
|
totpDisablePassword: '',
|
||||||
|
|
||||||
caldavUrl: '',
|
caldavUrl: '',
|
||||||
|
|
||||||
|
name: '',
|
||||||
|
userNameService: UserNameService,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -275,6 +312,9 @@ export default {
|
||||||
this.totpService = new TotpService()
|
this.totpService = new TotpService()
|
||||||
this.totp = new TotpModel()
|
this.totp = new TotpModel()
|
||||||
|
|
||||||
|
this.userNameService = new UserNameService()
|
||||||
|
this.name = this.$store.state.auth.info.name
|
||||||
|
|
||||||
this.totpStatus()
|
this.totpStatus()
|
||||||
this.buildCaldavUrl()
|
this.buildCaldavUrl()
|
||||||
},
|
},
|
||||||
|
@ -359,6 +399,16 @@ export default {
|
||||||
})
|
})
|
||||||
.catch(e => this.error(e, this))
|
.catch(e => this.error(e, this))
|
||||||
},
|
},
|
||||||
|
updateName() {
|
||||||
|
const name = new UserNameModel({name: this.name})
|
||||||
|
|
||||||
|
this.userNameService.update(name)
|
||||||
|
.then(() => {
|
||||||
|
this.$store.commit('auth/setUserName', this.name)
|
||||||
|
this.success({message: 'The name was successfully changed.'}, this)
|
||||||
|
})
|
||||||
|
.catch(e => this.error(e, this))
|
||||||
|
},
|
||||||
buildCaldavUrl() {
|
buildCaldavUrl() {
|
||||||
const apiBase = window.API_URL.replace('/api/v1', '')
|
const apiBase = window.API_URL.replace('/api/v1', '')
|
||||||
this.caldavUrl = `${apiBase}/dav/principals/${this.userInfo.username}/`
|
this.caldavUrl = `${apiBase}/dav/principals/${this.userInfo.username}/`
|
||||||
|
|
Loading…
Reference in a new issue