diff --git a/public/app/core/utils/UserProvider.tsx b/public/app/core/utils/UserProvider.tsx index e1e115c23bb..1426561bda5 100644 --- a/public/app/core/utils/UserProvider.tsx +++ b/public/app/core/utils/UserProvider.tsx @@ -1,19 +1,24 @@ import React, { PureComponent } from 'react'; import { getBackendSrv } from '@grafana/runtime'; import { User, Team } from 'app/types'; +import { config } from 'app/core/config'; export interface UserAPI { changePassword: (changePassword: ChangePasswordFields) => void; updateUserProfile: (profile: ProfileUpdateFields) => void; loadUser: () => void; loadTeams: () => void; + loadOrgs: () => void; + setUserOrg: (org: UserOrg) => void; } interface LoadingStates { changePassword: boolean; loadUser: boolean; loadTeams: boolean; + loadOrgs: boolean; updateUserProfile: boolean; + updateUserOrg: boolean; } export interface ChangePasswordFields { @@ -28,25 +33,35 @@ export interface ProfileUpdateFields { login: string; } +export interface UserOrg { + orgId: number; + name: string; + role: string; +} + export interface Props { userId?: number; // passed, will load user on mount - children: (api: UserAPI, states: LoadingStates, teams: Team[], user?: User) => JSX.Element; + children: (api: UserAPI, states: LoadingStates, teams: Team[], orgs: UserOrg[], user?: User) => JSX.Element; } export interface State { user?: User; teams: Team[]; + orgs: UserOrg[]; loadingStates: LoadingStates; } export class UserProvider extends PureComponent { state: State = { teams: [] as Team[], + orgs: [] as UserOrg[], loadingStates: { changePassword: false, loadUser: true, loadTeams: false, + loadOrgs: false, updateUserProfile: false, + updateUserOrg: false, }, }; @@ -78,6 +93,28 @@ export class UserProvider extends PureComponent { this.setState({ teams, loadingStates: { ...this.state.loadingStates, loadTeams: false } }); }; + loadOrgs = async () => { + this.setState({ + loadingStates: { ...this.state.loadingStates, loadOrgs: true }, + }); + const orgs = await getBackendSrv().get('/api/user/orgs'); + this.setState({ orgs, loadingStates: { ...this.state.loadingStates, loadOrgs: false } }); + }; + + setUserOrg = async (org: UserOrg) => { + this.setState({ + loadingStates: { ...this.state.loadingStates, updateUserOrg: true }, + }); + await getBackendSrv() + .post('/api/user/using/' + org.orgId, {}) + .then(() => { + window.location.href = config.appSubUrl + '/profile'; + }) + .finally(() => { + this.setState({ loadingStates: { ...this.state.loadingStates, updateUserOrg: false } }); + }); + }; + updateUserProfile = async (payload: ProfileUpdateFields) => { this.setState({ loadingStates: { ...this.state.loadingStates, updateUserProfile: true } }); await getBackendSrv() @@ -93,16 +130,18 @@ export class UserProvider extends PureComponent { render() { const { children } = this.props; - const { loadingStates, teams, user } = this.state; + const { loadingStates, teams, orgs, user } = this.state; const api = { changePassword: this.changePassword, loadUser: this.loadUser, loadTeams: this.loadTeams, + loadOrgs: this.loadOrgs, updateUserProfile: this.updateUserProfile, + setUserOrg: this.setUserOrg, }; - return <>{children(api, loadingStates, teams, user)}; + return <>{children(api, loadingStates, teams, orgs, user)}; } } diff --git a/public/app/features/profile/ProfileCtrl.ts b/public/app/features/profile/ProfileCtrl.ts index c604541bb8e..87fb073d00f 100644 --- a/public/app/features/profile/ProfileCtrl.ts +++ b/public/app/features/profile/ProfileCtrl.ts @@ -1,23 +1,15 @@ -import config from 'app/core/config'; import { coreModule, NavModelSrv } from 'app/core/core'; import { dateTime } from '@grafana/data'; import { UserSession } from 'app/types'; import { BackendSrv } from 'app/core/services/backend_srv'; export class ProfileCtrl { - user: any; - oldTheme: any; - orgs: any = []; sessions: object[] = []; - userForm: any; - showOrgsList = false; - readonlyLoginFields = config.disableLoginForm; navModel: any; /** @ngInject */ constructor(private backendSrv: BackendSrv, navModelSrv: NavModelSrv) { this.getUserSessions(); - this.getUserOrgs(); this.navModel = navModelSrv.getNav('profile', 'profile-settings', 0); } @@ -66,19 +58,6 @@ export class ProfileCtrl { }); }); } - - getUserOrgs() { - this.backendSrv.get('/api/user/orgs').then((orgs: any) => { - this.orgs = orgs; - this.showOrgsList = orgs.length > 1; - }); - } - - setUsingOrg(org: any) { - this.backendSrv.post('/api/user/using/' + org.orgId).then(() => { - window.location.href = config.appSubUrl + '/profile'; - }); - } } coreModule.controller('ProfileCtrl', ProfileCtrl); diff --git a/public/app/features/profile/ReactProfileWrapper.tsx b/public/app/features/profile/ReactProfileWrapper.tsx index 5330d2c8b41..9ee63febd5a 100644 --- a/public/app/features/profile/ReactProfileWrapper.tsx +++ b/public/app/features/profile/ReactProfileWrapper.tsx @@ -3,12 +3,13 @@ import { UserProvider } from 'app/core/utils/UserProvider'; import { UserProfileEditForm } from './UserProfileEditForm'; import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences'; import { UserTeams } from './UserTeams'; +import { UserOrganizations } from './UserOrganizations'; import { config } from '@grafana/runtime'; import { LoadingPlaceholder } from '@grafana/ui'; export const ReactProfileWrapper = () => ( - {(api, states, teams, user) => { + {(api, states, teams, orgs, user) => { return ( <> {states.loadUser ? ( @@ -22,6 +23,13 @@ export const ReactProfileWrapper = () => ( )} + ); }} diff --git a/public/app/features/profile/UserOrganizations.tsx b/public/app/features/profile/UserOrganizations.tsx new file mode 100644 index 00000000000..7c982b1c299 --- /dev/null +++ b/public/app/features/profile/UserOrganizations.tsx @@ -0,0 +1,74 @@ +import React, { PureComponent } from 'react'; +import { User } from 'app/types'; +import { UserOrg } from 'app/core/utils/UserProvider'; +import { LoadingPlaceholder, Button } from '@grafana/ui'; + +export interface Props { + user: User; + orgs: UserOrg[]; + isLoading: boolean; + loadOrgs: () => void; + setUserOrg: (org: UserOrg) => void; +} + +export class UserOrganizations extends PureComponent { + componentDidMount() { + this.props.loadOrgs(); + } + + render() { + const { isLoading, orgs, user } = this.props; + + if (isLoading) { + return ; + } + + return ( + <> + {orgs.length > 0 && ( + <> +

Organizations

+
+ + + + + + + + + {orgs.map((org: UserOrg, index) => { + return ( + + + + + + ); + })} + +
NameRole +
{org.name}{org.role} + {org.orgId === user.orgId ? ( + Current + ) : ( + + )} +
+
+ + )} + + ); + } +} + +export default UserOrganizations; diff --git a/public/app/features/profile/partials/profile.html b/public/app/features/profile/partials/profile.html index a924cdfe2ec..a54aa600b1d 100644 --- a/public/app/features/profile/partials/profile.html +++ b/public/app/features/profile/partials/profile.html @@ -3,37 +3,6 @@
-

Organizations

-
- - - - - - - - - - - - - - - -
NameRole
{{ org.name }}{{ org.role }} - - Current - - - Select - -
-
-

Sessions

diff --git a/public/app/types/user.ts b/public/app/types/user.ts index ddf8f6bce98..77ded384778 100644 --- a/public/app/types/user.ts +++ b/public/app/types/user.ts @@ -18,6 +18,7 @@ export interface User { login: string; email: string; name: string; + orgId?: number; } export interface Invitee {