Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
7bb01092
Commit
7bb01092
authored
Sep 14, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: dashboard permissions are working
parent
c7fdea1d
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
117 additions
and
620 deletions
+117
-620
public/app/core/components/PermissionList/AddPermission.tsx
+2
-1
public/app/core/components/PermissionList/PermissionsInfo.tsx
+0
-0
public/app/core/components/Permissions/AddPermissions.test.tsx
+0
-90
public/app/core/components/Permissions/AddPermissions.tsx
+0
-128
public/app/core/components/Permissions/DashboardPermissions.tsx
+0
-71
public/app/core/components/Permissions/DisabledPermissionsListItem.tsx
+0
-43
public/app/core/components/Permissions/FolderInfo.ts
+0
-5
public/app/core/components/Permissions/Permissions.tsx
+0
-91
public/app/core/components/Permissions/PermissionsList.tsx
+0
-64
public/app/core/components/Permissions/PermissionsListItem.tsx
+0
-91
public/app/features/dashboard/DashboardPermissions/DashboardPermissions.tsx
+17
-6
public/app/features/dashboard/state/actions.ts
+1
-1
public/app/features/folders/FolderPermissions.tsx
+1
-1
public/app/features/folders/state/reducers.test.ts
+74
-18
public/app/types/acl.ts
+14
-10
public/app/types/index.ts
+5
-0
scripts/webpack/webpack.common.js
+3
-0
No files found.
public/app/core/components/PermissionList/AddPermission.tsx
View file @
7bb01092
...
...
@@ -8,6 +8,7 @@ import {
AclTarget
,
PermissionLevel
,
NewDashboardAclItem
,
OrgRole
,
}
from
'app/types/acl'
;
export
interface
Props
{
...
...
@@ -25,7 +26,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
return
{
userId
:
0
,
teamId
:
0
,
role
:
''
,
role
:
OrgRole
.
Viewer
,
type
:
AclTarget
.
Team
,
permission
:
PermissionLevel
.
View
,
};
...
...
public/app/core/components/Permission
s
/PermissionsInfo.tsx
→
public/app/core/components/Permission
List
/PermissionsInfo.tsx
View file @
7bb01092
File moved
public/app/core/components/Permissions/AddPermissions.test.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
AddPermissions
from
'./AddPermissions'
;
import
{
RootStore
}
from
'app/stores/RootStore/RootStore'
;
import
{
getBackendSrv
}
from
'app/core/services/backend_srv'
;
jest
.
mock
(
'app/core/services/backend_srv'
,
()
=>
({
getBackendSrv
:
()
=>
{
return
{
get
:
()
=>
{
return
Promise
.
resolve
([
{
id
:
2
,
dashboardId
:
1
,
role
:
'Viewer'
,
permission
:
1
,
permissionName
:
'View'
},
{
id
:
3
,
dashboardId
:
1
,
role
:
'Editor'
,
permission
:
1
,
permissionName
:
'Edit'
},
]);
},
post
:
jest
.
fn
(()
=>
Promise
.
resolve
({})),
};
},
}));
describe
(
'AddPermissions'
,
()
=>
{
let
wrapper
;
let
store
;
let
instance
;
const
backendSrv
:
any
=
getBackendSrv
();
beforeAll
(()
=>
{
store
=
RootStore
.
create
({},
{
backendSrv
:
backendSrv
});
wrapper
=
shallow
(<
AddPermissions
permissions=
{
store
.
permissions
}
/>);
instance
=
wrapper
.
instance
();
return
store
.
permissions
.
load
(
1
,
true
,
false
);
});
describe
(
'when permission for a user is added'
,
()
=>
{
it
(
'should save permission to db'
,
()
=>
{
const
evt
=
{
target
:
{
value
:
'User'
,
},
};
const
userItem
=
{
id
:
2
,
login
:
'user2'
,
};
instance
.
onTypeChanged
(
evt
);
instance
.
onUserSelected
(
userItem
);
wrapper
.
update
();
expect
(
wrapper
.
find
(
'[data-save-permission]'
).
prop
(
'disabled'
)).
toBe
(
false
);
wrapper
.
find
(
'form'
).
simulate
(
'submit'
,
{
preventDefault
()
{}
});
expect
(
backendSrv
.
post
.
mock
.
calls
.
length
).
toBe
(
1
);
expect
(
backendSrv
.
post
.
mock
.
calls
[
0
][
0
]).
toBe
(
'/api/dashboards/id/1/permissions'
);
});
});
describe
(
'when permission for team is added'
,
()
=>
{
it
(
'should save permission to db'
,
()
=>
{
const
evt
=
{
target
:
{
value
:
'Group'
,
},
};
const
teamItem
=
{
id
:
2
,
name
:
'ug1'
,
};
instance
.
onTypeChanged
(
evt
);
instance
.
onTeamSelected
(
teamItem
);
wrapper
.
update
();
expect
(
wrapper
.
find
(
'[data-save-permission]'
).
prop
(
'disabled'
)).
toBe
(
false
);
wrapper
.
find
(
'form'
).
simulate
(
'submit'
,
{
preventDefault
()
{}
});
expect
(
backendSrv
.
post
.
mock
.
calls
.
length
).
toBe
(
1
);
expect
(
backendSrv
.
post
.
mock
.
calls
[
0
][
0
]).
toBe
(
'/api/dashboards/id/1/permissions'
);
});
});
afterEach
(()
=>
{
backendSrv
.
post
.
mockClear
();
});
});
public/app/core/components/Permissions/AddPermissions.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
,
{
Component
}
from
'react'
;
import
{
observer
}
from
'mobx-react'
;
import
{
aclTypes
}
from
'app/stores/PermissionsStore/PermissionsStore'
;
import
{
UserPicker
,
User
}
from
'app/core/components/Picker/UserPicker'
;
import
{
TeamPicker
,
Team
}
from
'app/core/components/Picker/TeamPicker'
;
import
DescriptionPicker
,
{
OptionWithDescription
}
from
'app/core/components/Picker/DescriptionPicker'
;
import
{
permissionOptions
}
from
'app/stores/PermissionsStore/PermissionsStore'
;
export
interface
Props
{
permissions
:
any
;
}
@
observer
class
AddPermissions
extends
Component
<
Props
,
any
>
{
constructor
(
props
)
{
super
(
props
);
}
componentWillMount
()
{
const
{
permissions
}
=
this
.
props
;
permissions
.
resetNewType
();
}
onTypeChanged
=
evt
=>
{
const
{
value
}
=
evt
.
target
;
const
{
permissions
}
=
this
.
props
;
permissions
.
setNewType
(
value
);
};
onUserSelected
=
(
user
:
User
)
=>
{
const
{
permissions
}
=
this
.
props
;
if
(
!
user
)
{
permissions
.
newItem
.
setUser
(
null
,
null
);
return
;
}
return
permissions
.
newItem
.
setUser
(
user
.
id
,
user
.
login
,
user
.
avatarUrl
);
};
onTeamSelected
=
(
team
:
Team
)
=>
{
const
{
permissions
}
=
this
.
props
;
if
(
!
team
)
{
permissions
.
newItem
.
setTeam
(
null
,
null
);
return
;
}
return
permissions
.
newItem
.
setTeam
(
team
.
id
,
team
.
name
,
team
.
avatarUrl
);
};
onPermissionChanged
=
(
permission
:
OptionWithDescription
)
=>
{
const
{
permissions
}
=
this
.
props
;
return
permissions
.
newItem
.
setPermission
(
permission
.
value
);
};
resetNewType
()
{
const
{
permissions
}
=
this
.
props
;
return
permissions
.
resetNewType
();
}
onSubmit
=
evt
=>
{
evt
.
preventDefault
();
const
{
permissions
}
=
this
.
props
;
permissions
.
addStoreItem
();
};
render
()
{
const
{
permissions
}
=
this
.
props
;
const
newItem
=
permissions
.
newItem
;
const
pickerClassName
=
'width-20'
;
const
isValid
=
newItem
.
isValid
();
return
(
<
div
className=
"gf-form-inline cta-form"
>
<
button
className=
"cta-form__close btn btn-transparent"
onClick=
{
permissions
.
hideAddPermissions
}
>
<
i
className=
"fa fa-close"
/>
</
button
>
<
form
name=
"addPermission"
onSubmit=
{
this
.
onSubmit
}
>
<
h5
>
Add Permission For
</
h5
>
<
div
className=
"gf-form-inline"
>
<
div
className=
"gf-form"
>
<
div
className=
"gf-form-select-wrapper"
>
<
select
className=
"gf-form-input gf-size-auto"
value=
{
newItem
.
type
}
onChange=
{
this
.
onTypeChanged
}
>
{
aclTypes
.
map
((
option
,
idx
)
=>
{
return
(
<
option
key=
{
idx
}
value=
{
option
.
value
}
>
{
option
.
text
}
</
option
>
);
})
}
</
select
>
</
div
>
</
div
>
{
newItem
.
type
===
'User'
?
(
<
div
className=
"gf-form"
>
<
UserPicker
onSelected=
{
this
.
onUserSelected
}
value=
{
newItem
.
userId
}
className=
{
pickerClassName
}
/>
</
div
>
)
:
null
}
{
newItem
.
type
===
'Group'
?
(
<
div
className=
"gf-form"
>
<
TeamPicker
onSelected=
{
this
.
onTeamSelected
}
value=
{
newItem
.
teamId
}
className=
{
pickerClassName
}
/>
</
div
>
)
:
null
}
<
div
className=
"gf-form"
>
<
DescriptionPicker
optionsWithDesc=
{
permissionOptions
}
onSelected=
{
this
.
onPermissionChanged
}
value=
{
newItem
.
permission
}
disabled=
{
false
}
className=
{
'gf-form-input--form-dropdown-right'
}
/>
</
div
>
<
div
className=
"gf-form"
>
<
button
data
-
save
-
permission
className=
"btn btn-success"
type=
"submit"
disabled=
{
!
isValid
}
>
Save
</
button
>
</
div
>
</
div
>
</
form
>
</
div
>
);
}
}
export
default
AddPermissions
;
public/app/core/components/Permissions/DashboardPermissions.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
,
{
Component
}
from
'react'
;
import
{
observer
}
from
'mobx-react'
;
import
{
store
}
from
'app/stores/store'
;
import
Permissions
from
'app/core/components/Permissions/Permissions'
;
import
Tooltip
from
'app/core/components/Tooltip/Tooltip'
;
import
PermissionsInfo
from
'app/core/components/Permissions/PermissionsInfo'
;
import
AddPermissions
from
'app/core/components/Permissions/AddPermissions'
;
import
SlideDown
from
'app/core/components/Animations/SlideDown'
;
import
{
FolderInfo
}
from
'./FolderInfo'
;
export
interface
Props
{
dashboardId
:
number
;
folder
?:
FolderInfo
;
backendSrv
:
any
;
}
@
observer
class
DashboardPermissions
extends
Component
<
Props
,
any
>
{
permissions
:
any
;
constructor
(
props
)
{
super
(
props
);
this
.
handleAddPermission
=
this
.
handleAddPermission
.
bind
(
this
);
this
.
permissions
=
store
.
permissions
;
}
handleAddPermission
()
{
this
.
permissions
.
toggleAddPermissions
();
}
componentWillUnmount
()
{
this
.
permissions
.
hideAddPermissions
();
}
render
()
{
const
{
dashboardId
,
folder
,
backendSrv
}
=
this
.
props
;
return
(
<
div
>
<
div
className=
"dashboard-settings__header"
>
<
div
className=
"page-action-bar"
>
<
h3
className=
"d-inline-block"
>
Permissions
</
h3
>
<
Tooltip
className=
"page-sub-heading-icon"
placement=
"auto"
content=
{
PermissionsInfo
}
>
<
i
className=
"gicon gicon-question gicon--has-hover"
/>
</
Tooltip
>
<
div
className=
"page-action-bar__spacer"
/>
<
button
className=
"btn btn-success pull-right"
onClick=
{
this
.
handleAddPermission
}
disabled=
{
this
.
permissions
.
isAddPermissionsVisible
}
>
<
i
className=
"fa fa-plus"
/>
Add Permission
</
button
>
</
div
>
</
div
>
<
SlideDown
in=
{
this
.
permissions
.
isAddPermissionsVisible
}
>
<
AddPermissions
permissions=
{
this
.
permissions
}
/>
</
SlideDown
>
<
Permissions
permissions=
{
this
.
permissions
}
isFolder=
{
false
}
dashboardId=
{
dashboardId
}
folderInfo=
{
folder
}
backendSrv=
{
backendSrv
}
/>
</
div
>
);
}
}
export
default
DashboardPermissions
;
public/app/core/components/Permissions/DisabledPermissionsListItem.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
,
{
Component
}
from
'react'
;
import
DescriptionPicker
from
'app/core/components/Picker/DescriptionPicker'
;
import
{
permissionOptions
}
from
'app/stores/PermissionsStore/PermissionsStore'
;
export
interface
Props
{
item
:
any
;
}
export
default
class
DisabledPermissionListItem
extends
Component
<
Props
,
any
>
{
render
()
{
const
{
item
}
=
this
.
props
;
return
(
<
tr
className=
"gf-form-disabled"
>
<
td
style=
{
{
width
:
'1%'
}
}
>
<
i
style=
{
{
width
:
'25px'
,
height
:
'25px'
}
}
className=
"gicon gicon-shield"
/>
</
td
>
<
td
style=
{
{
width
:
'90%'
}
}
>
{
item
.
name
}
<
span
className=
"filter-table__weak-italic"
>
(Role)
</
span
>
</
td
>
<
td
/>
<
td
className=
"query-keyword"
>
Can
</
td
>
<
td
>
<
div
className=
"gf-form"
>
<
DescriptionPicker
optionsWithDesc=
{
permissionOptions
}
onSelected=
{
()
=>
{}
}
value=
{
item
.
permission
}
disabled=
{
true
}
className=
{
'gf-form-input--form-dropdown-right'
}
/>
</
div
>
</
td
>
<
td
>
<
button
className=
"btn btn-inverse btn-small"
>
<
i
className=
"fa fa-lock"
/>
</
button
>
</
td
>
</
tr
>
);
}
}
public/app/core/components/Permissions/FolderInfo.ts
deleted
100644 → 0
View file @
c7fdea1d
export
interface
FolderInfo
{
id
:
number
;
title
:
string
;
url
:
string
;
}
public/app/core/components/Permissions/Permissions.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
,
{
Component
}
from
'react'
;
import
PermissionsList
from
'./PermissionsList'
;
import
{
observer
}
from
'mobx-react'
;
import
{
FolderInfo
}
from
'./FolderInfo'
;
export
interface
DashboardAcl
{
id
?:
number
;
dashboardId
?:
number
;
userId
?:
number
;
userLogin
?:
string
;
userEmail
?:
string
;
teamId
?:
number
;
team
?:
string
;
permission
?:
number
;
permissionName
?:
string
;
role
?:
string
;
icon
?:
string
;
name
?:
string
;
inherited
?:
boolean
;
sortRank
?:
number
;
}
export
interface
Props
{
dashboardId
:
number
;
folderInfo
?:
FolderInfo
;
permissions
?:
any
;
isFolder
:
boolean
;
backendSrv
:
any
;
}
@
observer
class
Permissions
extends
Component
<
Props
,
any
>
{
constructor
(
props
)
{
super
(
props
);
const
{
dashboardId
,
isFolder
,
folderInfo
}
=
this
.
props
;
this
.
permissionChanged
=
this
.
permissionChanged
.
bind
(
this
);
this
.
typeChanged
=
this
.
typeChanged
.
bind
(
this
);
this
.
removeItem
=
this
.
removeItem
.
bind
(
this
);
this
.
loadStore
(
dashboardId
,
isFolder
,
folderInfo
&&
folderInfo
.
id
===
0
);
}
loadStore
(
dashboardId
,
isFolder
,
isInRoot
=
false
)
{
return
this
.
props
.
permissions
.
load
(
dashboardId
,
isFolder
,
isInRoot
);
}
permissionChanged
(
index
:
number
,
permission
:
number
,
permissionName
:
string
)
{
const
{
permissions
}
=
this
.
props
;
permissions
.
updatePermissionOnIndex
(
index
,
permission
,
permissionName
);
}
removeItem
(
index
:
number
)
{
const
{
permissions
}
=
this
.
props
;
permissions
.
removeStoreItem
(
index
);
}
resetNewType
()
{
const
{
permissions
}
=
this
.
props
;
permissions
.
resetNewType
();
}
typeChanged
(
evt
)
{
const
{
value
}
=
evt
.
target
;
const
{
permissions
,
dashboardId
}
=
this
.
props
;
if
(
value
===
'Viewer'
||
value
===
'Editor'
)
{
permissions
.
addStoreItem
({
permission
:
1
,
role
:
value
,
dashboardId
:
dashboardId
},
dashboardId
);
this
.
resetNewType
();
return
;
}
permissions
.
setNewType
(
value
);
}
render
()
{
const
{
permissions
,
folderInfo
}
=
this
.
props
;
return
(
<
div
className=
"gf-form-group"
>
<
PermissionsList
permissions=
{
permissions
.
items
}
removeItem=
{
this
.
removeItem
}
permissionChanged=
{
this
.
permissionChanged
}
fetching=
{
permissions
.
fetching
}
folderInfo=
{
folderInfo
}
/>
</
div
>
);
}
}
export
default
Permissions
;
public/app/core/components/Permissions/PermissionsList.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
,
{
Component
}
from
'react'
;
import
PermissionsListItem
from
'./PermissionsListItem'
;
import
DisabledPermissionsListItem
from
'./DisabledPermissionsListItem'
;
import
{
observer
}
from
'mobx-react'
;
import
{
FolderInfo
}
from
'./FolderInfo'
;
export
interface
Props
{
permissions
:
any
[];
removeItem
:
any
;
permissionChanged
:
any
;
fetching
:
boolean
;
folderInfo
?:
FolderInfo
;
}
@
observer
class
PermissionsList
extends
Component
<
Props
,
any
>
{
render
()
{
const
{
permissions
,
removeItem
,
permissionChanged
,
fetching
,
folderInfo
}
=
this
.
props
;
return
(
<
table
className=
"filter-table gf-form-group"
>
<
tbody
>
<
DisabledPermissionsListItem
key=
{
0
}
item=
{
{
name
:
'Admin'
,
permission
:
4
,
icon
:
'fa fa-fw fa-street-view'
,
}
}
/>
{
permissions
.
map
((
item
,
idx
)
=>
{
return
(
<
PermissionsListItem
key=
{
idx
+
1
}
item=
{
item
}
itemIndex=
{
idx
}
removeItem=
{
removeItem
}
permissionChanged=
{
permissionChanged
}
folderInfo=
{
folderInfo
}
/>
);
})
}
{
fetching
===
true
&&
permissions
.
length
<
1
?
(
<
tr
>
<
td
colSpan=
{
4
}
>
<
em
>
Loading permissions...
</
em
>
</
td
>
</
tr
>
)
:
null
}
{
fetching
===
false
&&
permissions
.
length
<
1
?
(
<
tr
>
<
td
colSpan=
{
4
}
>
<
em
>
No permissions are set. Will only be accessible by admins.
</
em
>
</
td
>
</
tr
>
)
:
null
}
</
tbody
>
</
table
>
);
}
}
export
default
PermissionsList
;
public/app/core/components/Permissions/PermissionsListItem.tsx
deleted
100644 → 0
View file @
c7fdea1d
import
React
from
'react'
;
import
{
observer
}
from
'mobx-react'
;
import
DescriptionPicker
from
'app/core/components/Picker/DescriptionPicker'
;
import
{
permissionOptions
}
from
'app/stores/PermissionsStore/PermissionsStore'
;
const
setClassNameHelper
=
inherited
=>
{
return
inherited
?
'gf-form-disabled'
:
''
;
};
function
ItemAvatar
({
item
})
{
if
(
item
.
userAvatarUrl
)
{
return
<
img
className=
"filter-table__avatar"
src=
{
item
.
userAvatarUrl
}
/>;
}
if
(
item
.
teamAvatarUrl
)
{
return
<
img
className=
"filter-table__avatar"
src=
{
item
.
teamAvatarUrl
}
/>;
}
if
(
item
.
role
===
'Editor'
)
{
return
<
i
style=
{
{
width
:
'25px'
,
height
:
'25px'
}
}
className=
"gicon gicon-editor"
/>;
}
return
<
i
style=
{
{
width
:
'25px'
,
height
:
'25px'
}
}
className=
"gicon gicon-viewer"
/>;
}
function
ItemDescription
({
item
})
{
if
(
item
.
userId
)
{
return
<
span
className=
"filter-table__weak-italic"
>
(User)
</
span
>;
}
if
(
item
.
teamId
)
{
return
<
span
className=
"filter-table__weak-italic"
>
(Team)
</
span
>;
}
return
<
span
className=
"filter-table__weak-italic"
>
(Role)
</
span
>;
}
export
default
observer
(({
item
,
removeItem
,
permissionChanged
,
itemIndex
,
folderInfo
})
=>
{
const
handleRemoveItem
=
evt
=>
{
evt
.
preventDefault
();
removeItem
(
itemIndex
);
};
const
handleChangePermission
=
permissionOption
=>
{
permissionChanged
(
itemIndex
,
permissionOption
.
value
,
permissionOption
.
label
);
};
const
inheritedFromRoot
=
item
.
dashboardId
===
-
1
&&
!
item
.
inherited
;
return
(
<
tr
className=
{
setClassNameHelper
(
item
.
inherited
)
}
>
<
td
style=
{
{
width
:
'1%'
}
}
>
<
ItemAvatar
item=
{
item
}
/>
</
td
>
<
td
style=
{
{
width
:
'90%'
}
}
>
{
item
.
name
}
<
ItemDescription
item=
{
item
}
/>
</
td
>
<
td
>
{
item
.
inherited
&&
folderInfo
&&
(
<
em
className=
"muted no-wrap"
>
Inherited from folder
{
' '
}
<
a
className=
"text-link"
href=
{
`${folderInfo.url}/permissions`
}
>
{
folderInfo
.
title
}
</
a
>
{
' '
}
</
em
>
)
}
{
inheritedFromRoot
&&
<
em
className=
"muted no-wrap"
>
Default Permission
</
em
>
}
</
td
>
<
td
className=
"query-keyword"
>
Can
</
td
>
<
td
>
<
div
className=
"gf-form"
>
<
DescriptionPicker
optionsWithDesc=
{
permissionOptions
}
onSelected=
{
handleChangePermission
}
value=
{
item
.
permission
}
disabled=
{
item
.
inherited
}
className=
{
'gf-form-input--form-dropdown-right'
}
/>
</
div
>
</
td
>
<
td
>
{
!
item
.
inherited
?
(
<
a
className=
"btn btn-danger btn-small"
onClick=
{
handleRemoveItem
}
>
<
i
className=
"fa fa-remove"
/>
</
a
>
)
:
(
<
button
className=
"btn btn-inverse btn-small"
>
<
i
className=
"fa fa-lock"
/>
</
button
>
)
}
</
td
>
</
tr
>
);
});
public/app/features/dashboard/DashboardPermissions/DashboardPermissions.tsx
View file @
7bb01092
...
...
@@ -4,17 +4,25 @@ import Tooltip from 'app/core/components/Tooltip/Tooltip';
import
SlideDown
from
'app/core/components/Animations/SlideDown'
;
import
{
StoreState
,
FolderInfo
}
from
'app/types'
;
import
{
DashboardAcl
,
PermissionLevel
,
NewDashboardAclItem
}
from
'app/types/acl'
;
import
{
getDashboardPermissions
}
from
'../state/actions'
;
import
{
getDashboardPermissions
,
addDashboardPermission
,
removeDashboardPermission
,
updateDashboardPermission
,
}
from
'../state/actions'
;
import
PermissionList
from
'app/core/components/PermissionList/PermissionList'
;
import
AddPermission
from
'app/core/components/PermissionList/AddPermission'
;
import
PermissionsInfo
from
'app/core/components/Permission
s
/PermissionsInfo'
;
import
PermissionsInfo
from
'app/core/components/Permission
List
/PermissionsInfo'
;
import
{
store
}
from
'app/stores/configureStore'
;
export
interface
Props
{
dashboardId
:
number
;
folder
?:
FolderInfo
;
getDashboardPermissions
:
typeof
getDashboardPermissions
;
permissions
:
DashboardAcl
[];
getDashboardPermissions
:
typeof
getDashboardPermissions
;
updateDashboardPermission
:
typeof
updateDashboardPermission
;
removeDashboardPermission
:
typeof
removeDashboardPermission
;
addDashboardPermission
:
typeof
addDashboardPermission
;
}
export
interface
State
{
...
...
@@ -39,15 +47,15 @@ export class DashboardPermissions extends PureComponent<Props, State> {
};
onRemoveItem
=
(
item
:
DashboardAcl
)
=>
{
// this.props.removeFolderPermission(
item);
this
.
props
.
removeDashboardPermission
(
this
.
props
.
dashboardId
,
item
);
};
onPermissionChanged
=
(
item
:
DashboardAcl
,
level
:
PermissionLevel
)
=>
{
// this.props.updateFolderPermission(
item, level);
this
.
props
.
updateDashboardPermission
(
this
.
props
.
dashboardId
,
item
,
level
);
};
onAddPermission
=
(
newItem
:
NewDashboardAclItem
)
=>
{
// return this.props.addFolderPermission(
newItem);
return
this
.
props
.
addDashboardPermission
(
this
.
props
.
dashboardId
,
newItem
);
};
onCancelAddPermission
=
()
=>
{
...
...
@@ -101,6 +109,9 @@ const mapStateToProps = (state: StoreState) => ({
const
mapDispatchToProps
=
{
getDashboardPermissions
,
addDashboardPermission
,
removeDashboardPermission
,
updateDashboardPermission
,
};
export
default
connectWithStore
(
DashboardPermissions
,
mapStateToProps
,
mapDispatchToProps
);
public/app/features/dashboard/state/actions.ts
View file @
7bb01092
...
...
@@ -68,7 +68,7 @@ export function updateDashboardPermission(
itemsToUpdate
.
push
(
updated
);
}
await
getBackendSrv
().
post
(
`/api/dashboard/id/
${
dashboardId
}
/permissions`
,
{
items
:
itemsToUpdate
});
await
getBackendSrv
().
post
(
`/api/dashboard
s
/id/
${
dashboardId
}
/permissions`
,
{
items
:
itemsToUpdate
});
await
dispatch
(
getDashboardPermissions
(
dashboardId
));
};
}
...
...
public/app/features/folders/FolderPermissions.tsx
View file @
7bb01092
...
...
@@ -17,7 +17,7 @@ import {
import
{
getLoadingNav
}
from
'./state/navModel'
;
import
PermissionList
from
'app/core/components/PermissionList/PermissionList'
;
import
AddPermission
from
'app/core/components/PermissionList/AddPermission'
;
import
PermissionsInfo
from
'app/core/components/Permission
s
/PermissionsInfo'
;
import
PermissionsInfo
from
'app/core/components/Permission
List
/PermissionsInfo'
;
export
interface
Props
{
navModel
:
NavModel
;
...
...
public/app/features/folders/state/reducers.test.ts
View file @
7bb01092
import
{
Action
,
ActionTypes
}
from
'./actions'
;
import
{
FolderDTO
}
from
'app/types'
;
import
{
FolderDTO
,
OrgRole
,
PermissionLevel
,
FolderState
}
from
'app/types'
;
import
{
inititalState
,
folderReducer
}
from
'./reducers'
;
function
getTestFolder
():
FolderDTO
{
...
...
@@ -14,29 +14,85 @@ function getTestFolder(): FolderDTO {
}
describe
(
'folder reducer'
,
()
=>
{
it
(
'should load folder and set hasChanged to false'
,
()
=>
{
const
folder
=
getTestFolder
();
describe
(
'loadFolder'
,
()
=>
{
it
(
'should load folder and set hasChanged to false'
,
()
=>
{
const
folder
=
getTestFolder
();
const
action
:
Action
=
{
type
:
ActionTypes
.
LoadFolder
,
payload
:
folder
,
};
const
action
:
Action
=
{
type
:
ActionTypes
.
LoadFolder
,
payload
:
folder
,
};
const
state
=
folderReducer
(
inititalState
,
action
);
const
state
=
folderReducer
(
inititalState
,
action
);
expect
(
state
.
hasChanged
).
toEqual
(
false
);
expect
(
state
.
title
).
toEqual
(
'test folder'
);
expect
(
state
.
hasChanged
).
toEqual
(
false
);
expect
(
state
.
title
).
toEqual
(
'test folder'
);
});
});
it
(
'should set title'
,
()
=>
{
const
action
:
Action
=
{
type
:
ActionTypes
.
SetFolderTitle
,
payload
:
'new title'
,
};
describe
(
'detFolderTitle'
,
()
=>
{
it
(
'should set title'
,
()
=>
{
const
action
:
Action
=
{
type
:
ActionTypes
.
SetFolderTitle
,
payload
:
'new title'
,
};
const
state
=
folderReducer
(
inititalState
,
action
);
const
state
=
folderReducer
(
inititalState
,
action
);
expect
(
state
.
hasChanged
).
toEqual
(
true
);
expect
(
state
.
title
).
toEqual
(
'new title'
);
expect
(
state
.
hasChanged
).
toEqual
(
true
);
expect
(
state
.
title
).
toEqual
(
'new title'
);
});
});
describe
(
'loadFolderPermissions'
,
()
=>
{
let
state
:
FolderState
;
beforeEach
(()
=>
{
const
action
:
Action
=
{
type
:
ActionTypes
.
LoadFolderPermissions
,
payload
:
[
{
id
:
2
,
dashboardId
:
1
,
role
:
OrgRole
.
Viewer
,
permission
:
PermissionLevel
.
View
},
{
id
:
3
,
dashboardId
:
1
,
role
:
OrgRole
.
Editor
,
permission
:
PermissionLevel
.
Edit
},
{
id
:
4
,
dashboardId
:
10
,
permission
:
PermissionLevel
.
View
,
teamId
:
1
,
team
:
'MyTestTeam'
,
inherited
:
true
,
},
{
id
:
5
,
dashboardId
:
1
,
permission
:
PermissionLevel
.
View
,
userId
:
1
,
userLogin
:
'MyTestUser'
,
},
{
id
:
6
,
dashboardId
:
1
,
permission
:
PermissionLevel
.
Edit
,
teamId
:
2
,
team
:
'MyTestTeam2'
,
},
],
};
state
=
folderReducer
(
inititalState
,
action
);
});
it
(
'should add permissions to state'
,
async
()
=>
{
expect
(
state
.
permissions
.
length
).
toBe
(
5
);
expect
(
state
.
permissions
.
length
).
toBe
(
5
);
});
it
(
'should be sorted by sort rank and alphabetically'
,
async
()
=>
{
expect
(
state
.
permissions
[
0
].
name
).
toBe
(
'MyTestTeam'
);
expect
(
state
.
permissions
[
0
].
dashboardId
).
toBe
(
10
);
expect
(
state
.
permissions
[
1
].
name
).
toBe
(
'Editor'
);
expect
(
state
.
permissions
[
2
].
name
).
toBe
(
'Viewer'
);
expect
(
state
.
permissions
[
3
].
name
).
toBe
(
'MyTestTeam2'
);
expect
(
state
.
permissions
[
4
].
name
).
toBe
(
'MyTestUser'
);
});
});
});
public/app/types/acl.ts
View file @
7bb01092
export
enum
OrgRole
{
Viewer
=
'Viewer'
,
Editor
=
'Editor'
,
Admin
=
'Admin'
,
}
export
interface
DashboardAclDTO
{
id
?:
number
;
dashboardId
?:
number
;
...
...
@@ -7,8 +13,7 @@ export interface DashboardAclDTO {
teamId
?:
number
;
team
?:
string
;
permission
?:
PermissionLevel
;
permissionName
?:
string
;
role
?:
string
;
role
?:
OrgRole
;
icon
?:
string
;
inherited
?:
boolean
;
}
...
...
@@ -16,7 +21,7 @@ export interface DashboardAclDTO {
export
interface
DashboardAclUpdateDTO
{
userId
:
number
;
teamId
:
number
;
role
:
string
;
role
:
OrgRole
;
permission
:
PermissionLevel
;
}
...
...
@@ -29,8 +34,7 @@ export interface DashboardAcl {
teamId
?:
number
;
team
?:
string
;
permission
?:
PermissionLevel
;
permissionName
?:
string
;
role
?:
string
;
role
?:
OrgRole
;
icon
?:
string
;
name
?:
string
;
inherited
?:
boolean
;
...
...
@@ -46,7 +50,7 @@ export interface DashboardPermissionInfo {
export
interface
NewDashboardAclItem
{
teamId
:
number
;
userId
:
number
;
role
:
string
;
role
:
OrgRole
;
permission
:
PermissionLevel
;
type
:
AclTarget
;
}
...
...
@@ -58,10 +62,10 @@ export enum PermissionLevel {
}
export
enum
AclTarget
{
Team
=
'
t
eam'
,
User
=
'
u
ser'
,
Viewer
=
'
v
iewer'
,
Editor
=
'
e
ditor'
,
Team
=
'
T
eam'
,
User
=
'
U
ser'
,
Viewer
=
'
V
iewer'
,
Editor
=
'
E
ditor'
,
}
export
interface
AclTargetInfo
{
...
...
public/app/types/index.ts
View file @
7bb01092
...
...
@@ -4,6 +4,7 @@ import { LocationState, LocationUpdate, UrlQueryMap, UrlQueryValue } from './loc
import
{
NavModel
,
NavModelItem
,
NavIndex
}
from
'./navModel'
;
import
{
FolderDTO
,
FolderState
,
FolderInfo
}
from
'./folder'
;
import
{
DashboardState
}
from
'./dashboard'
;
import
{
DashboardAcl
,
OrgRole
,
PermissionLevel
}
from
'./acl'
;
export
{
Team
,
...
...
@@ -24,6 +25,10 @@ export {
FolderDTO
,
FolderState
,
FolderInfo
,
DashboardState
,
DashboardAcl
,
OrgRole
,
PermissionLevel
,
};
export
interface
StoreState
{
...
...
scripts/webpack/webpack.common.js
View file @
7bb01092
...
...
@@ -24,6 +24,9 @@ module.exports = {
path
.
resolve
(
'node_modules'
)
],
},
stats
:
{
warningsFilter
:
/export .* was not found in/
},
node
:
{
fs
:
'empty'
,
},
...
...
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