mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Redone with DataSourcePermissions
This commit is contained in:
parent
78b56dd528
commit
d71ae7bd4d
128
public/app/features/datasources/AddDataSourcePermissions.tsx
Normal file
128
public/app/features/datasources/AddDataSourcePermissions.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { UserPicker } from 'app/core/components/Picker/UserPicker';
|
||||
import { Team, TeamPicker } from 'app/core/components/Picker/TeamPicker';
|
||||
import DescriptionPicker, { OptionWithDescription } from 'app/core/components/Picker/DescriptionPicker';
|
||||
import { AclTarget, DataSourcePermissionLevel } from 'app/types/acl';
|
||||
import { User } from 'app/types';
|
||||
|
||||
export interface Props {
|
||||
onAddPermission: (state) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
userId: number;
|
||||
teamId: number;
|
||||
type: AclTarget;
|
||||
permission: DataSourcePermissionLevel;
|
||||
}
|
||||
|
||||
export class AddDataSourcePermissions extends PureComponent<Props, State> {
|
||||
cleanState = () => ({
|
||||
userId: 0,
|
||||
teamId: 0,
|
||||
type: AclTarget.Team,
|
||||
permission: DataSourcePermissionLevel.Query,
|
||||
});
|
||||
|
||||
state = this.cleanState();
|
||||
|
||||
isValid() {
|
||||
switch (this.state.type) {
|
||||
case AclTarget.Team:
|
||||
return this.state.teamId > 0;
|
||||
case AclTarget.User:
|
||||
return this.state.userId > 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
onTeamSelected = (team: Team) => {
|
||||
this.setState({ teamId: team ? team.id : 0 });
|
||||
};
|
||||
|
||||
onUserSelected = (user: User) => {
|
||||
this.setState({ userId: user ? user.id : 0 });
|
||||
};
|
||||
|
||||
onPermissionChanged = (permission: OptionWithDescription) => {
|
||||
this.setState({ permission: permission.value });
|
||||
};
|
||||
|
||||
onTypeChanged = event => {
|
||||
const type = event.target.value as AclTarget;
|
||||
|
||||
this.setState({ type: type, userId: 0, teamId: 0 });
|
||||
};
|
||||
|
||||
onSubmit = async event => {
|
||||
event.preventDefault();
|
||||
|
||||
await this.props.onAddPermission(this.state);
|
||||
this.setState(this.cleanState());
|
||||
};
|
||||
|
||||
render() {
|
||||
const { onCancel } = this.props;
|
||||
const { type, teamId, userId, permission } = this.state;
|
||||
|
||||
const pickerClassName = 'width-20';
|
||||
const aclTargets = [{ value: AclTarget.Team, text: 'Team' }, { value: AclTarget.User, text: 'User' }];
|
||||
const permissionLevels = [
|
||||
{ value: DataSourcePermissionLevel.Query, label: 'Query', description: 'Can query data source.' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="gf-form-inline cta-form">
|
||||
<button className="cta-form__close btn btn-transparent" onClick={onCancel}>
|
||||
<i className="fa fa-close" />
|
||||
</button>
|
||||
<form name="addPermission" onSubmit={this.onSubmit}>
|
||||
<h5>Add Permission For</h5>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<div className="gf-form-select-wrapper">
|
||||
<select className="gf-form-input gf-size-auto" value={type} onChange={this.onTypeChanged}>
|
||||
{aclTargets.map((option, idx) => {
|
||||
return (
|
||||
<option key={idx} value={option.value}>
|
||||
{option.text}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{type === AclTarget.User && (
|
||||
<div className="gf-form">
|
||||
<UserPicker onSelected={this.onUserSelected} value={userId.toString()} className={pickerClassName} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{type === AclTarget.Team && (
|
||||
<div className="gf-form">
|
||||
<TeamPicker onSelected={this.onTeamSelected} value={teamId.toString()} className={pickerClassName} />
|
||||
</div>
|
||||
)}
|
||||
<div className="gf-form">
|
||||
<DescriptionPicker
|
||||
optionsWithDesc={permissionLevels}
|
||||
onSelected={this.onPermissionChanged}
|
||||
value={permission}
|
||||
disabled={false}
|
||||
className={'gf-form-input--form-dropdown-right'}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<button data-save-permission className="btn btn-success" type="submit" disabled={!this.isValid()}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AddDataSourcePermissions;
|
@ -1,10 +1,20 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import SlideDown from '../../core/components/Animations/SlideDown';
|
||||
import AddPermissions from '../../core/components/PermissionList/AddPermission';
|
||||
import { AclTarget, AclTargetInfo } from 'app/types/acl';
|
||||
import AddDataSourcePermissions from './AddDataSourcePermissions';
|
||||
import { AclTarget } from 'app/types/acl';
|
||||
import { addDataSourcePermission, loadDataSourcePermissions, removeDataSourcePermission } from './state/actions';
|
||||
import { DashboardAcl, DataSourcePermission } from 'app/types';
|
||||
import { getRouteParamsId } from '../../core/selectors/location';
|
||||
import PermissionList from '../../core/components/PermissionList/PermissionList';
|
||||
|
||||
export interface Props {}
|
||||
export interface Props {
|
||||
dataSourcePermissions: DataSourcePermission[];
|
||||
pageId: number;
|
||||
addDataSourcePermission: typeof addDataSourcePermission;
|
||||
loadDataSourcePermissions: typeof loadDataSourcePermissions;
|
||||
removeDataSourcePermission: typeof removeDataSourcePermission;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isAdding: boolean;
|
||||
@ -15,13 +25,42 @@ export class DataSourcePermissions extends PureComponent<Props, State> {
|
||||
isAdding: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchDataSourcePermissions();
|
||||
}
|
||||
|
||||
async fetchDataSourcePermissions() {
|
||||
const { pageId, loadDataSourcePermissions } = this.props;
|
||||
|
||||
return await loadDataSourcePermissions(pageId);
|
||||
}
|
||||
|
||||
onOpenAddPermissions = () => {
|
||||
this.setState({
|
||||
isAdding: true,
|
||||
});
|
||||
};
|
||||
|
||||
onAddPermission = () => {};
|
||||
onAddPermission = state => {
|
||||
const { pageId, addDataSourcePermission } = this.props;
|
||||
const data = {
|
||||
permission: state.permission,
|
||||
userId: 0,
|
||||
teamId: 0,
|
||||
};
|
||||
|
||||
if (state.type === AclTarget.Team) {
|
||||
data.teamId = state.teamId;
|
||||
} else if (state.team === AclTarget.User) {
|
||||
data.userId = state.userId;
|
||||
}
|
||||
|
||||
addDataSourcePermission(pageId, data);
|
||||
};
|
||||
|
||||
onRemovePermission = (item: DashboardAcl) => {
|
||||
this.props.removeDataSourcePermission(1, 1);
|
||||
};
|
||||
|
||||
onCancelAddPermission = () => {
|
||||
this.setState({
|
||||
@ -30,13 +69,9 @@ export class DataSourcePermissions extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { dataSourcePermissions } = this.props;
|
||||
const { isAdding } = this.state;
|
||||
|
||||
const dashboardAclTargets: AclTargetInfo[] = [
|
||||
{ value: AclTarget.Team, text: 'Team' },
|
||||
{ value: AclTarget.User, text: 'User' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="page-action-bar">
|
||||
@ -47,20 +82,33 @@ export class DataSourcePermissions extends PureComponent<Props, State> {
|
||||
</button>
|
||||
</div>
|
||||
<SlideDown in={isAdding}>
|
||||
<AddPermissions
|
||||
dashboardAclTargets={dashboardAclTargets}
|
||||
showPermissionLevels={false}
|
||||
onAddPermission={this.onAddPermission}
|
||||
<AddDataSourcePermissions
|
||||
onAddPermission={state => this.onAddPermission(state)}
|
||||
onCancel={this.onCancelAddPermission}
|
||||
/>
|
||||
</SlideDown>
|
||||
<PermissionList
|
||||
items={dataSourcePermissions}
|
||||
onRemoveItem={this.onRemovePermission}
|
||||
onPermissionChanged={() => {}}
|
||||
isFetching={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {};
|
||||
return {
|
||||
pageId: getRouteParamsId(state.location),
|
||||
dataSourcePermissions: state.dataSources.dataSourcePermissions,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(DataSourcePermissions);
|
||||
const mapDispatchToProps = {
|
||||
addDataSourcePermission,
|
||||
loadDataSourcePermissions,
|
||||
removeDataSourcePermission,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DataSourcePermissions);
|
||||
|
@ -5,12 +5,14 @@ import { LayoutMode } from '../../../core/components/LayoutSelector/LayoutSelect
|
||||
import { updateLocation, updateNavIndex, UpdateNavIndexAction } from '../../../core/actions';
|
||||
import { UpdateLocationAction } from '../../../core/actions/location';
|
||||
import { buildNavModel } from './navModel';
|
||||
import { DataSourcePermission } from '../../../types/datasources';
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadDataSources = 'LOAD_DATA_SOURCES',
|
||||
LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES',
|
||||
LoadDataSource = 'LOAD_DATA_SOURCE',
|
||||
LoadDataSourceMeta = 'LOAD_DATA_SOURCE_META',
|
||||
LoadDataSourcePermissions = 'LOAD_DATA_SOURCE_PERMISSIONS',
|
||||
SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY',
|
||||
SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
|
||||
SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
|
||||
@ -51,6 +53,11 @@ export interface LoadDataSourceMetaAction {
|
||||
payload: Plugin;
|
||||
}
|
||||
|
||||
export interface LoadDataSourcePermissionsAction {
|
||||
type: ActionTypes.LoadDataSourcePermissions;
|
||||
payload: DataSourcePermission[];
|
||||
}
|
||||
|
||||
const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
|
||||
type: ActionTypes.LoadDataSources,
|
||||
payload: dataSources,
|
||||
@ -71,6 +78,13 @@ const dataSourceTypesLoaded = (dataSourceTypes: Plugin[]): LoadDataSourceTypesAc
|
||||
payload: dataSourceTypes,
|
||||
});
|
||||
|
||||
const dataSourcePermissionsLoaded = (
|
||||
dataSourcePermissions: DataSourcePermission[]
|
||||
): LoadDataSourcePermissionsAction => ({
|
||||
type: ActionTypes.LoadDataSourcePermissions,
|
||||
payload: dataSourcePermissions,
|
||||
});
|
||||
|
||||
export const setDataSourcesSearchQuery = (searchQuery: string): SetDataSourcesSearchQueryAction => ({
|
||||
type: ActionTypes.SetDataSourcesSearchQuery,
|
||||
payload: searchQuery,
|
||||
@ -95,7 +109,8 @@ export type Action =
|
||||
| SetDataSourceTypeSearchQueryAction
|
||||
| LoadDataSourceAction
|
||||
| UpdateNavIndexAction
|
||||
| LoadDataSourceMetaAction;
|
||||
| LoadDataSourceMetaAction
|
||||
| LoadDataSourcePermissionsAction;
|
||||
|
||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
||||
|
||||
@ -145,6 +160,28 @@ export function loadDataSourceTypes(): ThunkResult<void> {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadDataSourcePermissions(id: number): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
const response = await getBackendSrv().get(`/api/datasources/${id}/permissions`);
|
||||
dispatch(dataSourcePermissionsLoaded(response.permissions));
|
||||
};
|
||||
}
|
||||
|
||||
export function addDataSourcePermission(id: number, data: object): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
await getBackendSrv().post(`/api/datasources/${id}/permissions`, data);
|
||||
|
||||
dispatch(loadDataSourcePermissions(id));
|
||||
};
|
||||
}
|
||||
|
||||
export function removeDataSourcePermission(id: number, permissionId: number): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
await getBackendSrv().delete(`/api/datasources/${id}/permissions/${permissionId}`);
|
||||
dispatch(loadDataSourcePermissions(id));
|
||||
};
|
||||
}
|
||||
|
||||
export function nameExits(dataSources, name) {
|
||||
return (
|
||||
dataSources.filter(dataSource => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataSource, DataSourcesState, Plugin } from 'app/types';
|
||||
import { DataSource, DataSourcePermission, DataSourcesState, Plugin } from 'app/types';
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import { LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector';
|
||||
|
||||
@ -11,6 +11,7 @@ const initialState: DataSourcesState = {
|
||||
dataSourceTypes: [] as Plugin[],
|
||||
dataSourceTypeSearchQuery: '',
|
||||
dataSourceMeta: {} as Plugin,
|
||||
dataSourcePermissions: [] as DataSourcePermission[],
|
||||
};
|
||||
|
||||
export const dataSourcesReducer = (state = initialState, action: Action): DataSourcesState => {
|
||||
@ -35,6 +36,9 @@ export const dataSourcesReducer = (state = initialState, action: Action): DataSo
|
||||
|
||||
case ActionTypes.LoadDataSourceMeta:
|
||||
return { ...state, dataSourceMeta: action.payload };
|
||||
|
||||
case ActionTypes.LoadDataSourcePermissions:
|
||||
return { ...state, dataSourcePermissions: action.payload };
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -61,6 +61,11 @@ export enum PermissionLevel {
|
||||
Admin = 4,
|
||||
}
|
||||
|
||||
export enum DataSourcePermissionLevel {
|
||||
Query = 1,
|
||||
Admin = 2,
|
||||
}
|
||||
|
||||
export enum AclTarget {
|
||||
Team = 'Team',
|
||||
User = 'User',
|
||||
|
@ -1,6 +1,19 @@
|
||||
import { LayoutMode } from '../core/components/LayoutSelector/LayoutSelector';
|
||||
import { Plugin } from './plugins';
|
||||
|
||||
export interface DataSourcePermission {
|
||||
id: number;
|
||||
datasourceId: number;
|
||||
userId: number;
|
||||
userLogin: string;
|
||||
userEmail: string;
|
||||
userAvatarUrl: string;
|
||||
permission: number;
|
||||
permissionName: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
export interface DataSource {
|
||||
id: number;
|
||||
orgId: number;
|
||||
@ -27,4 +40,5 @@ export interface DataSourcesState {
|
||||
dataSourceTypes: Plugin[];
|
||||
dataSource: DataSource;
|
||||
dataSourceMeta: Plugin;
|
||||
dataSourcePermissions: DataSourcePermission[];
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { DashboardState } from './dashboard';
|
||||
import { DashboardAcl, OrgRole, PermissionLevel } from './acl';
|
||||
import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
|
||||
import { Invitee, OrgUser, User, UsersState } from './user';
|
||||
import { DataSource, DataSourcesState } from './datasources';
|
||||
import { DataSource, DataSourcePermission, DataSourcesState } from './datasources';
|
||||
import { PluginMeta, Plugin, PluginsState } from './plugins';
|
||||
|
||||
export {
|
||||
@ -41,6 +41,7 @@ export {
|
||||
Plugin,
|
||||
PluginsState,
|
||||
DataSourcesState,
|
||||
DataSourcePermission,
|
||||
Invitee,
|
||||
OrgUser,
|
||||
User,
|
||||
|
Loading…
Reference in New Issue
Block a user