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
05bfc365
Commit
05bfc365
authored
Sep 07, 2018
by
Peter Holmberg
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Teampages page
parent
f68ac202
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
410 additions
and
84 deletions
+410
-84
public/app/core/actions/index.ts
+2
-1
public/app/core/actions/navModel.ts
+11
-3
public/app/core/reducers/navModel.ts
+16
-2
public/app/core/selectors/location.ts
+3
-0
public/app/core/selectors/navModel.ts
+1
-1
public/app/features/teams/TeamGroupSync.tsx
+5
-7
public/app/features/teams/TeamMembers.tsx
+12
-15
public/app/features/teams/TeamPages.test.tsx
+63
-0
public/app/features/teams/TeamPages.tsx
+68
-39
public/app/features/teams/TeamSettings.tsx
+4
-6
public/app/features/teams/__mocks__/navModelMock.ts
+59
-0
public/app/features/teams/__snapshots__/TeamPages.test.tsx.snap
+87
-0
public/app/features/teams/state/actions.ts
+54
-3
public/app/features/teams/state/reducers.test.ts
+3
-3
public/app/features/teams/state/reducers.ts
+14
-3
public/app/features/teams/state/selectors.ts
+2
-0
public/app/types/index.ts
+6
-1
No files found.
public/app/core/actions/index.ts
View file @
05bfc365
import
{
updateLocation
}
from
'./location'
;
import
{
updateNavIndex
}
from
'./navModel'
;
export
{
updateLocation
};
export
{
updateLocation
,
updateNavIndex
};
public/app/core/actions/navModel.ts
View file @
05bfc365
import
{
NavModelItem
}
from
'../../types'
;
export
enum
ActionTypes
{
UpdateNavIndex
=
'UPDATE_NAV_INDEX'
,
}
export
type
Action
=
UpdateNavIndexAction
;
// this action is not used yet
...
...
@@ -5,9 +11,11 @@ export type Action = UpdateNavIndexAction;
// like datasource edit, teams edit page
export
interface
UpdateNavIndexAction
{
type
:
'UPDATE_NAV_INDEX'
;
type
:
ActionTypes
.
UpdateNavIndex
;
payload
:
NavModelItem
;
}
export
const
updateNavIndex
=
():
UpdateNavIndexAction
=>
({
type
:
'UPDATE_NAV_INDEX'
,
export
const
updateNavIndex
=
(
item
:
NavModelItem
):
UpdateNavIndexAction
=>
({
type
:
ActionTypes
.
UpdateNavIndex
,
payload
:
item
,
});
public/app/core/reducers/navModel.ts
View file @
05bfc365
import
{
Action
}
from
'app/core/actions/navModel'
;
import
{
Nav
ModelItem
,
NavIndex
}
from
'app/types'
;
import
{
Action
,
ActionTypes
}
from
'app/core/actions/navModel'
;
import
{
Nav
Index
,
NavModelItem
}
from
'app/types'
;
import
config
from
'app/core/config'
;
export
function
buildInitialState
():
NavIndex
{
...
...
@@ -25,5 +25,19 @@ function buildNavIndex(navIndex: NavIndex, children: NavModelItem[], parentItem?
export
const
initialState
:
NavIndex
=
buildInitialState
();
export
const
navIndexReducer
=
(
state
=
initialState
,
action
:
Action
):
NavIndex
=>
{
switch
(
action
.
type
)
{
case
ActionTypes
.
UpdateNavIndex
:
const
newPages
=
{};
const
payload
=
action
.
payload
;
for
(
const
node
of
payload
.
children
)
{
newPages
[
node
.
id
]
=
{
...
node
,
parentItem
:
payload
,
};
}
return
{
...
state
,
...
newPages
};
}
return
state
;
};
public/app/core/selectors/location.ts
0 → 100644
View file @
05bfc365
export
const
getRouteParamsId
=
state
=>
state
.
routeParams
.
id
;
export
const
getRouteParamsPage
=
state
=>
state
.
routeParams
.
page
;
public/app/core/selectors/navModel.ts
View file @
05bfc365
import
{
NavModel
,
NavModelItem
,
NavIndex
}
from
'app/types'
;
function
getNotFoundModel
():
NavModel
{
var
node
:
NavModelItem
=
{
const
node
:
NavModelItem
=
{
id
:
'not-found'
,
text
:
'Page not found'
,
icon
:
'fa fa-fw fa-warning'
,
...
...
public/app/features/teams/TeamGroupSync.tsx
View file @
05bfc365
import
React
from
'react'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
observer
}
from
'mobx-react'
;
import
{
Team
,
TeamGroup
}
from
'app/stores/TeamsStore/TeamsStore'
;
import
SlideDown
from
'app/core/components/Animations/SlideDown'
;
import
Tooltip
from
'app/core/components/Tooltip/Tooltip'
;
import
{
Team
,
TeamGroup
}
from
'../../types'
;
interface
Props
{
team
:
Team
;
...
...
@@ -16,7 +15,6 @@ interface State {
const
headerTooltip
=
`Sync LDAP or OAuth groups with your Grafana teams.`
;
@
observer
export
class
TeamGroupSync
extends
React
.
Component
<
Props
,
State
>
{
constructor
(
props
)
{
super
(
props
);
...
...
@@ -24,7 +22,7 @@ export class TeamGroupSync extends React.Component<Props, State> {
}
componentDidMount
()
{
this
.
props
.
team
.
loadGroups
();
//
this.props.team.loadGroups();
}
renderGroup
(
group
:
TeamGroup
)
{
...
...
@@ -49,12 +47,12 @@ export class TeamGroupSync extends React.Component<Props, State> {
};
onAddGroup
=
()
=>
{
this
.
props
.
team
.
addGroup
(
this
.
state
.
newGroupId
);
//
this.props.team.addGroup(this.state.newGroupId);
this
.
setState
({
isAdding
:
false
,
newGroupId
:
''
});
};
onRemoveGroup
=
(
group
:
TeamGroup
)
=>
{
this
.
props
.
team
.
removeGroup
(
group
.
groupId
);
//
this.props.team.removeGroup(group.groupId);
};
isNewGroupValid
()
{
...
...
@@ -63,7 +61,7 @@ export class TeamGroupSync extends React.Component<Props, State> {
render
()
{
const
{
isAdding
,
newGroupId
}
=
this
.
state
;
const
groups
=
this
.
props
.
team
.
groups
.
values
()
;
const
groups
=
this
.
props
.
team
.
groups
;
return
(
<
div
>
...
...
public/app/features/teams/TeamMembers.tsx
View file @
05bfc365
import
React
from
'react'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
observer
}
from
'mobx-react'
;
import
{
Team
,
TeamMember
}
from
'app/stores/TeamsStore/TeamsStore'
;
import
SlideDown
from
'app/core/components/Animations/SlideDown'
;
import
{
UserPicker
,
User
}
from
'app/core/components/Picker/UserPicker'
;
import
DeleteButton
from
'app/core/components/DeleteButton/DeleteButton'
;
import
{
Team
,
TeamMember
}
from
'../../types'
;
interface
Props
{
team
:
Team
;
...
...
@@ -15,27 +14,26 @@ interface State {
newTeamMember
?:
User
;
}
@
observer
export
class
TeamMembers
extends
React
.
Component
<
Props
,
State
>
{
export
class
TeamMembers
extends
PureComponent
<
Props
,
State
>
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
isAdding
:
false
,
newTeamMember
:
null
};
}
componentDidMount
()
{
this
.
props
.
team
.
loadMembers
();
//
this.props.team.loadMembers();
}
onSearchQueryChange
=
evt
=>
{
this
.
props
.
team
.
setSearchQuery
(
evt
.
target
.
value
);
//
this.props.team.setSearchQuery(evt.target.value);
};
removeMember
(
member
:
TeamMember
)
{
this
.
props
.
team
.
removeMember
(
member
);
//
this.props.team.removeMember(member);
}
removeMemberConfirmed
(
member
:
TeamMember
)
{
this
.
props
.
team
.
removeMember
(
member
);
//
this.props.team.removeMember(member);
}
renderMember
(
member
:
TeamMember
)
{
...
...
@@ -62,16 +60,15 @@ export class TeamMembers extends React.Component<Props, State> {
};
onAddUserToTeam
=
async
()
=>
{
await
this
.
props
.
team
.
addMember
(
this
.
state
.
newTeamMember
.
id
);
await
this
.
props
.
team
.
loadMembers
();
this
.
setState
({
newTeamMember
:
null
});
//
await this.props.team.addMember(this.state.newTeamMember.id);
//
await this.props.team.loadMembers();
//
this.setState({ newTeamMember: null });
};
render
()
{
const
{
newTeamMember
,
isAdding
}
=
this
.
state
;
const
members
=
this
.
props
.
team
.
filteredMembers
;
const
newTeamMemberValue
=
newTeamMember
&&
newTeamMember
.
id
.
toString
();
const
{
team
}
=
this
.
props
;
const
newTeamMemberValue
=
newTeamMember
&&
newTeamMember
.
id
.
toString
();
return
(
<
div
>
...
...
@@ -124,7 +121,7 @@ export class TeamMembers extends React.Component<Props, State> {
<
th
style=
{
{
width
:
'1%'
}
}
/>
</
tr
>
</
thead
>
<
tbody
>
{
members
.
map
(
member
=>
this
.
renderMember
(
member
))
}
</
tbody
>
<
tbody
>
{
team
.
members
&&
team
.
members
.
map
(
member
=>
this
.
renderMember
(
member
))
}
</
tbody
>
</
table
>
</
div
>
</
div
>
...
...
public/app/features/teams/TeamPages.test.tsx
0 → 100644
View file @
05bfc365
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
{
TeamPages
,
Props
}
from
'./TeamPages'
;
import
{
NavModel
,
Team
}
from
'../../types'
;
import
{
getMockTeam
}
from
'./__mocks__/teamMocks'
;
jest
.
mock
(
'app/core/config'
,
()
=>
({
buildInfo
:
{
isEnterprise
:
true
},
}));
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
navModel
:
{}
as
NavModel
,
teamId
:
1
,
loadTeam
:
jest
.
fn
(),
pageName
:
'members'
,
team
:
{}
as
Team
,
};
Object
.
assign
(
props
,
propOverrides
);
const
wrapper
=
shallow
(<
TeamPages
{
...
props
}
/>);
const
instance
=
wrapper
.
instance
();
return
{
wrapper
,
instance
,
};
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
{
wrapper
}
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render member page if team not empty'
,
()
=>
{
const
{
wrapper
}
=
setup
({
team
:
getMockTeam
(),
});
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render settings page'
,
()
=>
{
const
{
wrapper
}
=
setup
({
team
:
getMockTeam
(),
pageName
:
'settings'
,
});
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render group sync page'
,
()
=>
{
const
{
wrapper
}
=
setup
({
team
:
getMockTeam
(),
pageName
:
'groupsync'
,
});
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/teams/TeamPages.tsx
View file @
05bfc365
import
React
from
'react'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
_
from
'lodash'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
inject
,
observer
}
from
'mobx-react'
;
import
config
from
'app/core/config'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
{
NavStore
}
from
'app/stores/NavStore/NavStore'
;
import
{
TeamsStore
,
Team
}
from
'app/stores/TeamsStore/TeamsStore'
;
import
{
ViewStore
}
from
'app/stores/ViewStore/ViewStore'
;
import
TeamMembers
from
'./TeamMembers'
;
import
TeamSettings
from
'./TeamSettings'
;
import
TeamGroupSync
from
'./TeamGroupSync'
;
import
{
NavModel
,
Team
}
from
'../../types'
;
import
{
loadTeam
}
from
'./state/actions'
;
import
{
getTeam
}
from
'./state/selectors'
;
import
{
getNavModel
}
from
'../../core/selectors/navModel'
;
import
{
getRouteParamsId
,
getRouteParamsPage
}
from
'../../core/selectors/location'
;
interface
Props
{
nav
:
typeof
NavStore
.
Type
;
teams
:
typeof
TeamsStore
.
Type
;
view
:
typeof
ViewStore
.
Type
;
export
interface
Props
{
team
:
Team
;
loadTeam
:
typeof
loadTeam
;
teamId
:
number
;
pageName
:
string
;
navModel
:
NavModel
;
}
@
inject
(
'nav'
,
'teams'
,
'view'
)
@
observer
export
class
TeamPages
extends
React
.
Component
<
Props
,
any
>
{
interface
State
{
isSyncEnabled
:
boolean
;
currentPage
:
string
;
}
enum
PageTypes
{
Members
=
'members'
,
Settings
=
'settings'
,
GroupSync
=
'groupsync'
,
}
export
class
TeamPages
extends
PureComponent
<
Props
,
State
>
{
constructor
(
props
)
{
super
(
props
);
this
.
isSyncEnabled
=
config
.
buildInfo
.
isEnterprise
;
this
.
currentPage
=
this
.
getCurrentPage
();
this
.
state
=
{
isSyncEnabled
:
config
.
buildInfo
.
isEnterprise
,
};
}
componentDidMount
()
{
this
.
loadTeam
();
}
async
loadTeam
()
{
const
{
teams
,
nav
,
view
}
=
this
.
props
;
await
teams
.
loadById
(
view
.
routeParams
.
get
(
'id'
));
const
{
loadTeam
,
teamId
}
=
this
.
props
;
nav
.
initTeamPage
(
this
.
getCurrentTeam
(),
this
.
currentPage
,
this
.
isSyncEnabled
);
}
getCurrentTeam
():
Team
{
const
{
teams
,
view
}
=
this
.
props
;
return
teams
.
map
.
get
(
view
.
routeParams
.
get
(
'id'
));
await
loadTeam
(
teamId
);
}
getCurrentPage
()
{
const
pages
=
[
'members'
,
'settings'
,
'groupsync'
];
const
currentPage
=
this
.
props
.
view
.
routeParams
.
get
(
'page'
)
;
const
currentPage
=
this
.
props
.
pageName
;
return
_
.
includes
(
pages
,
currentPage
)
?
currentPage
:
pages
[
0
];
}
render
()
{
const
{
nav
}
=
this
.
props
;
const
currentTeam
=
this
.
getCurrentTeam
();
renderPage
()
{
const
{
team
}
=
this
.
props
;
const
{
isSyncEnabled
}
=
this
.
state
;
const
currentPage
=
this
.
getCurrentPage
();
switch
(
currentPage
)
{
case
PageTypes
.
Members
:
return
<
TeamMembers
team=
{
team
}
/>;
if
(
!
nav
.
main
)
{
return
null
;
case
PageTypes
.
Settings
:
return
<
TeamSettings
team=
{
team
}
/>;
case
PageTypes
.
GroupSync
:
return
isSyncEnabled
&&
<
TeamGroupSync
team=
{
team
}
/>;
}
return
null
;
}
render
()
{
const
{
team
,
navModel
}
=
this
.
props
;
return
(
<
div
>
<
PageHeader
model=
{
nav
as
any
}
/>
{
currentTeam
&&
(
<
div
className=
"page-container page-body"
>
{
this
.
currentPage
===
'members'
&&
<
TeamMembers
team=
{
currentTeam
}
/>
}
{
this
.
currentPage
===
'settings'
&&
<
TeamSettings
team=
{
currentTeam
}
/>
}
{
this
.
currentPage
===
'groupsync'
&&
this
.
isSyncEnabled
&&
<
TeamGroupSync
team=
{
currentTeam
}
/>
}
</
div
>
)
}
<
PageHeader
model=
{
navModel
}
/>
{
team
&&
Object
.
keys
(
team
).
length
!==
0
&&
<
div
className=
"page-container page-body"
>
{
this
.
renderPage
()
}
</
div
>
}
</
div
>
);
}
}
export
default
hot
(
module
)(
TeamPages
);
function
mapStateToProps
(
state
)
{
const
teamId
=
getRouteParamsId
(
state
.
location
);
const
pageName
=
getRouteParamsPage
(
state
.
location
)
||
'members'
;
return
{
navModel
:
getNavModel
(
state
.
navIndex
,
`team-
${
pageName
}
-
${
teamId
}
`
),
teamId
:
teamId
,
pageName
:
pageName
,
team
:
getTeam
(
state
.
team
),
};
}
const
mapDispatchToProps
=
{
loadTeam
,
};
export
default
hot
(
module
)(
connect
(
mapStateToProps
,
mapDispatchToProps
)(
TeamPages
));
public/app/features/teams/TeamSettings.tsx
View file @
05bfc365
import
React
from
'react'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
observer
}
from
'mobx-react'
;
import
{
Team
}
from
'app/stores/TeamsStore/TeamsStore'
;
import
{
Label
}
from
'app/core/components/Forms/Forms'
;
import
{
Team
}
from
'../../types'
;
interface
Props
{
team
:
Team
;
}
@
observer
export
class
TeamSettings
extends
React
.
Component
<
Props
,
any
>
{
constructor
(
props
)
{
super
(
props
);
}
onChangeName
=
evt
=>
{
this
.
props
.
team
.
setName
(
evt
.
target
.
value
);
//
this.props.team.setName(evt.target.value);
};
onChangeEmail
=
evt
=>
{
this
.
props
.
team
.
setEmail
(
evt
.
target
.
value
);
//
this.props.team.setEmail(evt.target.value);
};
onUpdate
=
evt
=>
{
evt
.
preventDefault
();
this
.
props
.
team
.
update
();
//
this.props.team.update();
};
render
()
{
...
...
public/app/features/teams/__mocks__/navModelMock.ts
0 → 100644
View file @
05bfc365
export
const
getMockNavModel
=
(
pageName
:
string
)
=>
{
return
{
node
:
{
active
:
false
,
icon
:
'gicon gicon-team'
,
id
:
`team-
${
pageName
}
-2`
,
text
:
`
${
pageName
}
`
,
url
:
'org/teams/edit/2/members'
,
parentItem
:
{
img
:
'/avatar/b5695b61c91d13e7fa2fe71cfb95de9b'
,
id
:
'team-2'
,
subTitle
:
'Manage members & settings'
,
url
:
''
,
text
:
'test1'
,
breadcrumbs
:
[{
title
:
'Teams'
,
url
:
'org/teams'
}],
children
:
[
{
active
:
false
,
icon
:
'gicon gicon-team'
,
id
:
'team-members-2'
,
text
:
'Members'
,
url
:
'org/teams/edit/2/members'
,
},
{
active
:
false
,
icon
:
'fa fa-fw fa-sliders'
,
id
:
'team-settings-2'
,
text
:
'Settings'
,
url
:
'org/teams/edit/2/settings'
,
},
],
},
},
main
:
{
img
:
'/avatar/b5695b61c91d13e7fa2fe71cfb95de9b'
,
id
:
'team-2'
,
subTitle
:
'Manage members & settings'
,
url
:
''
,
text
:
'test1'
,
breadcrumbs
:
[{
title
:
'Teams'
,
url
:
'org/teams'
}],
children
:
[
{
active
:
true
,
icon
:
'gicon gicon-team'
,
id
:
'team-members-2'
,
text
:
'Members'
,
url
:
'org/teams/edit/2/members'
,
},
{
active
:
false
,
icon
:
'fa fa-fw fa-sliders'
,
id
:
'team-settings-2'
,
text
:
'Settings'
,
url
:
'org/teams/edit/2/settings'
,
},
],
},
};
};
public/app/features/teams/__snapshots__/TeamPages.test.tsx.snap
0 → 100644
View file @
05bfc365
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<div>
<PageHeader
model={Object {}}
/>
</div>
`;
exports[`Render should render group sync page 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<TeamGroupSync
team={
Object {
"avatarUrl": "some/url/",
"email": "test@test.com",
"groups": Array [],
"id": 1,
"memberCount": 1,
"members": Array [],
"name": "test",
"search": "",
}
}
/>
</div>
</div>
`;
exports[`Render should render member page if team not empty 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<TeamMembers
team={
Object {
"avatarUrl": "some/url/",
"email": "test@test.com",
"groups": Array [],
"id": 1,
"memberCount": 1,
"members": Array [],
"name": "test",
"search": "",
}
}
/>
</div>
</div>
`;
exports[`Render should render settings page 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<TeamSettings
team={
Object {
"avatarUrl": "some/url/",
"email": "test@test.com",
"groups": Array [],
"id": 1,
"memberCount": 1,
"members": Array [],
"name": "test",
"search": "",
}
}
/>
</div>
</div>
`;
public/app/features/teams/state/actions.ts
View file @
05bfc365
import
{
ThunkAction
}
from
'redux-thunk'
;
import
{
getBackendSrv
}
from
'app/core/services/backend_srv'
;
import
{
StoreState
,
Team
}
from
'../../../types'
;
import
{
NavModelItem
,
StoreState
,
Team
}
from
'../../../types'
;
import
{
updateNavIndex
}
from
'../../../core/actions'
;
import
{
UpdateNavIndexAction
}
from
'../../../core/actions/navModel'
;
export
enum
ActionTypes
{
LoadTeams
=
'LOAD_TEAMS'
,
LoadTeam
=
'LOAD_TEAM'
,
SetSearchQuery
=
'SET_SEARCH_QUERY'
,
}
...
...
@@ -12,20 +15,30 @@ export interface LoadTeamsAction {
payload
:
Team
[];
}
export
interface
LoadTeamAction
{
type
:
ActionTypes
.
LoadTeam
;
payload
:
Team
;
}
export
interface
SetSearchQueryAction
{
type
:
ActionTypes
.
SetSearchQuery
;
payload
:
string
;
}
export
type
Action
=
LoadTeamsAction
|
SetSearchQueryAction
;
export
type
Action
=
LoadTeamsAction
|
SetSearchQueryAction
|
LoadTeamAction
;
type
ThunkResult
<
R
>
=
ThunkAction
<
R
,
StoreState
,
undefined
,
Action
>
;
type
ThunkResult
<
R
>
=
ThunkAction
<
R
,
StoreState
,
undefined
,
Action
|
UpdateNavIndexAction
>
;
const
teamsLoaded
=
(
teams
:
Team
[]):
LoadTeamsAction
=>
({
type
:
ActionTypes
.
LoadTeams
,
payload
:
teams
,
});
const
teamLoaded
=
(
team
:
Team
):
LoadTeamAction
=>
({
type
:
ActionTypes
.
LoadTeam
,
payload
:
team
,
});
export
const
setSearchQuery
=
(
searchQuery
:
string
):
SetSearchQueryAction
=>
({
type
:
ActionTypes
.
SetSearchQuery
,
payload
:
searchQuery
,
...
...
@@ -38,6 +51,44 @@ export function loadTeams(): ThunkResult<void> {
};
}
function
buildNavModel
(
team
:
Team
):
NavModelItem
{
return
{
img
:
team
.
avatarUrl
,
id
:
'team-'
+
team
.
id
,
subTitle
:
'Manage members & settings'
,
url
:
''
,
text
:
team
.
name
,
breadcrumbs
:
[{
title
:
'Teams'
,
url
:
'org/teams'
}],
children
:
[
{
active
:
false
,
icon
:
'gicon gicon-team'
,
id
:
`team-members-
${
team
.
id
}
`
,
text
:
'Members'
,
url
:
`org/teams/edit/
${
team
.
id
}
/members`
,
},
{
active
:
false
,
icon
:
'fa fa-fw fa-sliders'
,
id
:
`team-settings-
${
team
.
id
}
`
,
text
:
'Settings'
,
url
:
`org/teams/edit/
${
team
.
id
}
/settings`
,
},
],
};
}
export
function
loadTeam
(
id
:
number
):
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
await
getBackendSrv
()
.
get
(
`/api/teams/
${
id
}
`
)
.
then
(
response
=>
{
dispatch
(
teamLoaded
(
response
));
dispatch
(
updateNavIndex
(
buildNavModel
(
response
)));
});
};
}
export
function
deleteTeam
(
id
:
number
):
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
await
getBackendSrv
()
...
...
public/app/features/teams/state/reducers.test.ts
View file @
05bfc365
import
{
Action
,
ActionTypes
}
from
'./actions'
;
import
{
initialState
,
teamsReducer
}
from
'./reducers'
;
import
{
initial
Teams
State
,
teamsReducer
}
from
'./reducers'
;
describe
(
'teams reducer'
,
()
=>
{
it
(
'should set teams'
,
()
=>
{
...
...
@@ -21,7 +21,7 @@ describe('teams reducer', () => {
payload
,
};
const
result
=
teamsReducer
(
initialState
,
action
);
const
result
=
teamsReducer
(
initial
Teams
State
,
action
);
expect
(
result
.
teams
).
toEqual
(
payload
);
});
...
...
@@ -34,7 +34,7 @@ describe('teams reducer', () => {
payload
,
};
const
result
=
teamsReducer
(
initialState
,
action
);
const
result
=
teamsReducer
(
initial
Teams
State
,
action
);
expect
(
result
.
searchQuery
).
toEqual
(
'test'
);
});
...
...
public/app/features/teams/state/reducers.ts
View file @
05bfc365
import
{
Team
s
State
}
from
'../../../types'
;
import
{
Team
,
TeamsState
,
Team
State
}
from
'../../../types'
;
import
{
Action
,
ActionTypes
}
from
'./actions'
;
export
const
initialState
:
TeamsState
=
{
teams
:
[],
searchQuery
:
''
};
export
const
initialTeamsState
:
TeamsState
=
{
teams
:
[],
searchQuery
:
''
};
export
const
initialTeamState
:
TeamState
=
{
team
:
{}
as
Team
,
searchQuery
:
''
};
export
const
teamsReducer
=
(
state
=
initialState
,
action
:
Action
):
TeamsState
=>
{
export
const
teamsReducer
=
(
state
=
initial
Teams
State
,
action
:
Action
):
TeamsState
=>
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadTeams
:
return
{
...
state
,
teams
:
action
.
payload
};
...
...
@@ -14,6 +15,16 @@ export const teamsReducer = (state = initialState, action: Action): TeamsState =
return
state
;
};
export
const
teamReducer
=
(
state
=
initialTeamState
,
action
:
Action
):
TeamState
=>
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadTeam
:
return
{
...
state
,
team
:
action
.
payload
};
}
return
state
;
};
export
default
{
teams
:
teamsReducer
,
team
:
teamReducer
,
};
public/app/features/teams/state/selectors.ts
View file @
05bfc365
export
const
getSearchQuery
=
state
=>
state
.
searchQuery
;
export
const
getTeam
=
state
=>
state
.
team
;
export
const
getTeams
=
state
=>
{
const
regex
=
RegExp
(
state
.
searchQuery
,
'i'
);
...
...
public/app/types/index.ts
View file @
05bfc365
...
...
@@ -96,7 +96,7 @@ export interface NavModelItem {
hideFromTabs
?:
boolean
;
divider
?:
boolean
;
children
?:
NavModelItem
[];
breadcrumbs
?:
NavModelItem
[];
breadcrumbs
?:
{
title
:
string
;
url
:
string
}
[];
target
?:
string
;
parentItem
?:
NavModelItem
;
}
...
...
@@ -122,6 +122,11 @@ export interface TeamsState {
searchQuery
:
string
;
}
export
interface
TeamState
{
team
:
Team
;
searchQuery
:
string
;
}
export
interface
StoreState
{
navIndex
:
NavIndex
;
location
:
LocationState
;
...
...
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