Teampages page
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { updateLocation } from './location';
|
||||
import { updateNavIndex } from './navModel';
|
||||
|
||||
export { updateLocation };
|
||||
export { updateLocation, updateNavIndex };
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
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,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Action } from 'app/core/actions/navModel';
|
||||
import { NavModelItem, NavIndex } from 'app/types';
|
||||
import { Action, ActionTypes } from 'app/core/actions/navModel';
|
||||
import { NavIndex, 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;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export const getRouteParamsId = state => state.routeParams.id;
|
||||
|
||||
export const getRouteParamsPage = state => state.routeParams.page;
|
||||
@@ -1,7 +1,7 @@
|
||||
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',
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
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>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
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>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -1,77 +1,106 @@
|
||||
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;
|
||||
const { loadTeam, teamId } = this.props;
|
||||
|
||||
await teams.loadById(view.routeParams.get('id'));
|
||||
|
||||
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();
|
||||
|
||||
if (!nav.main) {
|
||||
return null;
|
||||
switch (currentPage) {
|
||||
case PageTypes.Members:
|
||||
return <TeamMembers team={team} />;
|
||||
|
||||
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));
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
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() {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
// 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>
|
||||
`;
|
||||
@@ -1,9 +1,12 @@
|
||||
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()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import { initialState, teamsReducer } from './reducers';
|
||||
import { initialTeamsState, 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(initialTeamsState, action);
|
||||
|
||||
expect(result.teams).toEqual(payload);
|
||||
});
|
||||
@@ -34,7 +34,7 @@ describe('teams reducer', () => {
|
||||
payload,
|
||||
};
|
||||
|
||||
const result = teamsReducer(initialState, action);
|
||||
const result = teamsReducer(initialTeamsState, action);
|
||||
|
||||
expect(result.searchQuery).toEqual('test');
|
||||
});
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { TeamsState } from '../../../types';
|
||||
import { Team, TeamsState, TeamState } 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 = initialTeamsState, 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,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export const getSearchQuery = state => state.searchQuery;
|
||||
|
||||
export const getTeam = state => state.team;
|
||||
|
||||
export const getTeams = state => {
|
||||
const regex = RegExp(state.searchQuery, 'i');
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user