TeamPages.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { includes } from 'lodash';
  2. import React, { PureComponent } from 'react';
  3. import { connect, ConnectedProps } from 'react-redux';
  4. import { NavModel } from '@grafana/data';
  5. import { featureEnabled } from '@grafana/runtime';
  6. import { Themeable2, withTheme2 } from '@grafana/ui';
  7. import Page from 'app/core/components/Page/Page';
  8. import { UpgradeBox } from 'app/core/components/Upgrade/UpgradeBox';
  9. import config from 'app/core/config';
  10. import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
  11. import { getNavModel } from 'app/core/selectors/navModel';
  12. import { contextSrv } from 'app/core/services/context_srv';
  13. import { AccessControlAction, StoreState } from 'app/types';
  14. import TeamGroupSync, { TeamSyncUpgradeContent } from './TeamGroupSync';
  15. import TeamMembers from './TeamMembers';
  16. import TeamPermissions from './TeamPermissions';
  17. import TeamSettings from './TeamSettings';
  18. import { loadTeam, loadTeamMembers } from './state/actions';
  19. import { getTeamLoadingNav } from './state/navModel';
  20. import { getTeam, getTeamMembers, isSignedInUserTeamAdmin } from './state/selectors';
  21. interface TeamPageRouteParams {
  22. id: string;
  23. page: string | null;
  24. }
  25. export interface OwnProps extends GrafanaRouteComponentProps<TeamPageRouteParams>, Themeable2 {}
  26. interface State {
  27. isSyncEnabled: boolean;
  28. isLoading: boolean;
  29. }
  30. enum PageTypes {
  31. Members = 'members',
  32. Settings = 'settings',
  33. GroupSync = 'groupsync',
  34. }
  35. function mapStateToProps(state: StoreState, props: OwnProps) {
  36. const teamId = parseInt(props.match.params.id, 10);
  37. const team = getTeam(state.team, teamId);
  38. let defaultPage = 'members';
  39. if (contextSrv.accessControlEnabled()) {
  40. // With RBAC the settings page will always be available
  41. if (!team || !contextSrv.hasPermissionInMetadata(AccessControlAction.ActionTeamsPermissionsRead, team)) {
  42. defaultPage = 'settings';
  43. }
  44. }
  45. const pageName = props.match.params.page ?? defaultPage;
  46. const teamLoadingNav = getTeamLoadingNav(pageName as string);
  47. const navModel = getNavModel(state.navIndex, `team-${pageName}-${teamId}`, teamLoadingNav);
  48. const members = getTeamMembers(state.team);
  49. return {
  50. navModel,
  51. teamId: teamId,
  52. pageName: pageName,
  53. team,
  54. members,
  55. editorsCanAdmin: config.editorsCanAdmin, // this makes the feature toggle mockable/controllable from tests,
  56. signedInUser: contextSrv.user, // this makes the feature toggle mockable/controllable from tests,
  57. };
  58. }
  59. const mapDispatchToProps = {
  60. loadTeam,
  61. loadTeamMembers,
  62. };
  63. const connector = connect(mapStateToProps, mapDispatchToProps);
  64. export type Props = OwnProps & ConnectedProps<typeof connector>;
  65. export class TeamPages extends PureComponent<Props, State> {
  66. constructor(props: Props) {
  67. super(props);
  68. this.state = {
  69. isLoading: false,
  70. isSyncEnabled: featureEnabled('teamsync'),
  71. };
  72. }
  73. async componentDidMount() {
  74. await this.fetchTeam();
  75. }
  76. async fetchTeam() {
  77. const { loadTeam, teamId } = this.props;
  78. this.setState({ isLoading: true });
  79. const team = await loadTeam(teamId);
  80. // With accesscontrol, the TeamPermissions will fetch team members
  81. if (!contextSrv.accessControlEnabled()) {
  82. await this.props.loadTeamMembers();
  83. }
  84. this.setState({ isLoading: false });
  85. return team;
  86. }
  87. getCurrentPage() {
  88. const pages = ['members', 'settings', 'groupsync'];
  89. const currentPage = this.props.pageName;
  90. return includes(pages, currentPage) ? currentPage : pages[0];
  91. }
  92. textsAreEqual = (text1: string, text2: string) => {
  93. if (!text1 && !text2) {
  94. return true;
  95. }
  96. if (!text1 || !text2) {
  97. return false;
  98. }
  99. return text1.toLocaleLowerCase() === text2.toLocaleLowerCase();
  100. };
  101. hideTabsFromNonTeamAdmin = (navModel: NavModel, isSignedInUserTeamAdmin: boolean) => {
  102. if (contextSrv.accessControlEnabled()) {
  103. return navModel;
  104. }
  105. if (!isSignedInUserTeamAdmin && navModel.main && navModel.main.children) {
  106. navModel.main.children
  107. .filter((navItem) => !this.textsAreEqual(navItem.text, PageTypes.Members))
  108. .map((navItem) => {
  109. navItem.hideFromTabs = true;
  110. });
  111. }
  112. return navModel;
  113. };
  114. renderPage(isSignedInUserTeamAdmin: boolean): React.ReactNode {
  115. const { isSyncEnabled } = this.state;
  116. const { members, team } = this.props;
  117. const currentPage = this.getCurrentPage();
  118. const canReadTeam = contextSrv.hasAccessInMetadata(
  119. AccessControlAction.ActionTeamsRead,
  120. team!,
  121. isSignedInUserTeamAdmin
  122. );
  123. const canReadTeamPermissions = contextSrv.hasAccessInMetadata(
  124. AccessControlAction.ActionTeamsPermissionsRead,
  125. team!,
  126. isSignedInUserTeamAdmin
  127. );
  128. const canWriteTeamPermissions = contextSrv.hasAccessInMetadata(
  129. AccessControlAction.ActionTeamsPermissionsWrite,
  130. team!,
  131. isSignedInUserTeamAdmin
  132. );
  133. switch (currentPage) {
  134. case PageTypes.Members:
  135. if (contextSrv.accessControlEnabled()) {
  136. return <TeamPermissions team={team!} />;
  137. } else {
  138. return <TeamMembers syncEnabled={isSyncEnabled} members={members} />;
  139. }
  140. case PageTypes.Settings:
  141. return canReadTeam && <TeamSettings team={team!} />;
  142. case PageTypes.GroupSync:
  143. if (isSyncEnabled) {
  144. if (canReadTeamPermissions) {
  145. return <TeamGroupSync isReadOnly={!canWriteTeamPermissions} />;
  146. }
  147. } else if (config.featureToggles.featureHighlights) {
  148. return (
  149. <>
  150. <UpgradeBox featureName={'team sync'} featureId={'team-sync'} />
  151. <TeamSyncUpgradeContent />
  152. </>
  153. );
  154. }
  155. }
  156. return null;
  157. }
  158. render() {
  159. const { team, navModel, members, editorsCanAdmin, signedInUser } = this.props;
  160. const isTeamAdmin = isSignedInUserTeamAdmin({ members, editorsCanAdmin, signedInUser });
  161. return (
  162. <Page navModel={this.hideTabsFromNonTeamAdmin(navModel, isTeamAdmin)}>
  163. <Page.Contents isLoading={this.state.isLoading}>
  164. {team && Object.keys(team).length !== 0 && this.renderPage(isTeamAdmin)}
  165. </Page.Contents>
  166. </Page>
  167. );
  168. }
  169. }
  170. export default connector(withTheme2(TeamPages));