mirror of https://github.com/grafana/grafana
Logs: Add href to internal link (#23757)
parent
eae11f53f3
commit
319a0585a5
@ -0,0 +1,91 @@ |
||||
import { getFieldLinksForExplore } from './links'; |
||||
import { |
||||
ArrayVector, |
||||
DataLink, |
||||
DataSourceInstanceSettings, |
||||
dateTime, |
||||
Field, |
||||
FieldType, |
||||
LinkModel, |
||||
ScopedVars, |
||||
TimeRange, |
||||
} from '@grafana/data'; |
||||
import { setLinkSrv } from '../../panel/panellinks/link_srv'; |
||||
import { setDataSourceSrv } from '@grafana/runtime'; |
||||
|
||||
describe('getFieldLinksForExplore', () => { |
||||
it('returns correct link model for external link', () => { |
||||
const { field, range } = setup({ |
||||
title: 'external', |
||||
url: 'http://regionalhost', |
||||
}); |
||||
const links = getFieldLinksForExplore(field, 0, jest.fn(), range); |
||||
|
||||
expect(links[0].href).toBe('http://regionalhost'); |
||||
expect(links[0].title).toBe('external'); |
||||
}); |
||||
|
||||
it('returns correct link model for internal link', () => { |
||||
const { field, range } = setup({ |
||||
title: 'test', |
||||
url: 'query_1', |
||||
meta: { |
||||
datasourceUid: 'uid_1', |
||||
}, |
||||
}); |
||||
const splitfn = jest.fn(); |
||||
|
||||
const links = getFieldLinksForExplore(field, 0, splitfn, range); |
||||
|
||||
expect(links[0].href).toBe( |
||||
'/explore?left={"range":{"from":"now-1h","to":"now"},"datasource":"test_ds","queries":[{"query":"query_1"}],"mode":"Metrics","ui":{"showingGraph":true,"showingTable":true,"showingLogs":true}}' |
||||
); |
||||
expect(links[0].title).toBe('test'); |
||||
links[0].onClick({}); |
||||
expect(splitfn).toBeCalledWith({ datasourceUid: 'uid_1', query: 'query_1' }); |
||||
}); |
||||
}); |
||||
|
||||
function setup(link: DataLink) { |
||||
setLinkSrv({ |
||||
getDataLinkUIModel(link: DataLink, scopedVars: ScopedVars, origin: any): LinkModel<any> { |
||||
return { |
||||
href: link.url, |
||||
title: link.title, |
||||
target: '_blank', |
||||
origin: origin, |
||||
}; |
||||
}, |
||||
}); |
||||
setDataSourceSrv({ |
||||
getDataSourceSettingsByUid(uid: string) { |
||||
return { |
||||
id: 1, |
||||
uid: 'uid_1', |
||||
type: 'metrics', |
||||
name: 'test_ds', |
||||
meta: {}, |
||||
jsonData: {}, |
||||
} as DataSourceInstanceSettings; |
||||
}, |
||||
} as any); |
||||
const field: Field<string> = { |
||||
name: 'flux-dimensions', |
||||
type: FieldType.string, |
||||
values: new ArrayVector([]), |
||||
config: { |
||||
links: [link], |
||||
}, |
||||
}; |
||||
|
||||
const range: TimeRange = { |
||||
from: dateTime(), |
||||
to: dateTime(), |
||||
raw: { |
||||
from: 'now-1h', |
||||
to: 'now', |
||||
}, |
||||
}; |
||||
|
||||
return { range, field }; |
||||
} |
@ -0,0 +1,65 @@ |
||||
import { splitOpen } from '../state/actions'; |
||||
import { ExploreMode, Field, LinkModel, locationUtil, TimeRange } from '@grafana/data'; |
||||
import { getLinksFromLogsField } from '../../panel/panellinks/linkSuppliers'; |
||||
import { serializeStateToUrlParam } from '../../../core/utils/explore'; |
||||
import { getDataSourceSrv } from '@grafana/runtime'; |
||||
|
||||
/** |
||||
* Get links from the filed of a dataframe that was given to as 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 function getFieldLinksForExplore( |
||||
field: Field, |
||||
rowIndex: number, |
||||
splitOpenFn: typeof splitOpen, |
||||
range: TimeRange |
||||
): Array<LinkModel<Field>> { |
||||
const data = getLinksFromLogsField(field, rowIndex); |
||||
return data.map(d => { |
||||
if (d.link.meta?.datasourceUid) { |
||||
return { |
||||
...d.linkModel, |
||||
onClick: () => { |
||||
splitOpenFn({ |
||||
datasourceUid: d.link.meta.datasourceUid, |
||||
// TODO: fix the ambiguity here
|
||||
// This looks weird but in case meta.datasourceUid is set we save the query in url which will get
|
||||
// interpolated into href
|
||||
query: d.linkModel.href, |
||||
}); |
||||
}, |
||||
// We need to create real href here as the linkModel.href actually contains query. As in this case this is
|
||||
// meant to be internal link (opens split view by default) the href will also points to explore but this
|
||||
// way you can open it in new tab.
|
||||
href: generateInternalHref(d.link.meta.datasourceUid, d.linkModel.href, range), |
||||
}; |
||||
} |
||||
return d.linkModel; |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Generates href for internal derived field link. |
||||
*/ |
||||
function generateInternalHref(datasourceUid: string, query: string, range: TimeRange): string { |
||||
return locationUtil.assureBaseUrl( |
||||
`/explore?left=${serializeStateToUrlParam({ |
||||
range: range.raw, |
||||
datasource: getDataSourceSrv().getDataSourceSettingsByUid(datasourceUid).name, |
||||
// Again hardcoded for Jaeger query structure
|
||||
// TODO: fix
|
||||
queries: [{ query }], |
||||
// This should get overwritten if datasource does not support that mode and we do not know what mode is
|
||||
// preferred anyway.
|
||||
mode: ExploreMode.Metrics, |
||||
ui: { |
||||
showingGraph: true, |
||||
showingTable: true, |
||||
showingLogs: true, |
||||
}, |
||||
})}` |
||||
); |
||||
} |
Loading…
Reference in new issue