Browse Source

convert teams section of user profile to react (#18633)

* convert teams section of user profile to react

* isLoading prop

* loading placeholders
Shavonn Brown 6 years ago
parent
commit
1c36542018

+ 19 - 5
public/app/core/utils/UserProvider.tsx

@@ -1,16 +1,18 @@
 import React, { PureComponent } from 'react';
 import { getBackendSrv } from '@grafana/runtime';
-import { User } from 'app/types';
+import { User, Team } from 'app/types';
 
 export interface UserAPI {
   changePassword: (changePassword: ChangePasswordFields) => void;
   updateUserProfile: (profile: ProfileUpdateFields) => void;
   loadUser: () => void;
+  loadTeams: () => void;
 }
 
 interface LoadingStates {
   changePassword: boolean;
   loadUser: boolean;
+  loadTeams: boolean;
   updateUserProfile: boolean;
 }
 
@@ -28,24 +30,27 @@ export interface ProfileUpdateFields {
 
 export interface Props {
   userId?: number; // passed, will load user on mount
-  children: (api: UserAPI, states: LoadingStates, user?: User) => JSX.Element;
+  children: (api: UserAPI, states: LoadingStates, teams: Team[], user?: User) => JSX.Element;
 }
 
 export interface State {
   user?: User;
+  teams: Team[];
   loadingStates: LoadingStates;
 }
 
 export class UserProvider extends PureComponent<Props, State> {
   state: State = {
+    teams: [] as Team[],
     loadingStates: {
       changePassword: false,
       loadUser: true,
+      loadTeams: false,
       updateUserProfile: false,
     },
   };
 
-  componentDidMount() {
+  componentWillMount() {
     if (this.props.userId) {
       this.loadUser();
     }
@@ -65,6 +70,14 @@ export class UserProvider extends PureComponent<Props, State> {
     this.setState({ user, loadingStates: { ...this.state.loadingStates, loadUser: Object.keys(user).length === 0 } });
   };
 
+  loadTeams = async () => {
+    this.setState({
+      loadingStates: { ...this.state.loadingStates, loadTeams: true },
+    });
+    const teams = await getBackendSrv().get('/api/user/teams');
+    this.setState({ teams, loadingStates: { ...this.state.loadingStates, loadTeams: false } });
+  };
+
   updateUserProfile = async (payload: ProfileUpdateFields) => {
     this.setState({ loadingStates: { ...this.state.loadingStates, updateUserProfile: true } });
     await getBackendSrv()
@@ -80,15 +93,16 @@ export class UserProvider extends PureComponent<Props, State> {
 
   render() {
     const { children } = this.props;
-    const { loadingStates, user } = this.state;
+    const { loadingStates, teams, user } = this.state;
 
     const api = {
       changePassword: this.changePassword,
       loadUser: this.loadUser,
+      loadTeams: this.loadTeams,
       updateUserProfile: this.updateUserProfile,
     };
 
-    return <>{children(api, loadingStates, user)}</>;
+    return <>{children(api, loadingStates, teams, user)}</>;
   }
 }
 

+ 0 - 10
public/app/features/profile/ProfileCtrl.ts

@@ -7,11 +7,9 @@ import { BackendSrv } from 'app/core/services/backend_srv';
 export class ProfileCtrl {
   user: any;
   oldTheme: any;
-  teams: any = [];
   orgs: any = [];
   sessions: object[] = [];
   userForm: any;
-  showTeamsList = false;
   showOrgsList = false;
   readonlyLoginFields = config.disableLoginForm;
   navModel: any;
@@ -19,7 +17,6 @@ export class ProfileCtrl {
   /** @ngInject */
   constructor(private backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
     this.getUserSessions();
-    this.getUserTeams();
     this.getUserOrgs();
     this.navModel = navModelSrv.getNav('profile', 'profile-settings', 0);
   }
@@ -70,13 +67,6 @@ export class ProfileCtrl {
       });
   }
 
-  getUserTeams() {
-    this.backendSrv.get('/api/user/teams').then((teams: any) => {
-      this.teams = teams;
-      this.showTeamsList = this.teams.length > 0;
-    });
-  }
-
   getUserOrgs() {
     this.backendSrv.get('/api/user/orgs').then((orgs: any) => {
       this.orgs = orgs;

+ 7 - 2
public/app/features/profile/ReactProfileWrapper.tsx

@@ -2,14 +2,18 @@ import React from 'react';
 import { UserProvider } from 'app/core/utils/UserProvider';
 import { UserProfileEditForm } from './UserProfileEditForm';
 import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
+import { UserTeams } from './UserTeams';
 import { config } from '@grafana/runtime';
+import { LoadingPlaceholder } from '@grafana/ui';
 
 export const ReactProfileWrapper = () => (
   <UserProvider userId={config.bootData.user.id}>
-    {(api, states, user) => {
+    {(api, states, teams, user) => {
       return (
         <>
-          {!states.loadUser && (
+          {states.loadUser ? (
+            <LoadingPlaceholder text="Loading user profile..." />
+          ) : (
             <UserProfileEditForm
               updateProfile={api.updateUserProfile}
               isSavingUser={states.updateUserProfile}
@@ -17,6 +21,7 @@ export const ReactProfileWrapper = () => (
             />
           )}
           <SharedPreferences resourceUri="user" />
+          <UserTeams isLoading={states.loadTeams} loadTeams={api.loadTeams} teams={teams} />
         </>
       );
     }}

+ 61 - 0
public/app/features/profile/UserTeams.tsx

@@ -0,0 +1,61 @@
+import React, { PureComponent } from 'react';
+import { Team } from 'app/types';
+import { LoadingPlaceholder } from '@grafana/ui';
+
+export interface Props {
+  teams: Team[];
+  isLoading: boolean;
+  loadTeams: () => void;
+}
+
+export class UserTeams extends PureComponent<Props> {
+  componentDidMount() {
+    this.props.loadTeams();
+  }
+
+  render() {
+    const { isLoading, teams } = this.props;
+
+    if (isLoading) {
+      return <LoadingPlaceholder text="Loading teams..." />;
+    }
+
+    return (
+      <>
+        {teams.length > 0 && (
+          <>
+            <h3 className="page-sub-heading">Teams</h3>
+            <div className="gf-form-group">
+              <table className="filter-table form-inline">
+                <thead>
+                  <tr>
+                    <th />
+                    <th>Name</th>
+                    <th>Email</th>
+                    <th>Members</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  {teams.map((team: Team, index) => {
+                    return (
+                      <tr key={index}>
+                        <td className="width-4 text-center">
+                          <img className="filter-table__avatar" src={team.avatarUrl} />
+                        </td>
+                        <td>{team.name}</td>
+                        <td>{team.email}</td>
+                        <td>{team.memberCount}</td>
+                      </tr>
+                    );
+                  })}
+                </tbody>
+              </table>
+            </div>
+          </>
+        )}
+      </>
+    );
+  }
+}
+
+export default UserTeams;

+ 0 - 22
public/app/features/profile/partials/profile.html

@@ -3,28 +3,6 @@
 <div class="page-container page-body">
   <react-profile-wrapper></react-profile-wrapper>
 
-  <h3 class="page-heading" ng-show="ctrl.showTeamsList">Teams</h3>
-  <div class="gf-form-group" ng-show="ctrl.showTeamsList">
-    <table class="filter-table form-inline">
-      <thead>
-        <tr>
-          <th></th>
-          <th>Name</th>
-          <th>Email</th>
-          <th>Members</th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr ng-repeat="team in ctrl.teams">
-          <td class="width-4 text-center"><img class="filter-table__avatar" ng-src="{{ team.avatarUrl }}" /></td>
-          <td>{{ team.name }}</td>
-          <td>{{ team.email }}</td>
-          <td>{{ team.memberCount }}</td>
-        </tr>
-      </tbody>
-    </table>
-  </div>
-
   <h3 class="page-heading" ng-show="ctrl.showOrgsList">Organizations</h3>
   <div class="gf-form-group" ng-show="ctrl.showOrgsList">
     <table class="filter-table form-inline">