mirror of
https://github.com/grafana/grafana.git
synced 2025-02-12 08:35:43 -06:00
* add fixed role for datasource read operations * Add action for datasource explore * add authorize middleware to explore index route * add fgac support for explore navlink * update hasAccessToExplore to check if accesscontrol is enable and evalute action if it is * add getExploreRoles to evalute roles based onaccesscontrol, viewersCanEdit and default * create function to evaluate permissions or using fallback if accesscontrol is disabled * change hasAccess to prop and derive the value in mapStateToProps * add test case to ensure buttons is not rendered when user does not have access * Only hide return with changes button * remove internal links if user does not have access to explorer Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
134 lines
3.8 KiB
TypeScript
134 lines
3.8 KiB
TypeScript
import { useCallback } from 'react';
|
|
import {
|
|
Field,
|
|
LinkModel,
|
|
TimeRange,
|
|
mapInternalLinkToExplore,
|
|
InterpolateFunction,
|
|
ScopedVars,
|
|
DataFrame,
|
|
getFieldDisplayValuesProxy,
|
|
} from '@grafana/data';
|
|
import { getTemplateSrv } from '@grafana/runtime';
|
|
import { SplitOpen } from 'app/types/explore';
|
|
import { getLinkSrv } from '../../panel/panellinks/link_srv';
|
|
import { contextSrv } from 'app/core/services/context_srv';
|
|
|
|
/**
|
|
* Get links from the field of a dataframe and in addition check if there is associated
|
|
* metadata with datasource in which case we will add onClick to open the link in new split window. This assumes
|
|
* that we just supply datasource name and field value and Explore split window will know how to render that
|
|
* appropriately. This is for example used for transition from log with traceId to trace datasource to show that
|
|
* trace.
|
|
*/
|
|
export const getFieldLinksForExplore = (options: {
|
|
field: Field;
|
|
rowIndex: number;
|
|
splitOpenFn?: SplitOpen;
|
|
range: TimeRange;
|
|
vars?: ScopedVars;
|
|
dataFrame?: DataFrame;
|
|
}): Array<LinkModel<Field>> => {
|
|
const { field, vars, splitOpenFn, range, rowIndex, dataFrame } = options;
|
|
const scopedVars: any = { ...(vars || {}) };
|
|
scopedVars['__value'] = {
|
|
value: {
|
|
raw: field.values.get(rowIndex),
|
|
},
|
|
text: 'Raw value',
|
|
};
|
|
|
|
// If we have a dataFrame we can allow referencing other columns and their values in the interpolation.
|
|
if (dataFrame) {
|
|
scopedVars['__data'] = {
|
|
value: {
|
|
name: dataFrame.name,
|
|
refId: dataFrame.refId,
|
|
fields: getFieldDisplayValuesProxy({
|
|
frame: dataFrame,
|
|
rowIndex,
|
|
}),
|
|
},
|
|
text: 'Data',
|
|
};
|
|
}
|
|
|
|
if (field.config.links) {
|
|
const links = [];
|
|
|
|
if (!contextSrv.hasAccessToExplore()) {
|
|
links.push(...field.config.links.filter((l) => !l.internal));
|
|
} else {
|
|
links.push(...field.config.links);
|
|
}
|
|
|
|
return links.map((link) => {
|
|
if (!link.internal) {
|
|
const replace: InterpolateFunction = (value, vars) =>
|
|
getTemplateSrv().replace(value, { ...vars, ...scopedVars });
|
|
|
|
const linkModel = getLinkSrv().getDataLinkUIModel(link, replace, field);
|
|
if (!linkModel.title) {
|
|
linkModel.title = getTitleFromHref(linkModel.href);
|
|
}
|
|
return linkModel;
|
|
} else {
|
|
return mapInternalLinkToExplore({
|
|
link,
|
|
internalLink: link.internal,
|
|
scopedVars: scopedVars,
|
|
range,
|
|
field,
|
|
onClickFn: splitOpenFn,
|
|
replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
return [];
|
|
};
|
|
|
|
function getTitleFromHref(href: string): string {
|
|
// The URL constructor needs the url to have protocol
|
|
if (href.indexOf('://') < 0) {
|
|
// Doesn't really matter what protocol we use.
|
|
href = `http://${href}`;
|
|
}
|
|
let title;
|
|
try {
|
|
const parsedUrl = new URL(href);
|
|
title = parsedUrl.hostname;
|
|
} catch (_e) {
|
|
// Should be good enough fallback, user probably did not input valid url.
|
|
title = href;
|
|
}
|
|
return title;
|
|
}
|
|
|
|
/**
|
|
* Hook that returns a function that can be used to retrieve all the links for a row. This returns all the links from
|
|
* all the fields so is useful for visualisation where the whole row is represented as single clickable item like a
|
|
* service map.
|
|
*/
|
|
export function useLinks(range: TimeRange, splitOpenFn?: SplitOpen) {
|
|
return useCallback(
|
|
(dataFrame: DataFrame, rowIndex: number) => {
|
|
return dataFrame.fields.flatMap((f) => {
|
|
if (f.config?.links && f.config?.links.length) {
|
|
return getFieldLinksForExplore({
|
|
field: f,
|
|
rowIndex: rowIndex,
|
|
range,
|
|
dataFrame,
|
|
splitOpenFn,
|
|
});
|
|
} else {
|
|
return [];
|
|
}
|
|
});
|
|
},
|
|
[range, splitOpenFn]
|
|
);
|
|
}
|