Commit a89c5c10 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Improved navigation using Vue Router; Improved permission editing; Bugfixes and refactoring

parent 9cb983f9
......@@ -2,9 +2,7 @@
<div id="app" v-if="model">
<TopMenu v-bind:user="model.user" />
<div class="container">
<Main v-if="page === 'main'" />
<GenericSearchResults v-if="page === 'search'" />
<UserSearchResult v-if="page === 'userSearch'" />
<router-view></router-view>
</div>
<div id="loading" v-if="loading">
<div id="spinner-wrapper">
......@@ -16,21 +14,13 @@
<script>
import TopMenu from './components/TopMenu.vue';
import Main from './components/Main.vue';
import GenericSearchResults from './components/GenericSearchResults.vue';
import UserSearchResult from './components/UserSearchResult.vue';
import {
mapState
} from 'vuex';
import { mapState } from 'vuex';
import client from 'api-client';
export default {
name: 'app',
components: {
TopMenu,
Main,
GenericSearchResults,
UserSearchResult
TopMenu
},
computed: mapState({
model: state => state.model,
......@@ -52,10 +42,7 @@ export default {
});
// retrieve the initial model
client.fetchHomePageModel(this.input)
.then(model => {
this.$store.commit('updateHomePageModel', model);
});
this.$store.dispatch('loadHomePageModel');
setInterval(client.keepAlive, 60000);
}
......
......@@ -47,6 +47,9 @@ export default {
addPermission() {
return fetch(permissionsPanel);
},
updatePermission() {
return fetch({"permission": "ADMIN"});
},
getPermission() {
return fetch(permission);
},
......
const BASE_API_URL = process.env.VUE_APP_API_BASE_URL;
function apiRequest(url, options, showLoading = true) {
import axios from 'axios';
function apiRequest(options, showLoading = true, handleValidationErrors = false) {
if (showLoading) {
loading(true);
}
return new Promise((resolve) => {
fetch(url, options)
return new Promise((resolve, reject) => {
axios(options)
.then(response => {
loading(false);
if ([200, 201, 204, 400].includes(response.status)) { // valid status codes
if (response.status === 204) {
resolve({});
} else {
resolve(response.json());
}
if (response.status === 204) {
resolve({});
} else {
response.json().then(jsonValue => dispatchApiErrorEvent(jsonValue));
resolve(response.data);
}
loading(false);
})
.catch(error => {
if(handleValidationErrors && error.response && error.response.status === 400) {
reject(error.response.data);
} else {
dispatchApiErrorEvent(error);
}
loading(false);
dispatchApiErrorEvent(error);
});
});
}
function dispatchApiErrorEvent(error) {
let event = new CustomEvent('apiError');
let errorMessage;
if (error.response && error.response.data && error.response.data.message) {
errorMessage = error.response.data.message;
} else if (error.message) {
errorMessage = error.message;
} else {
errorMessage = 'Unknown error';
}
event.message = {
title: error.error || 'Error',
body: error.message || 'Unknown error'
body: errorMessage
};
document.dispatchEvent(event);
}
......@@ -47,13 +57,14 @@ export default {
'home?groupId=' + input.selectedGroupId +
'&paginatorPageSize=' + input.paginatorPageSize +
'&paginatorPage=' + input.paginatorPage;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
......@@ -66,13 +77,14 @@ export default {
if (input.searchFilter !== null) {
url += '&searchFilter=' + input.searchFilter;
}
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
......@@ -85,13 +97,14 @@ export default {
if (input.searchFilter !== null) {
url += '&searchFilter=' + input.searchFilter;
}
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
......@@ -100,13 +113,14 @@ export default {
'members?groupId=' + input.selectedGroupId +
'&paginatorPageSize=' + input.paginatorPageSize +
'&paginatorPage=' + input.paginatorPage;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
......@@ -115,54 +129,57 @@ export default {
'permissions?groupId=' + input.selectedGroupId +
'&paginatorPageSize=' + input.paginatorPageSize +
'&paginatorPage=' + input.paginatorPage;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
addGroup(newGroupName, leaf, input) {
let url = BASE_API_URL + 'group';
return apiRequest(url, {
return apiRequest({
method: 'POST',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
},
body: JSON.stringify({
data: {
newGroupName: newGroupName,
parentGroupId: input.selectedGroupId,
paginatorPageSize: input.paginatorPageSize,
paginatorPage: input.paginatorPage,
searchFilter: input.searchFilter,
leaf: leaf
})
});
}
}, true, true);
},
updateGroup(groupId, newGroupName, leaf, input) {
let url = BASE_API_URL + 'group/' + groupId;
return apiRequest(url, {
return apiRequest({
method: 'PUT',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
},
body: JSON.stringify({
data: {
newGroupName: newGroupName,
leaf: leaf,
paginatorPageSize: input.paginatorPageSize,
paginatorPage: input.paginatorPage,
searchFilter: input.searchFilter
})
});
}
}, true, true);
},
removeGroup(groupId, input) {
let url = BASE_API_URL + 'group/' + groupId +
......@@ -171,80 +188,104 @@ export default {
if (input.searchFilter !== null) {
url += '&searchFilter=' + input.searchFilter;
}
return apiRequest(url, {
return apiRequest({
method: 'DELETE',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
searchUser(searchInput) {
let url = BASE_API_URL + 'users?search=' + searchInput;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
addPermission(userId, permission, input) {
addPermission(userId, permission, input, override) {
let url = BASE_API_URL + 'permission';
return apiRequest(url, {
return apiRequest({
method: 'POST',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
},
body: JSON.stringify({
data: {
groupId: input.selectedGroupId,
userId: userId,
permission: permission,
override: override,
paginatorPageSize: input.paginatorPageSize,
paginatorPage: input.paginatorPage
})
}
});
},
updatePermission(groupId, userId, permission) {
let url = BASE_API_URL + 'permission';
return apiRequest({
method: 'PUT',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
},
data: {
groupId: groupId,
userId: userId,
permission: permission
}
});
},
getPermission(groupId, userId) {
let url = BASE_API_URL + 'permission?groupId=' + groupId + '&userId=' + userId;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
addMember(userId, permission, input) {
let url = BASE_API_URL + 'member';
return apiRequest(url, {
return apiRequest({
method: 'POST',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
},
body: JSON.stringify({
data: {
groupId: input.selectedGroupId,
userId: userId,
permission: permission,
paginatorPageSize: input.paginatorPageSize,
paginatorPage: input.paginatorPage
})
}
});
},
removeMember(userId, removeAlsoPermission, input) {
......@@ -254,13 +295,14 @@ export default {
'&removeAlsoPermission=' + removeAlsoPermission +
'&paginatorPageSize=' + input.paginatorPageSize +
'&paginatorPage=' + input.paginatorPage;
return apiRequest(url, {
return apiRequest({
method: 'DELETE',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
......@@ -270,13 +312,14 @@ export default {
'&userId=' + userId +
'&paginatorPageSize=' + input.paginatorPageSize +
'&paginatorPage=' + input.paginatorPage;
return apiRequest(url, {
return apiRequest({
method: 'DELETE',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
......@@ -284,36 +327,41 @@ export default {
let url = BASE_API_URL + 'search?query=' + input.genericSearch.filter +
'&page=' + input.genericSearch.paginatorPage + '&pageSize=' + input.genericSearch.paginatorPageSize;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
openUserSearchResult(userId) {
let url = BASE_API_URL + 'search/user/' + userId;
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include',
url: url,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cache-Control': 'no-cache'
}
});
},
keepAlive() {
let url = BASE_API_URL + 'keepAlive';
return apiRequest(url, {
return apiRequest({
method: 'GET',
cache: 'no-cache',
credentials: 'include'
url: url,
withCredentials: true,
headers: {
'Cache-Control': 'no-cache'
}
}, false);
}
};
......@@ -17,11 +17,8 @@
</template>
<script>
import client from 'api-client';
import Paginator from './Paginator.vue';
import {
mapState
} from 'vuex';
import { mapState } from 'vuex';
export default {
name: 'GenericSearchResults',
......@@ -32,22 +29,26 @@ export default {
model: state => state.model,
input: state => state.input
}),
created () {
this.updateSearchResults();
},
watch: {
// call again the method if the route changes
'$route': 'updateSearchResults'
},
methods: {
openSearchResult: function(result) {
switch (result.type) {
case 'GROUP':
this.$store.commit('openGroup', result.id);
this.$store.dispatch('openGroup', result.id);
break;
case 'USER':
this.$store.dispatch('openUserPage', result.id);
this.$router.push({ path: `/user/${result.id}` }, () => {});
break;
}
},
updateSearchResults: function() {
client.search(this.input)
.then(results => {
this.$store.commit('displaySearchResults', results);
});
this.$store.dispatch('search', this.$route.query.q);
}
}
}
......
<template>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item" v-for="group in groups" v-bind:class="{ active: group.active }">
<li class="breadcrumb-item" v-for="group in groups" v-bind:class="{ active: group.active }" v-bind:key="group.groupId">
<a href="#" v-on:click="changeBreadcrumb(group.groupId)" v-if="!group.active">{{group.groupName}}</a>
<span v-if="group.active">{{group.groupName}}</span>
</li>
......@@ -10,9 +10,7 @@
</template>
<script>
import {
mapState
} from 'vuex';
import { mapState } from 'vuex';
import client from 'api-client';
function buildItems(values) {
......@@ -49,7 +47,7 @@ export default {
this.$store.commit('updateGroups', model);
});
} else {
this.$store.commit('setTabIndex', 0);
this.$store.dispatch('changeTab', 0);
}
}
}
......
......@@ -6,7 +6,7 @@
</b-col>
</b-row>
<div id="groups-list" v-if="model.groupsPanel !== null">
<b-list-group v-for="group in model.groupsPanel.items">
<b-list-group v-for="group in model.groupsPanel.items" v-bind:key="group.groupId">
<b-list-group-item href="#" v-on:click="openGroup(group)">
<span class="float-left">{{group.groupName}}</span>
<span v-if="group.permission === 'ADMIN'" class="float-right">
......@@ -32,10 +32,7 @@
import EditGroupModal from './modals/EditGroupModal.vue';
import ConfirmRemoveGroupModal from './modals/ConfirmRemoveGroupModal.vue';
import Paginator from './Paginator.vue';
import {
mapState,
mapActions
} from 'vuex';
import { mapState } from 'vuex';
import client from 'api-client';
import debounce from 'debounce'; // for delaying the input event (search filter)
......@@ -52,7 +49,7 @@ export default {
}),
methods: {
openGroup: function(group) {
this.$store.commit('openGroup', group.groupId);
this.$store.dispatch('openGroup', group.groupId);
},
openEditGroupModal: function(group) {
this.$refs.editGroupModal.openEditGroupModal(group);
......
......@@ -28,10 +28,7 @@ import PermissionsPanel from './PermissionsPanel.vue'
import AddGroupModal from './modals/AddGroupModal.vue'
import AddMemberModal from './modals/AddMemberModal.vue'
import AddPermissionModal from './modals/AddPermissionModal.vue'
import {
mapState
} from 'vuex';
import client from 'api-client';
import { mapState } from 'vuex';
export default {
name: 'Main',
......@@ -54,28 +51,7 @@ export default {
}),
methods: {
tabChanged: function(tabIndex) {
// reset paginator
this.input.paginatorPage = 1;