1
0

Hide UI elements if the user does not have the right to use them (#211)

Hide Team UI elements if the user does not have the rights to use them

Fix replacing the right saved in the model when updating

Hide UI-Elements on task if the user does not have the rights to use them

Hide UI-Elements on gantt if the user does not have the rights to use them

Hide UI-Elements on kanban if the user does not have rights to use them

Fix canWrite condition

Hide list components if the user has no right to write to the list

Add max right to model

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/211
This commit is contained in:
konrad
2020-08-11 18:18:59 +00:00
parent e64b4e3329
commit 3c07c6e8c0
22 changed files with 282 additions and 132 deletions

View File

@ -1,6 +1,6 @@
<template>
<div class="editor">
<div class="tabs is-right" v-if="hasPreview">
<div class="editor" :class="{'is-pulled-up': isEditEnabled}">
<div class="tabs is-right" v-if="hasPreview && isEditEnabled">
<ul>
<li :class="{'is-active': isPreviewActive}" v-if="isEditActive">
<a @click="showPreview">Preview</a>
@ -58,6 +58,9 @@
type: Boolean,
default: true,
},
isEditEnabled: {
default: true,
},
},
data() {
return {

View File

@ -35,7 +35,7 @@
'has-dark-text': colorIsDark(t.hexColor)
}"
:style="{'border-color': t.hexColor, 'background-color': t.hexColor}"
:isActive="true"
:isActive="canWrite"
:x="t.offsetDays * dayWidth - 6"
:y="0"
:w="t.durationDays * dayWidth"
@ -67,7 +67,7 @@
<div class="row" v-for="(t, k) in tasksWithoutDates" :key="t.id" :style="{background: 'repeating-linear-gradient(90deg, #ededed, #ededed 1px, ' + (k % 2 === 0 ? '#fafafa 1px, #fafafa ' : '#fff 1px, #fff ') + dayWidth + 'px)'}">
<VueDragResize
class="task nodate"
:isActive="true"
:isActive="canWrite"
:x="dayOffsetUntilToday * dayWidth - 6"
:y="0"
:h="31"
@ -88,7 +88,7 @@
</div>
</template>
</div>
<form @submit.prevent="addNewTask()" class="add-new-task">
<form @submit.prevent="addNewTask()" class="add-new-task" v-if="canWrite">
<transition name="width">
<input
type="text"
@ -138,6 +138,8 @@
import priorities from '../../models/priorities'
import PriorityLabel from './partials/priorityLabel'
import TaskCollectionService from '../../services/taskCollection'
import {mapState} from 'vuex'
import Rights from '../../models/rights.json'
export default {
name: 'GanttChart',
@ -201,6 +203,9 @@
mounted() {
this.buildTheGanttChart()
},
computed: mapState({
canWrite: state => state.currentList.maxRight > Rights.READ,
}),
methods: {
buildTheGanttChart() {
this.setDates()

View File

@ -6,6 +6,7 @@
</span>
Attachments
<a
v-if="editEnabled"
class="button is-primary is-outlined is-small noshadow"
@click="$refs.files.click()"
:disabled="attachmentService.loading">
@ -14,7 +15,7 @@
</a>
</h3>
<input type="file" id="files" ref="files" multiple @change="uploadNewAttachment()" :disabled="attachmentService.loading"/>
<input type="file" id="files" ref="files" multiple @change="uploadNewAttachment()" :disabled="attachmentService.loading" v-if="editEnabled"/>
<progress v-if="attachmentService.uploadProgress > 0" class="progress is-primary" :value="attachmentService.uploadProgress" max="100">{{ attachmentService.uploadProgress }}%</progress>
<table>
@ -41,7 +42,7 @@
<icon icon="cloud-download-alt"/>
</span>
</a>
<a class="button is-danger noshadow" v-tooltip="'Delete this attachment'" @click="() => {attachmentToDelete = a; showDeleteModal = true}">
<a v-if="editEnabled" class="button is-danger noshadow" v-tooltip="'Delete this attachment'" @click="() => {attachmentToDelete = a; showDeleteModal = true}">
<span class="icon">
<icon icon="trash-alt"/>
</span>
@ -52,7 +53,7 @@
</table>
<!-- Dropzone -->
<div class="dropzone" :class="{ 'hidden': !showDropzone }">
<div class="dropzone" :class="{ 'hidden': !showDropzone }" v-if="editEnabled">
<div class="drop-hint">
<div class="icon">
<icon icon="cloud-upload-alt"/>
@ -102,7 +103,10 @@
},
initialAttachments: {
type: Array,
}
},
editEnabled: {
default: true,
},
},
created() {
this.attachmentService = new AttachmentService()

View File

@ -1,6 +1,6 @@
<template>
<div class="content details has-top-border">
<h1>
<div class="content details" :class="{'has-top-border': canWrite || comments.length > 0}">
<h1 v-if="canWrite || comments.length > 0">
<span class="icon is-grey">
<icon :icon="['far', 'comments']"/>
</span>
@ -15,7 +15,7 @@
<img class="image is-avatar" :src="c.author.getAvatarUrl(48)" alt="" width="48" height="48"/>
</figure>
<div class="media-content">
<div class="comment-info">
<div class="comment-info" :class="{'is-pulled-up': canWrite}">
<strong>{{ c.author.username }}</strong>&nbsp;
<small v-tooltip="formatDate(c.created)">{{ formatDateSince(c.created) }}</small>
<small v-if="+new Date(c.created) !== +new Date(c.updated)" v-tooltip="formatDate(c.updated)"> ·
@ -27,13 +27,14 @@
@change="() => {toggleEdit(c);editComment()}"
:upload-enabled="true"
:upload-callback="attachmentUpload"
:is-edit-enabled="canWrite"
/>
<div class="comment-actions">
<div class="comment-actions" v-if="canWrite">
<a @click="toggleDelete(c.id)">Remove</a>
</div>
</div>
</div>
<div class="media comment">
<div class="media comment" v-if="canWrite">
<figure class="media-left">
<img class="image is-avatar" :src="userAvatar" alt="" width="48" height="48"/>
</figure>
@ -95,7 +96,10 @@
taskId: {
type: Number,
required: true,
}
},
canWrite: {
default: true,
},
},
data() {
return {
@ -125,7 +129,7 @@
watch: {
taskId() {
this.loadComments()
}
},
},
computed: {
userAvatar() {

View File

@ -17,10 +17,11 @@
track-by="id"
select-label="Assign this user"
:showNoOptions="false"
:disabled="disabled"
>
<template slot="tag" slot-scope="{ option }">
<user :user="option" :show-username="false" :avatar-size="30"/>
<a @click="removeAssignee(option)" class="remove-assignee">
<a @click="removeAssignee(option)" class="remove-assignee" v-if="!disabled">
<icon icon="times"/>
</a>
</template>
@ -65,7 +66,10 @@
initialAssignees: {
type: Array,
default: () => [],
}
},
disabled: {
default: false,
},
},
data() {
return {

View File

@ -19,6 +19,7 @@
:showNoOptions="false"
@tag="createAndAddLabel"
tag-placeholder="Add this as new label"
:disabled="disabled"
>
<template slot="tag" slot-scope="{ option }">
<span class="tag"
@ -54,6 +55,9 @@
type: Number,
required: true,
},
disabled: {
default: false,
},
},
data() {
return {

View File

@ -1,6 +1,6 @@
<template>
<div class="select">
<select v-model.number="percentDone" @change="updateData">
<select v-model.number="percentDone" @change="updateData" :disabled="disabled">
<option value="0">0%</option>
<option value="0.1">10%</option>
<option value="0.2">20%</option>
@ -28,7 +28,10 @@
value: {
default: 0,
type: Number,
}
},
disabled: {
default: false,
},
},
watch: {
// Set the priority to the :value every time it changes from the outside

View File

@ -1,6 +1,6 @@
<template>
<div class="select">
<select v-model="priority" @change="updateData">
<select v-model="priority" @change="updateData" :disabled="disabled">
<option :value="priorities.UNSET">Unset</option>
<option :value="priorities.LOW">Low</option>
<option :value="priorities.MEDIUM">Medium</option>
@ -26,7 +26,10 @@
value: {
default: 0,
type: Number,
}
},
disabled: {
default: false,
},
},
watch: {
// Set the priority to the :value every time it changes from the outside

View File

@ -1,47 +1,49 @@
<template>
<div class="task-relations">
<label class="label">New Task Relation</label>
<div class="field">
<multiselect
v-model="newTaskRelationTask"
:options="foundTasks"
:multiple="false"
:searchable="true"
:loading="taskService.loading"
:internal-search="true"
@search-change="findTasks"
placeholder="Type search for a new task to add as related..."
label="title"
track-by="id"
:taggable="true"
:showNoOptions="false"
@tag="createAndRelateTask"
tag-placeholder="Add this as new related task"
>
<template slot="clear" slot-scope="props">
<div
class="multiselect__clear"
v-if="newTaskRelationTask !== null && newTaskRelationTask.id !== 0"
@mousedown.prevent.stop="clearAllFoundTasks(props.search)"></div>
</template>
<span slot="noResult">No task found. Consider changing the search query.</span>
</multiselect>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth has-defaults">
<select v-model="newTaskRelationKind">
<option value="unset">Select a relation kind</option>
<option v-for="(label, rk) in relationKinds" :key="rk" :value="rk">
{{ label[0] }}
</option>
</select>
<template v-if="editEnabled">
<label class="label">New Task Relation</label>
<div class="field">
<multiselect
v-model="newTaskRelationTask"
:options="foundTasks"
:multiple="false"
:searchable="true"
:loading="taskService.loading"
:internal-search="true"
@search-change="findTasks"
placeholder="Type search for a new task to add as related..."
label="title"
track-by="id"
:taggable="true"
:showNoOptions="false"
@tag="createAndRelateTask"
tag-placeholder="Add this as new related task"
>
<template slot="clear" slot-scope="props">
<div
class="multiselect__clear"
v-if="newTaskRelationTask !== null && newTaskRelationTask.id !== 0"
@mousedown.prevent.stop="clearAllFoundTasks(props.search)"></div>
</template>
<span slot="noResult">No task found. Consider changing the search query.</span>
</multiselect>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth has-defaults">
<select v-model="newTaskRelationKind">
<option value="unset">Select a relation kind</option>
<option v-for="(label, rk) in relationKinds" :key="rk" :value="rk">
{{ label[0] }}
</option>
</select>
</div>
</div>
<div class="control">
<a class="button is-primary" @click="addTaskRelation()">Add task Relation</a>
</div>
</div>
<div class="control">
<a class="button is-primary" @click="addTaskRelation()">Add task Relation</a>
</div>
</div>
</template>
<div class="related-tasks" v-for="(rts, kind ) in relatedTasks" :key="kind">
<template v-if="rts.length > 0">
@ -50,13 +52,17 @@
<div class="task" v-for="t in rts" :key="t.id">
<router-link :to="{ name: $route.name, params: { id: t.id } }">
<span class="tasktext" :class="{ 'done': t.done}">
<span v-if="t.listId !== listId" class="different-list" v-tooltip="'This task belongs to a different list.'">
<span
v-if="t.listId !== listId"
class="different-list"
v-tooltip="'This task belongs to a different list.'">
{{ $store.getters['lists/getListById'](t.listId) === null ? '' : $store.getters['lists/getListById'](t.listId).title }} >
</span>
{{t.title}}
</span>
</router-link>
<a
v-if="editEnabled"
class="remove"
@click="() => {showDeleteModal = true; relationToDelete = {relationKind: kind, otherTaskId: t.id}}">
<icon icon="trash-alt"/>
@ -131,7 +137,10 @@
listId: {
type: Number,
default: 0,
}
},
editEnabled: {
default: true,
},
},
created() {
this.taskService = new TaskService()
@ -222,7 +231,7 @@
return relationKinds[kind][1]
}
return relationKinds[kind][0]
}
},
},
}
</script>

View File

@ -10,9 +10,10 @@
:value="r"
:data-index="index"
placeholder="Add a new reminder..."
:disabled="disabled"
>
</flat-pickr>
<a v-if="index !== (reminders.length - 1)" @click="removeReminderByIndex(index)">
<a v-if="index !== (reminders.length - 1) && !disabled" @click="removeReminderByIndex(index)">
<icon icon="times"></icon>
</a>
</div>
@ -44,7 +45,10 @@
value: {
default: () => [],
type: Array,
}
},
disabled: {
default: false,
},
},
components: {
flatPickr,

View File

@ -6,6 +6,7 @@
<div class="column is-7 field has-addons">
<div class="control">
<input
:disabled="disabled"
class="input"
placeholder="Specify an amount..."
v-model="repeatAfter.amount"
@ -13,7 +14,7 @@
</div>
<div class="control">
<div class="select">
<select v-model="repeatAfter.type" @change="updateData">
<select v-model="repeatAfter.type" @change="updateData" :disabled="disabled">
<option value="hours">Hours</option>
<option value="days">Days</option>
<option value="weeks">Weeks</option>
@ -24,6 +25,7 @@
</div>
</div>
<fancycheckbox
:disabled="disabled"
class="column"
@change="updateData"
v-model="task.repeatFromCurrentDate"
@ -54,7 +56,10 @@
default: () => {
},
required: true,
}
},
disabled: {
default: false,
},
},
watch: {
value(newVal) {

View File

@ -1,6 +1,6 @@
<template>
<span>
<fancycheckbox v-model="task.done" @change="markAsDone" :disabled="isArchived"/>
<fancycheckbox v-model="task.done" @change="markAsDone" :disabled="isArchived || disabled"/>
<span class="tasktext" :class="{ 'done': task.done}">
<router-link :to="{ name: taskDetailRoute, params: { id: task.id } }">
<router-link
@ -88,6 +88,10 @@
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
},
watch: {
theTask(newVal) {