mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
UserProfile: convert user organizations section to react (#18707)
* convert user organizations section to react * reload page on org change
This commit is contained in:
parent
849d4881cd
commit
e80e3608ad
@ -1,19 +1,24 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv } from '@grafana/runtime';
|
||||||
import { User, Team } from 'app/types';
|
import { User, Team } from 'app/types';
|
||||||
|
import { config } from 'app/core/config';
|
||||||
|
|
||||||
export interface UserAPI {
|
export interface UserAPI {
|
||||||
changePassword: (changePassword: ChangePasswordFields) => void;
|
changePassword: (changePassword: ChangePasswordFields) => void;
|
||||||
updateUserProfile: (profile: ProfileUpdateFields) => void;
|
updateUserProfile: (profile: ProfileUpdateFields) => void;
|
||||||
loadUser: () => void;
|
loadUser: () => void;
|
||||||
loadTeams: () => void;
|
loadTeams: () => void;
|
||||||
|
loadOrgs: () => void;
|
||||||
|
setUserOrg: (org: UserOrg) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoadingStates {
|
interface LoadingStates {
|
||||||
changePassword: boolean;
|
changePassword: boolean;
|
||||||
loadUser: boolean;
|
loadUser: boolean;
|
||||||
loadTeams: boolean;
|
loadTeams: boolean;
|
||||||
|
loadOrgs: boolean;
|
||||||
updateUserProfile: boolean;
|
updateUserProfile: boolean;
|
||||||
|
updateUserOrg: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChangePasswordFields {
|
export interface ChangePasswordFields {
|
||||||
@ -28,25 +33,35 @@ export interface ProfileUpdateFields {
|
|||||||
login: string;
|
login: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserOrg {
|
||||||
|
orgId: number;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
userId?: number; // passed, will load user on mount
|
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 {
|
export interface State {
|
||||||
user?: User;
|
user?: User;
|
||||||
teams: Team[];
|
teams: Team[];
|
||||||
|
orgs: UserOrg[];
|
||||||
loadingStates: LoadingStates;
|
loadingStates: LoadingStates;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserProvider extends PureComponent<Props, State> {
|
export class UserProvider extends PureComponent<Props, State> {
|
||||||
state: State = {
|
state: State = {
|
||||||
teams: [] as Team[],
|
teams: [] as Team[],
|
||||||
|
orgs: [] as UserOrg[],
|
||||||
loadingStates: {
|
loadingStates: {
|
||||||
changePassword: false,
|
changePassword: false,
|
||||||
loadUser: true,
|
loadUser: true,
|
||||||
loadTeams: false,
|
loadTeams: false,
|
||||||
|
loadOrgs: false,
|
||||||
updateUserProfile: false,
|
updateUserProfile: false,
|
||||||
|
updateUserOrg: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,6 +93,28 @@ export class UserProvider extends PureComponent<Props, State> {
|
|||||||
this.setState({ teams, loadingStates: { ...this.state.loadingStates, loadTeams: false } });
|
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) => {
|
updateUserProfile = async (payload: ProfileUpdateFields) => {
|
||||||
this.setState({ loadingStates: { ...this.state.loadingStates, updateUserProfile: true } });
|
this.setState({ loadingStates: { ...this.state.loadingStates, updateUserProfile: true } });
|
||||||
await getBackendSrv()
|
await getBackendSrv()
|
||||||
@ -93,16 +130,18 @@ export class UserProvider extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
const { loadingStates, teams, user } = this.state;
|
const { loadingStates, teams, orgs, user } = this.state;
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
changePassword: this.changePassword,
|
changePassword: this.changePassword,
|
||||||
loadUser: this.loadUser,
|
loadUser: this.loadUser,
|
||||||
loadTeams: this.loadTeams,
|
loadTeams: this.loadTeams,
|
||||||
|
loadOrgs: this.loadOrgs,
|
||||||
updateUserProfile: this.updateUserProfile,
|
updateUserProfile: this.updateUserProfile,
|
||||||
|
setUserOrg: this.setUserOrg,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <>{children(api, loadingStates, teams, user)}</>;
|
return <>{children(api, loadingStates, teams, orgs, user)}</>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
import config from 'app/core/config';
|
|
||||||
import { coreModule, NavModelSrv } from 'app/core/core';
|
import { coreModule, NavModelSrv } from 'app/core/core';
|
||||||
import { dateTime } from '@grafana/data';
|
import { dateTime } from '@grafana/data';
|
||||||
import { UserSession } from 'app/types';
|
import { UserSession } from 'app/types';
|
||||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||||
|
|
||||||
export class ProfileCtrl {
|
export class ProfileCtrl {
|
||||||
user: any;
|
|
||||||
oldTheme: any;
|
|
||||||
orgs: any = [];
|
|
||||||
sessions: object[] = [];
|
sessions: object[] = [];
|
||||||
userForm: any;
|
|
||||||
showOrgsList = false;
|
|
||||||
readonlyLoginFields = config.disableLoginForm;
|
|
||||||
navModel: any;
|
navModel: any;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
|
constructor(private backendSrv: BackendSrv, navModelSrv: NavModelSrv) {
|
||||||
this.getUserSessions();
|
this.getUserSessions();
|
||||||
this.getUserOrgs();
|
|
||||||
this.navModel = navModelSrv.getNav('profile', 'profile-settings', 0);
|
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);
|
coreModule.controller('ProfileCtrl', ProfileCtrl);
|
||||||
|
@ -3,12 +3,13 @@ import { UserProvider } from 'app/core/utils/UserProvider';
|
|||||||
import { UserProfileEditForm } from './UserProfileEditForm';
|
import { UserProfileEditForm } from './UserProfileEditForm';
|
||||||
import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
|
import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
|
||||||
import { UserTeams } from './UserTeams';
|
import { UserTeams } from './UserTeams';
|
||||||
|
import { UserOrganizations } from './UserOrganizations';
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { LoadingPlaceholder } from '@grafana/ui';
|
import { LoadingPlaceholder } from '@grafana/ui';
|
||||||
|
|
||||||
export const ReactProfileWrapper = () => (
|
export const ReactProfileWrapper = () => (
|
||||||
<UserProvider userId={config.bootData.user.id}>
|
<UserProvider userId={config.bootData.user.id}>
|
||||||
{(api, states, teams, user) => {
|
{(api, states, teams, orgs, user) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{states.loadUser ? (
|
{states.loadUser ? (
|
||||||
@ -22,6 +23,13 @@ export const ReactProfileWrapper = () => (
|
|||||||
)}
|
)}
|
||||||
<SharedPreferences resourceUri="user" />
|
<SharedPreferences resourceUri="user" />
|
||||||
<UserTeams isLoading={states.loadTeams} loadTeams={api.loadTeams} teams={teams} />
|
<UserTeams isLoading={states.loadTeams} loadTeams={api.loadTeams} teams={teams} />
|
||||||
|
<UserOrganizations
|
||||||
|
isLoading={states.loadOrgs}
|
||||||
|
setUserOrg={api.setUserOrg}
|
||||||
|
loadOrgs={api.loadOrgs}
|
||||||
|
orgs={orgs}
|
||||||
|
user={user}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
74
public/app/features/profile/UserOrganizations.tsx
Normal file
74
public/app/features/profile/UserOrganizations.tsx
Normal file
@ -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<Props> {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.loadOrgs();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isLoading, orgs, user } = this.props;
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <LoadingPlaceholder text="Loading organizations..." />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{orgs.length > 0 && (
|
||||||
|
<>
|
||||||
|
<h3 className="page-sub-heading">Organizations</h3>
|
||||||
|
<div className="gf-form-group">
|
||||||
|
<table className="filter-table form-inline">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th />
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{orgs.map((org: UserOrg, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{org.name}</td>
|
||||||
|
<td>{org.role}</td>
|
||||||
|
<td className="text-right">
|
||||||
|
{org.orgId === user.orgId ? (
|
||||||
|
<span className="btn btn-primary btn-small">Current</span>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="inverse"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
this.props.setUserOrg(org);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Select
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserOrganizations;
|
@ -3,37 +3,6 @@
|
|||||||
<div class="page-container page-body">
|
<div class="page-container page-body">
|
||||||
<react-profile-wrapper></react-profile-wrapper>
|
<react-profile-wrapper></react-profile-wrapper>
|
||||||
|
|
||||||
<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">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Role</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="org in ctrl.orgs">
|
|
||||||
<td>{{ org.name }}</td>
|
|
||||||
<td>{{ org.role }}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<span class="btn btn-primary btn-small" ng-show="org.orgId === contextSrv.user.orgId">
|
|
||||||
Current
|
|
||||||
</span>
|
|
||||||
<a
|
|
||||||
ng-click="ctrl.setUsingOrg(org)"
|
|
||||||
class="btn btn-inverse btn-small"
|
|
||||||
ng-show="org.orgId !== contextSrv.user.orgId"
|
|
||||||
>
|
|
||||||
Select
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 class="page-heading">Sessions</h3>
|
<h3 class="page-heading">Sessions</h3>
|
||||||
<div class="gf-form-group">
|
<div class="gf-form-group">
|
||||||
<table class="filter-table form-inline">
|
<table class="filter-table form-inline">
|
||||||
|
@ -18,6 +18,7 @@ export interface User {
|
|||||||
login: string;
|
login: string;
|
||||||
email: string;
|
email: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
orgId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Invitee {
|
export interface Invitee {
|
||||||
|
Loading…
Reference in New Issue
Block a user