DataSourcePermissions.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import React, { PureComponent } from 'react';
  2. import { connect, ConnectedProps } from 'react-redux';
  3. import { Alert, Button } from '@grafana/ui';
  4. import { SlideDown } from 'app/core/components/Animations/SlideDown';
  5. import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
  6. import PageHeader from 'app/core/components/PageHeader/PageHeader';
  7. import { UpgradeBox } from 'app/core/components/Upgrade/UpgradeBox';
  8. import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
  9. import { getNavModel } from 'app/core/selectors/navModel';
  10. import { highlightTrial } from 'app/features/admin/utils';
  11. import { loadDataSource, loadDataSourceMeta } from 'app/features/datasources/state/actions';
  12. import { getDataSourceLoadingNav } from 'app/features/datasources/state/navModel';
  13. import { AclTarget } from 'app/types';
  14. import { DataSourcePermission, EnterpriseStoreState } from '../types';
  15. import { AddDataSourcePermissions, State as AddState } from './AddDataSourcePermissions';
  16. import { DataSourcePermissionsList } from './DataSourcePermissionsList';
  17. import { PermissionsUpgradeContent } from './UpgradePage';
  18. import {
  19. addDataSourcePermission,
  20. disableDataSourcePermissions,
  21. enableDataSourcePermissions,
  22. loadDataSourcePermissions,
  23. removeDataSourcePermission,
  24. } from './state/actions';
  25. interface RouteProps extends GrafanaRouteComponentProps<{ uid: string }> {}
  26. function mapStateToProps(state: EnterpriseStoreState, props: RouteProps) {
  27. const uid = props.match.params.uid;
  28. const dataSourceLoadingNav = getDataSourceLoadingNav('permissions');
  29. return {
  30. uid,
  31. enabled: state.dataSourcePermission.enabled,
  32. isDefault: state.dataSources.dataSource.isDefault,
  33. permissions: state.dataSourcePermission.permissions,
  34. navModel: getNavModel(state.navIndex, `datasource-permissions-${uid}`, dataSourceLoadingNav),
  35. };
  36. }
  37. const mapDispatchToProps = {
  38. addDataSourcePermission,
  39. enableDataSourcePermissions,
  40. disableDataSourcePermissions,
  41. loadDataSourcePermissions,
  42. loadDataSource,
  43. loadDataSourceMeta,
  44. removeDataSourcePermission,
  45. };
  46. const connector = connect(mapStateToProps, mapDispatchToProps);
  47. export type Props = ConnectedProps<typeof connector>;
  48. interface State {
  49. isAdding: boolean;
  50. datasourceId: number;
  51. }
  52. export class DataSourcePermissions extends PureComponent<Props, State> {
  53. state: State = {
  54. datasourceId: 0,
  55. isAdding: false,
  56. };
  57. componentDidMount() {
  58. this.fetchDataSource().then((ds) => {
  59. this.props.loadDataSourceMeta(ds);
  60. this.setState({ datasourceId: ds.id });
  61. this.fetchDataSourcePermissions(ds.id);
  62. });
  63. }
  64. async fetchDataSource() {
  65. const { uid, loadDataSource } = this.props;
  66. return loadDataSource(uid);
  67. }
  68. async fetchDataSourcePermissions(id: number) {
  69. const { loadDataSourcePermissions } = this.props;
  70. return loadDataSourcePermissions(id);
  71. }
  72. onOpenAddPermissions = () => {
  73. this.setState({
  74. isAdding: true,
  75. });
  76. };
  77. onEnablePermissions = () => {
  78. const { enableDataSourcePermissions } = this.props;
  79. enableDataSourcePermissions(this.state.datasourceId);
  80. };
  81. onDisablePermissions = () => {
  82. const { disableDataSourcePermissions } = this.props;
  83. disableDataSourcePermissions(this.state.datasourceId);
  84. };
  85. onAddPermission = (state: AddState) => {
  86. const { addDataSourcePermission } = this.props;
  87. const data = { permission: state.permission };
  88. if (state.type === AclTarget.Team) {
  89. addDataSourcePermission(this.state.datasourceId, Object.assign(data, { teamId: state.teamId }));
  90. } else if (state.type === AclTarget.User) {
  91. addDataSourcePermission(this.state.datasourceId, Object.assign(data, { userId: state.userId }));
  92. }
  93. };
  94. onRemovePermission = (item: DataSourcePermission) => {
  95. this.props.removeDataSourcePermission(item.datasourceId, item.id);
  96. };
  97. onCancelAddPermission = () => {
  98. this.setState({
  99. isAdding: false,
  100. });
  101. };
  102. isEnabled = () => {
  103. return this.props.enabled;
  104. };
  105. renderActions = () => {
  106. const actions = [];
  107. const { isAdding } = this.state;
  108. if (this.isEnabled()) {
  109. actions.push(
  110. <Button variant={'primary'} key="add-permission" onClick={this.onOpenAddPermissions} disabled={isAdding}>
  111. Add a permission
  112. </Button>
  113. );
  114. actions.push(
  115. <Button variant={'destructive'} key="disable-permissions" onClick={this.onDisablePermissions}>
  116. Disable permissions
  117. </Button>
  118. );
  119. }
  120. return actions;
  121. };
  122. render() {
  123. const { permissions, navModel, isDefault } = this.props;
  124. const { isAdding } = this.state;
  125. return (
  126. <div>
  127. <PageHeader model={navModel} />
  128. <div className="page-container page-body">
  129. {highlightTrial() && (
  130. <UpgradeBox
  131. featureId={'data-source-permissions'}
  132. eventVariant={'trial'}
  133. featureName={'data source permissions'}
  134. text={'Enable data source permissions for free during your trial of Grafana Pro.'}
  135. />
  136. )}
  137. <div className="page-action-bar">
  138. <h3 className="page-sub-heading">Permissions</h3>
  139. <div className="page-action-bar__spacer" />
  140. {this.renderActions()}
  141. </div>
  142. {isDefault && !this.isEnabled() && (
  143. <Alert title="Warning!">
  144. Enabling permissions on the default data source makes it unavailable for users not listed in the
  145. permissions.
  146. </Alert>
  147. )}
  148. {!this.isEnabled() ? (
  149. highlightTrial() ? (
  150. <PermissionsUpgradeContent action={{ onClick: this.onEnablePermissions, text: 'Enable permissions' }} />
  151. ) : (
  152. <EmptyListCTA
  153. title="Permissions not enabled for this data source."
  154. buttonTitle="Enable"
  155. buttonIcon="unlock"
  156. onClick={this.onEnablePermissions}
  157. proTip="Only admins will be able to query the data source after you enable permissions."
  158. proTipLink="https://docs.grafana.org/permissions/datasource_permissions/"
  159. proTipLinkTitle="Learn more"
  160. />
  161. )
  162. ) : (
  163. <div>
  164. <SlideDown in={isAdding}>
  165. <AddDataSourcePermissions
  166. onAddPermission={(state) => this.onAddPermission(state)}
  167. onCancel={this.onCancelAddPermission}
  168. />
  169. </SlideDown>
  170. <DataSourcePermissionsList items={permissions} onRemoveItem={this.onRemovePermission} />
  171. </div>
  172. )}
  173. </div>
  174. </div>
  175. );
  176. }
  177. }
  178. export default connector(DataSourcePermissions);