mirror of
https://github.com/grafana/grafana.git
synced 2026-08-19 01:34:54 -05:00
AccessControl: Add accesscontrol metadata to datasources DTOs (#42675)
* AccessControl: Provide scope to frontend * Covering datasources with accesscontrol metadata * Write benchmark tests for GetResourcesMetadata * Add accesscontrol util and interface * Add the hasPermissionInMetadata function in the frontend access control code * Use IsDisabled rather that performing a feature toggle check Co-authored-by: Karl Persson <kalle.persson@grafana.com>
This commit is contained in:
co-authored by
Karl Persson
parent
2b1ed43cb2
commit
c7cabdfd6f
@@ -12,7 +12,8 @@ jest.mock('app/core/core', () => {
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
isReadOnly: true,
|
||||
canSave: false,
|
||||
canDelete: false,
|
||||
onSubmit: jest.fn(),
|
||||
onDelete: jest.fn(),
|
||||
onTest: jest.fn(),
|
||||
@@ -33,7 +34,8 @@ describe('Render', () => {
|
||||
|
||||
it('should render with buttons enabled', () => {
|
||||
const wrapper = setup({
|
||||
isReadOnly: false,
|
||||
canSave: true,
|
||||
canDelete: true,
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
@@ -8,15 +8,14 @@ import { contextSrv } from 'app/core/core';
|
||||
|
||||
export interface Props {
|
||||
exploreUrl: string;
|
||||
isReadOnly: boolean;
|
||||
canSave: boolean;
|
||||
canDelete: boolean;
|
||||
onDelete: () => void;
|
||||
onSubmit: (event: any) => void;
|
||||
onTest: (event: any) => void;
|
||||
}
|
||||
|
||||
const ButtonRow: FC<Props> = ({ isReadOnly, onDelete, onSubmit, onTest, exploreUrl }) => {
|
||||
const canEditDataSources = !isReadOnly && contextSrv.hasPermission(AccessControlAction.DataSourcesWrite);
|
||||
const canDeleteDataSources = !isReadOnly && contextSrv.hasPermission(AccessControlAction.DataSourcesDelete);
|
||||
const ButtonRow: FC<Props> = ({ canSave, canDelete, onDelete, onSubmit, onTest, exploreUrl }) => {
|
||||
const canExploreDataSources = contextSrv.hasPermission(AccessControlAction.DataSourcesExplore);
|
||||
|
||||
return (
|
||||
@@ -30,24 +29,24 @@ const ButtonRow: FC<Props> = ({ isReadOnly, onDelete, onSubmit, onTest, exploreU
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
disabled={!canDeleteDataSources}
|
||||
disabled={!canDelete}
|
||||
onClick={onDelete}
|
||||
aria-label={selectors.pages.DataSource.delete}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
{canEditDataSources && (
|
||||
{canSave && (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
disabled={!canEditDataSources}
|
||||
disabled={!canSave}
|
||||
onClick={(event) => onSubmit(event)}
|
||||
aria-label={selectors.pages.DataSource.saveAndTest}
|
||||
>
|
||||
Save & test
|
||||
</Button>
|
||||
)}
|
||||
{!canEditDataSources && (
|
||||
{!canSave && (
|
||||
<Button type="submit" variant="primary" onClick={onTest}>
|
||||
Test
|
||||
</Button>
|
||||
|
||||
@@ -13,6 +13,7 @@ jest.mock('app/core/core', () => {
|
||||
return {
|
||||
contextSrv: {
|
||||
hasPermission: () => true,
|
||||
hasPermissionInMetadata: () => true,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -167,8 +167,9 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
renderLoadError() {
|
||||
const { loadError } = this.props;
|
||||
const canDeleteDataSources = !this.isReadOnly() && contextSrv.hasPermission(AccessControlAction.DataSourcesDelete);
|
||||
const { loadError, dataSource } = this.props;
|
||||
const canDeleteDataSource =
|
||||
!this.isReadOnly() && contextSrv.hasPermissionInMetadata(AccessControlAction.DataSourcesDelete, dataSource);
|
||||
|
||||
const node = {
|
||||
text: loadError!,
|
||||
@@ -185,7 +186,7 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
<Page.Contents isLoading={this.props.loading}>
|
||||
{this.isReadOnly() && this.renderIsReadOnlyMessage()}
|
||||
<div className="gf-form-button-row">
|
||||
{canDeleteDataSources && (
|
||||
{canDeleteDataSource && (
|
||||
<Button type="submit" variant="destructive" onClick={this.onDelete}>
|
||||
Delete
|
||||
</Button>
|
||||
@@ -230,11 +231,12 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
|
||||
renderSettings() {
|
||||
const { dataSourceMeta, setDataSourceName, setIsDefault, dataSource, plugin, testingStatus } = this.props;
|
||||
const canEditDataSources = contextSrv.hasPermission(AccessControlAction.DataSourcesWrite);
|
||||
const canWriteDataSource = contextSrv.hasPermissionInMetadata(AccessControlAction.DataSourcesWrite, dataSource);
|
||||
const canDeleteDataSource = contextSrv.hasPermissionInMetadata(AccessControlAction.DataSourcesDelete, dataSource);
|
||||
|
||||
return (
|
||||
<form onSubmit={this.onSubmit}>
|
||||
{!canEditDataSources && this.renderMissingEditRightsMessage()}
|
||||
{!canWriteDataSource && this.renderMissingEditRightsMessage()}
|
||||
{this.isReadOnly() && this.renderIsReadOnlyMessage()}
|
||||
{dataSourceMeta.state && (
|
||||
<div className="gf-form">
|
||||
@@ -277,7 +279,8 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
|
||||
<ButtonRow
|
||||
onSubmit={(event) => this.onSubmit(event)}
|
||||
isReadOnly={this.isReadOnly()}
|
||||
canSave={!this.isReadOnly() && canWriteDataSource}
|
||||
canDelete={!this.isReadOnly() && canDeleteDataSource}
|
||||
onDelete={this.onDelete}
|
||||
onTest={(event) => this.onTest(event)}
|
||||
exploreUrl={this.onNavigateToExplore()}
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
testDataSourceSucceeded,
|
||||
} from './reducers';
|
||||
import { getDataSource, getDataSourceMeta } from './selectors';
|
||||
import { addAccessControlQueryParam } from 'app/core/utils/accessControl';
|
||||
|
||||
export interface DataSourceTypesLoadedPayload {
|
||||
plugins: DataSourcePluginMeta[];
|
||||
@@ -154,7 +155,7 @@ export async function getDataSourceUsingUidOrId(uid: string | number): Promise<D
|
||||
const byUid = await lastValueFrom(
|
||||
getBackendSrv().fetch<DataSourceSettings>({
|
||||
method: 'GET',
|
||||
url: `/api/datasources/uid/${uid}`,
|
||||
url: addAccessControlQueryParam(`/api/datasources/uid/${uid}`),
|
||||
showErrorAlert: false,
|
||||
})
|
||||
);
|
||||
@@ -172,7 +173,7 @@ export async function getDataSourceUsingUidOrId(uid: string | number): Promise<D
|
||||
const response = await lastValueFrom(
|
||||
getBackendSrv().fetch<DataSourceSettings>({
|
||||
method: 'GET',
|
||||
url: `/api/datasources/${id}`,
|
||||
url: addAccessControlQueryParam(`/api/datasources/${id}`),
|
||||
showErrorAlert: false,
|
||||
})
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user