Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Coscine
frontend
apps
UserManagement
Commits
510d981a
Commit
510d981a
authored
Feb 17, 2020
by
Marcel Nellesen
Browse files
Merge branch 'Sprint/2020-02' into 'master'
Sprint/2020-02 See merge request coscine/app/usermanagement!23
parents
749d2904
27c656fe
Changes
6
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
package-lock.json
View file @
510d981a
This diff is collapsed.
Click to expand it.
package.json
View file @
510d981a
...
...
@@ -12,11 +12,11 @@
"test:unit"
:
"vue-cli-service test:unit"
},
"dependencies"
:
{
"
@coscine/api-connection
"
:
"
^1.
5
.0
"
,
"
@coscine/app-util
"
:
"
^1.
1
.0
"
,
"
@types/jquery
"
:
"
^3.3.3
1
"
,
"
@coscine/api-connection
"
:
"
^1.
8
.0
"
,
"
@coscine/app-util
"
:
"
^1.
2
.0
"
,
"
@types/jquery
"
:
"
^3.3.3
2
"
,
"
@types/vue-select
"
:
"
^2.5.0
"
,
"
bootstrap-vue
"
:
"
^2.
2.1
"
,
"
bootstrap-vue
"
:
"
^2.
4.2
"
,
"
jquery
"
:
"
^3.4.1
"
,
"
vue
"
:
"
^2.6.11
"
,
"
vue-i18n
"
:
"
^8.15.3
"
,
...
...
@@ -24,23 +24,23 @@
"
vue-select
"
:
"
^3.4.0
"
},
"devDependencies"
:
{
"
@semantic-release/commit-analyzer
"
:
"
^
6.3.3
"
,
"
@semantic-release/git
"
:
"
^
7
.0.
18
"
,
"
@semantic-release/gitlab
"
:
"
^
4.1.0
"
,
"
@semantic-release/npm
"
:
"
^
5.3.5
"
,
"
@semantic-release/release-notes-generator
"
:
"
^
7.3.5
"
,
"
@types/chai
"
:
"
^4.2.
7
"
,
"
@types/mocha
"
:
"
^
5.2.7
"
,
"
@vue/cli-plugin-babel
"
:
"
^4.
1
.2
"
,
"
@vue/cli-plugin-typescript
"
:
"
^4.
1
.2
"
,
"
@vue/cli-plugin-unit-mocha
"
:
"
^4.
1
.2
"
,
"
@vue/cli-service
"
:
"
^4.
1
.2
"
,
"
@vue/test-utils
"
:
"
1.0.0-beta.3
0
"
,
"
@semantic-release/commit-analyzer
"
:
"
^
8.0.1
"
,
"
@semantic-release/git
"
:
"
^
9
.0.
0
"
,
"
@semantic-release/gitlab
"
:
"
^
6.0.2
"
,
"
@semantic-release/npm
"
:
"
^
7.0.3
"
,
"
@semantic-release/release-notes-generator
"
:
"
^
9.0.0
"
,
"
@types/chai
"
:
"
^4.2.
9
"
,
"
@types/mocha
"
:
"
^
7.0.1
"
,
"
@vue/cli-plugin-babel
"
:
"
^4.
2
.2
"
,
"
@vue/cli-plugin-typescript
"
:
"
^4.
2
.2
"
,
"
@vue/cli-plugin-unit-mocha
"
:
"
^4.
2
.2
"
,
"
@vue/cli-service
"
:
"
^4.
2
.2
"
,
"
@vue/test-utils
"
:
"
1.0.0-beta.3
1
"
,
"
chai
"
:
"
^4.2.0
"
,
"
typescript
"
:
"
^3.7.
4
"
,
"
typescript
"
:
"
^3.7.
5
"
,
"
vue-template-compiler
"
:
"
^2.6.11
"
,
"
semantic-release
"
:
"
^1
5.14.0
"
,
"
@hutson/semantic-delivery-gitlab
"
:
"
^9.
0.8
"
"
semantic-release
"
:
"
^1
7.0.3
"
,
"
@hutson/semantic-delivery-gitlab
"
:
"
^9.
1.0
"
},
"repository"
:
{
"type"
:
"git"
,
...
...
src/App.vue
View file @
510d981a
...
...
@@ -8,6 +8,7 @@
<
script
lang=
"ts"
>
import
Vue
from
'
vue
'
;
import
UserManagement
from
'
./components/UserManagement.vue
'
;
import
{
GuidUtil
}
from
'
@coscine/app-util
'
;
export
default
Vue
.
extend
({
name
:
'
users
'
,
...
...
@@ -17,16 +18,8 @@ export default Vue.extend({
projectId
:
''
,
};
},
methods
:
{
getProjectId
()
{
const
baseUrl
=
(
_spPageContextInfo
as
any
).
siteAbsoluteUrl
;
const
splitUrl
=
baseUrl
.
split
(
'
/
'
);
const
projectUri
=
splitUrl
[
splitUrl
.
length
-
1
];
return
projectUri
;
},
},
beforeMount
()
{
this
.
projectId
=
this
.
getProjectId
();
created
()
{
this
.
projectId
=
GuidUtil
.
getProjectId
();
},
components
:
{
UserManagement
,
...
...
src/components/UserManagement.vue
View file @
510d981a
<
template
>
<div
class=
"UserManagement"
>
<div
class=
"UserManagement"
>
<b-container>
<b-row
align-h=
"between"
>
<b-row
align-h=
"between"
>
<b-col
md=
"6"
align-self=
"start"
>
<div
class=
"adaptAlign"
>
<b-row>
<b-col
sm=
"5"
@
keydown.enter.prevent.self=
""
>
<v-select
v-model=
"searchString"
:class=
"
{'adaptSelect':true, 'no-results':(queriedUsers.length === 0)}" :placeholder="$t('searchUserPlaceholder')" :options="queriedUsers" :filterBy="filterMock" @change="validateSelection()" @input="setNewRole" @search="
fetchUserOptions
">
<v-select
v-model=
"searchString"
:class=
"
{'adaptSelect':true, 'no-results':(queriedUsers.length === 0)}" :placeholder="$t('searchUserPlaceholder')" :options="queriedUsers" :filterBy="filterMock" @change="validateSelection()" @input="setNewRole" @search="
triggerFetchOptions" :selectable="option => !option.hasProjectRole
">
<template
v-if=
"searchString !== ''"
slot=
"no-options"
>
{{
$t
(
'
noUserOptions
'
)
}}
</
template
>
...
...
@@ -15,7 +15,7 @@
</
template
>
<
template
slot=
"option"
slot-scope=
"option"
>
<div
class=
"d-center"
>
{{
option
.
displayName
}}
{{
option
.
displayName
}}
<span
v-if=
option.hasProjectRole
>
{{
$t
(
'
alreadyGotRole
'
)
}}
</span>
</div>
</
template
>
<
template
slot=
"selected-option"
slot-scope=
"option"
>
...
...
@@ -30,7 +30,7 @@
v-model=
"newUserRole.role.id"
:options=
"roles"
@
change=
"validateSelection()"
@
input=
"validateSelection()"
>
@
input=
"validateSelection()"
>
</b-form-select>
</b-col>
<b-col
sm=
"4"
>
...
...
@@ -46,15 +46,15 @@
type=
"search"
id=
"filterInput"
:placeholder=
"$t('typeToSearch')"
></b-form-input>
></b-form-input>
</b-input-group>
</b-col>
</b-row>
<br>
<b-row>
<b-col>
<b-table
id=
"userTable"
<b-table
id=
"userTable"
:fields=
"headers"
:items=
"projectRoles"
:busy=
"isBusy"
...
...
@@ -71,7 +71,7 @@
striped
bordered
outlined
hover
hover
head-variant=
"dark"
class=
"adaptTable"
@
filtered=
"onFiltered"
...
...
@@ -80,7 +80,7 @@
<b-spinner
class=
"align-middle"
></b-spinner>
<strong
style=
"margin-left: 1%;"
>
{{ $t('loading') }}
</strong>
</div>
<
template
v-slot:cell(roleName)=
"row"
>
<
template
v-slot:cell(roleName)=
"row"
>
<b-form-select
v-model=
"row.item.role.id"
:options=
"roles"
...
...
@@ -92,19 +92,19 @@
<button
type=
"button"
class=
"btn btn-secondary deleteUser"
:disabled=
"!row.item.enabledControls"
name=
"deleteUser"
v-on:click=
"prepareDeletion(row.item)"
>
{{
$t
(
'
deleteUser
'
)
}}
</button>
</
template
>
</b-table>
</b-col>
</b-col>
</b-row>
<b-row>
<b-col
id=
"perPageSelection"
sm=
"2"
>
<b-col
id=
"perPageSelection"
sm=
"2"
>
<label
for=
"perPageSelect"
>
{{ $t('perPage') }}
</label>
<b-form-select
<b-form-select
v-model=
"perPage"
id=
"perPageSelect"
size=
"sm"
:options=
"pageOptions"
></b-form-select>
</b-col>
<b-col
v-if=
"filteredRows > perPage"
offset-sm=
"7"
sm=
"3"
>
<b-col
v-if=
"filteredRows > perPage"
offset-sm=
"7"
sm=
"3"
>
<b-pagination
v-model=
"currentPage"
:total-rows=
"filteredRows"
...
...
@@ -132,8 +132,11 @@
<
script
lang=
"ts"
>
import
Vue
from
'
vue
'
;
import
{
RoleApi
,
UserApi
,
ProjectRoleApi
,
ProjectApi
,
defaultOnCatch
}
from
'
@coscine/api-connection
'
;
import
{
LanguageUtil
}
from
'
@coscine/app-util
'
;
import
vSelect
from
'
vue-select
'
;
import
'
vue-select/dist/vue-select.css
'
;
import
{
ToastPlugin
}
from
'
bootstrap-vue
'
;
Vue
.
use
(
ToastPlugin
);
Vue
.
component
(
'
v-select
'
,
vSelect
);
...
...
@@ -141,11 +144,9 @@ export default Vue.extend({
name
:
'
UserManagement
'
,
created
()
{
ProjectApi
.
getProjectInformation
(
this
.
parentId
,
(
response
:
any
)
=>
{
this
.
projectName
=
response
.
data
.
displayName
;
},
defaultOnCatch
);
(
response
:
any
)
=>
{
this
.
projectName
=
response
.
data
.
displayName
;
});
},
mounted
()
{
// TODO: Add catch and do something on failure
RoleApi
.
getRoles
(
(
response
:
any
)
=>
{
for
(
const
datum
of
response
.
data
)
{
this
.
roles
.
push
({
value
:
datum
.
id
,
text
:
datum
.
displayName
});
...
...
@@ -154,9 +155,7 @@ export default Vue.extend({
this
.
newUserRole
.
role
.
id
=
this
.
roleDefaultId
;
}
}
},
defaultOnCatch
,
);
});
this
.
getProjectRoles
();
},
data
()
{
...
...
@@ -214,6 +213,7 @@ export default Vue.extend({
},
},
queriedUsers
:
[]
as
object
[],
queryTimer
:
0
,
searchString
:
''
,
selectionIsValid
:
false
,
ownerCount
:
0
,
...
...
@@ -254,6 +254,15 @@ export default Vue.extend({
this
.
newUserRole
.
user
=
value
;
this
.
validateSelection
();
},
triggerFetchOptions
(
search
:
string
,
loading
:
(
value
:
boolean
)
=>
{})
{
clearTimeout
(
this
.
queryTimer
);
if
(
search
.
length
<
3
)
{
this
.
queriedUsers
=
[];
return
;
}
this
.
queryTimer
=
setTimeout
(()
=>
(
this
.
fetchUserOptions
(
search
,
loading
)),
1000
)
;
},
fetchUserOptions
(
search
:
string
,
loading
:
(
value
:
boolean
)
=>
{})
{
if
(
search
!==
''
)
{
loading
(
true
);
...
...
@@ -308,9 +317,20 @@ export default Vue.extend({
})
{
projectRole
.
projectId
=
this
.
parentId
;
projectRole
.
role
.
displayName
=
projectRole
.
role
.
displayName
===
'
Member
'
?
'
Owner
'
:
'
Member
'
;
let
text
=
''
;
if
(
LanguageUtil
.
getLanguage
()
===
'
de
'
)
{
text
=
this
.
$t
(
'
changedRole1
'
)
+
projectRole
.
user
.
displayName
+
this
.
$t
(
'
changedRole2
'
)
+
this
.
getRoleNameFromId
(
projectRole
.
role
.
id
)
+
this
.
$t
(
'
changedRole3
'
)
+
this
.
projectName
;
}
else
{
text
=
this
.
$t
(
'
changedRole1
'
)
+
projectRole
.
user
.
displayName
+
this
.
$t
(
'
changedRole2
'
)
+
this
.
projectName
+
this
.
$t
(
'
changedRole3
'
)
+
projectRole
.
role
.
displayName
;
}
ProjectRoleApi
.
setProjectRole
(
projectRole
,
(
response
:
any
)
=>
{
this
.
makeToast
(
text
,
this
.
$t
(
'
userManagement
'
).
toString
());
if
(
projectRole
.
role
.
displayName
===
'
Owner
'
)
{
this
.
ownerCount
++
;
}
else
{
...
...
@@ -323,20 +343,41 @@ export default Vue.extend({
((
currentProjectRole
as
any
).
role
.
displayName
!==
'
Owner
'
||
this
.
ownerCount
>
1
));
}
}
},
defaultOnCatch
);
});
},
getRoleNameFromId
(
roleId
:
string
)
{
for
(
const
role
of
this
.
roles
)
{
if
((
role
as
any
).
value
===
roleId
)
{
return
(
role
as
any
).
text
;
}
}
},
addUser
(
projectRole
:
{
projectId
:
string
,
user
:
{
id
:
string
,
displayName
:
string
,
givenname
:
string
,
surname
:
string
,
emailAddress
:
string
},
role
:
{
id
:
string
,
displayName
:
string
},
})
{
this
.
selectionIsValid
=
false
;
this
.
searchString
=
''
;
projectRole
.
projectId
=
this
.
parentId
;
let
text
=
''
;
if
(
LanguageUtil
.
getLanguage
()
===
'
de
'
)
{
text
=
this
.
$t
(
'
addedUser1
'
)
+
projectRole
.
user
.
displayName
+
this
.
$t
(
'
addedUser2
'
)
+
this
.
getRoleNameFromId
(
projectRole
.
role
.
id
)
+
this
.
$t
(
'
addedUser3
'
)
+
this
.
projectName
+
this
.
$t
(
'
addedUser4
'
);
}
else
{
text
=
this
.
$t
(
'
addedUser1
'
)
+
projectRole
.
user
.
displayName
+
this
.
$t
(
'
addedUser2
'
)
+
this
.
projectName
+
this
.
$t
(
'
addedUser3
'
)
+
this
.
getRoleNameFromId
(
projectRole
.
role
.
id
)
+
this
.
$t
(
'
addedUser4
'
);
}
ProjectRoleApi
.
setProjectRole
(
projectRole
,
(
response
:
any
)
=>
{
this
.
getProjectRoles
();
},
defaultOnCatch
);
(
response
:
any
)
=>
{
this
.
getProjectRoles
();
this
.
makeToast
(
text
,
this
.
$t
(
'
userManagement
'
).
toString
());
this
.
queriedUsers
=
[];
this
.
newUserRole
.
user
.
id
=
''
;
});
},
prepareDeletion
(
projectRole
:
{
projectId
:
string
,
...
...
@@ -347,11 +388,15 @@ export default Vue.extend({
this
.
$bvModal
.
show
(
'
deleteUserModal
'
);
},
deleteUser
()
{
const
text
=
this
.
$t
(
'
removedUser1
'
)
+
this
.
candidateForDeletion
.
user
.
displayName
+
this
.
$t
(
'
removedUser2
'
)
+
this
.
projectName
+
this
.
$t
(
'
removedUser3
'
);
ProjectRoleApi
.
deleteUser
(
this
.
candidateForDeletion
.
projectId
,
this
.
candidateForDeletion
.
user
.
id
,
this
.
candidateForDeletion
.
role
.
id
,
(
response
:
any
)
=>
{
this
.
getProjectRoles
();
},
(
response
:
any
)
=>
{
this
.
getProjectRoles
();
this
.
makeToast
(
text
,
this
.
$t
(
'
userManagement
'
).
toString
());
},
defaultOnCatch
);
},
filterMock
(
option
:
any
,
label
:
any
,
search
:
string
)
{
...
...
@@ -361,6 +406,17 @@ export default Vue.extend({
this
.
filteredRows
=
filteredItems
.
length
;
this
.
currentPage
=
1
;
},
makeToast
(
text
:
string
=
'
Message
'
,
givenTitle
:
string
=
'
Title
'
)
{
this
.
$bvToast
.
toast
(
text
,
{
title
:
givenTitle
,
autoHideDelay
:
5000
,
toaster
:
'
b-toaster-bottom-right
'
,
noCloseButton
:
true
,
},
);
},
},
});
</
script
>
...
...
@@ -378,7 +434,7 @@ export default Vue.extend({
}
.UserManagement
.adaptAlign
.col-sm-5
.no-results
.vs__actions
{
display
:
none
;
}
}
.UserManagement
.adaptAlign
.col-sm-4
{
padding-right
:
4px
;
padding-left
:
0px
;
...
...
@@ -390,15 +446,15 @@ export default Vue.extend({
.UserManagement
.col-sm-3
{
padding-right
:
4px
;
padding-left
:
0px
;
text-align
:
left
;
text-align
:
left
;
}
.UserManagement
.col-sm-3
#perPageSelect
{
padding-right
:
4px
;
text-align
:
left
;
margin-left
:
0px
;
padding-left
:
0px
;
padding-left
:
0px
;
}
.UserManagement
.adaptTable
.deleteUser
:hover
{
background-color
:
#9b0517
;
...
...
src/locale/de.ts
View file @
510d981a
...
...
@@ -13,6 +13,7 @@ export default {
clear
:
'
Leeren
'
,
perPage
:
'
Pro Seite
'
,
searchUserPlaceholder
:
'
Nutzer suchen...
'
,
alreadyGotRole
:
'
(bereits Teilnehmer)
'
,
selectRolePlaceholder
:
'
Rolle auswählen
'
,
firstName
:
'
Vorname
'
,
lastName
:
'
Nachname
'
,
...
...
@@ -28,4 +29,14 @@ export default {
cancel
:
'
Abbrechen
'
,
emptyTableText
:
'
Keine Nutzer gefunden.
'
,
emptyFilterText
:
'
Keine Nutzer gefunden die mit Ihrer Anfrage übereinstimmen.
'
,
addedUser1
:
''
,
addedUser2
:
'
als
'
,
addedUser3
:
'
zu
'
,
addedUser4
:
'
hinzugefügt
'
,
removedUser1
:
''
,
removedUser2
:
'
von
'
,
removedUser3
:
'
gelöscht
'
,
changedRole1
:
''
,
changedRole2
:
'
ist nun
'
,
changedRole3
:
'
in
'
,
};
src/locale/en.ts
View file @
510d981a
...
...
@@ -13,6 +13,7 @@ export default {
clear
:
'
Clear
'
,
perPage
:
'
Per page
'
,
searchUserPlaceholder
:
'
Search a user...
'
,
alreadyGotRole
:
'
(Already added)
'
,
selectRolePlaceholder
:
'
Select Role
'
,
firstName
:
'
First Name
'
,
lastName
:
'
Last Name
'
,
...
...
@@ -28,4 +29,14 @@ export default {
cancel
:
'
Cancel
'
,
emptyTableText
:
'
No user found.
'
,
emptyFilterText
:
'
No user found matching your request.
'
,
addedUser1
:
'
Added
'
,
addedUser2
:
'
to
'
,
addedUser3
:
'
as
'
,
addedUser4
:
''
,
removedUser1
:
'
Removed
'
,
removedUser2
:
'
from
'
,
removedUser3
:
''
,
changedRole1
:
'
Changed
'
,
changedRole2
:
'
in
'
,
changedRole3
:
'
to
'
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment