grafana/public/app/features/teams/TeamPages.tsx
Torkel Ödegaard 1e85a6f4fd
TopNav: New page layouts (#51510)
* First stab at new page layouts behind feature toggle

* Simplifying PageHeader

* Progress on a new model that can more easily support new and old page layouts

* Progress

* rename folder

* Progress

* Minor change

* fixes

* Fixing tests

* Make breadcrumbs work

* Add tests for old Page component

* Adding tests for new Page component and behavior

* fixing page header test

* Fixed test

* AppChrome outside route

* Renaming folder

* Minor fix

* Updated

* Fixing StoragePage

* Fix for banners

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2022-07-06 17:00:56 +02:00

200 lines
6.1 KiB
TypeScript

import { includes } from 'lodash';
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { NavModelItem } from '@grafana/data';
import { featureEnabled } from '@grafana/runtime';
import { Themeable2, withTheme2 } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { UpgradeBox } from 'app/core/components/Upgrade/UpgradeBox';
import config from 'app/core/config';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { getNavModel } from 'app/core/selectors/navModel';
import { contextSrv } from 'app/core/services/context_srv';
import { AccessControlAction, StoreState } from 'app/types';
import TeamGroupSync, { TeamSyncUpgradeContent } from './TeamGroupSync';
import TeamMembers from './TeamMembers';
import TeamPermissions from './TeamPermissions';
import TeamSettings from './TeamSettings';
import { loadTeam, loadTeamMembers } from './state/actions';
import { getTeamLoadingNav } from './state/navModel';
import { getTeam, getTeamMembers, isSignedInUserTeamAdmin } from './state/selectors';
interface TeamPageRouteParams {
id: string;
page: string | null;
}
export interface OwnProps extends GrafanaRouteComponentProps<TeamPageRouteParams>, Themeable2 {}
interface State {
isSyncEnabled: boolean;
isLoading: boolean;
}
enum PageTypes {
Members = 'members',
Settings = 'settings',
GroupSync = 'groupsync',
}
function mapStateToProps(state: StoreState, props: OwnProps) {
const teamId = parseInt(props.match.params.id, 10);
const team = getTeam(state.team, teamId);
let defaultPage = 'members';
if (contextSrv.accessControlEnabled()) {
// With RBAC the settings page will always be available
if (!team || !contextSrv.hasPermissionInMetadata(AccessControlAction.ActionTeamsPermissionsRead, team)) {
defaultPage = 'settings';
}
}
const pageName = props.match.params.page ?? defaultPage;
const teamLoadingNav = getTeamLoadingNav(pageName as string);
const pageNav = getNavModel(state.navIndex, `team-${pageName}-${teamId}`, teamLoadingNav).main;
const members = getTeamMembers(state.team);
return {
pageNav,
teamId: teamId,
pageName: pageName,
team,
members,
editorsCanAdmin: config.editorsCanAdmin, // this makes the feature toggle mockable/controllable from tests,
signedInUser: contextSrv.user, // this makes the feature toggle mockable/controllable from tests,
};
}
const mapDispatchToProps = {
loadTeam,
loadTeamMembers,
};
const connector = connect(mapStateToProps, mapDispatchToProps);
export type Props = OwnProps & ConnectedProps<typeof connector>;
export class TeamPages extends PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
isLoading: false,
isSyncEnabled: featureEnabled('teamsync'),
};
}
async componentDidMount() {
await this.fetchTeam();
}
async fetchTeam() {
const { loadTeam, teamId } = this.props;
this.setState({ isLoading: true });
const team = await loadTeam(teamId);
// With accesscontrol, the TeamPermissions will fetch team members
if (!contextSrv.accessControlEnabled()) {
await this.props.loadTeamMembers();
}
this.setState({ isLoading: false });
return team;
}
getCurrentPage() {
const pages = ['members', 'settings', 'groupsync'];
const currentPage = this.props.pageName;
return includes(pages, currentPage) ? currentPage : pages[0];
}
textsAreEqual = (text1: string, text2: string) => {
if (!text1 && !text2) {
return true;
}
if (!text1 || !text2) {
return false;
}
return text1.toLocaleLowerCase() === text2.toLocaleLowerCase();
};
hideTabsFromNonTeamAdmin = (pageNav: NavModelItem, isSignedInUserTeamAdmin: boolean) => {
if (contextSrv.accessControlEnabled()) {
return pageNav;
}
if (!isSignedInUserTeamAdmin && pageNav && pageNav.children) {
pageNav.children
.filter((navItem) => !this.textsAreEqual(navItem.text, PageTypes.Members))
.map((navItem) => {
navItem.hideFromTabs = true;
});
}
return pageNav;
};
renderPage(isSignedInUserTeamAdmin: boolean): React.ReactNode {
const { isSyncEnabled } = this.state;
const { members, team } = this.props;
const currentPage = this.getCurrentPage();
const canReadTeam = contextSrv.hasAccessInMetadata(
AccessControlAction.ActionTeamsRead,
team!,
isSignedInUserTeamAdmin
);
const canReadTeamPermissions = contextSrv.hasAccessInMetadata(
AccessControlAction.ActionTeamsPermissionsRead,
team!,
isSignedInUserTeamAdmin
);
const canWriteTeamPermissions = contextSrv.hasAccessInMetadata(
AccessControlAction.ActionTeamsPermissionsWrite,
team!,
isSignedInUserTeamAdmin
);
switch (currentPage) {
case PageTypes.Members:
if (contextSrv.accessControlEnabled()) {
return <TeamPermissions team={team!} />;
} else {
return <TeamMembers syncEnabled={isSyncEnabled} members={members} />;
}
case PageTypes.Settings:
return canReadTeam && <TeamSettings team={team!} />;
case PageTypes.GroupSync:
if (isSyncEnabled) {
if (canReadTeamPermissions) {
return <TeamGroupSync isReadOnly={!canWriteTeamPermissions} />;
}
} else if (config.featureToggles.featureHighlights) {
return (
<>
<UpgradeBox featureName={'team sync'} featureId={'team-sync'} />
<TeamSyncUpgradeContent />
</>
);
}
}
return null;
}
render() {
const { team, pageNav, members, editorsCanAdmin, signedInUser } = this.props;
const isTeamAdmin = isSignedInUserTeamAdmin({ members, editorsCanAdmin, signedInUser });
return (
<Page navId="teams" pageNav={this.hideTabsFromNonTeamAdmin(pageNav, isTeamAdmin)}>
<Page.Contents isLoading={this.state.isLoading}>
{team && Object.keys(team).length !== 0 && this.renderPage(isTeamAdmin)}
</Page.Contents>
</Page>
);
}
}
export default connector(withTheme2(TeamPages));