Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
319a0585
Unverified
Commit
319a0585
authored
Apr 22, 2020
by
Andrej Ocenas
Committed by
GitHub
Apr 22, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Logs: Add href to internal link (#23757)
parent
eae11f53
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
179 additions
and
33 deletions
+179
-33
packages/grafana-data/src/utils/location.ts
+1
-1
packages/grafana-runtime/src/services/dataSourceSrv.ts
+6
-1
public/app/features/alerting/getAlertingValidationMessage.test.ts
+5
-0
public/app/features/explore/LogsContainer.tsx
+9
-29
public/app/features/explore/state/actions.ts
+2
-2
public/app/features/explore/utils/links.test.ts
+91
-0
public/app/features/explore/utils/links.ts
+65
-0
No files found.
packages/grafana-data/src/utils/location.ts
View file @
319a0585
...
...
@@ -25,7 +25,7 @@ const stripBaseFromUrl = (url: string): string => {
* @param url
* @internal
*/
const
assureBaseUrl
=
(
url
:
string
)
=>
{
const
assureBaseUrl
=
(
url
:
string
)
:
string
=>
{
if
(
url
.
startsWith
(
'/'
))
{
return
`
${
grafanaConfig
?
grafanaConfig
().
appSubUrl
:
''
}${
stripBaseFromUrl
(
url
)}
`
;
}
...
...
packages/grafana-runtime/src/services/dataSourceSrv.ts
View file @
319a0585
import
{
ScopedVars
,
DataSourceApi
}
from
'@grafana/data'
;
import
{
ScopedVars
,
DataSourceApi
,
DataSourceInstanceSettings
}
from
'@grafana/data'
;
/**
* This is the entry point for communicating with a datasource that is added as
...
...
@@ -14,6 +14,11 @@ export interface DataSourceSrv {
* @param scopedVars - variables used to interpolate a templated passed as name.
*/
get
(
name
?:
string
,
scopedVars
?:
ScopedVars
):
Promise
<
DataSourceApi
>
;
/**
* Returns metadata based on UID.
*/
getDataSourceSettingsByUid
(
uid
:
string
):
DataSourceInstanceSettings
|
undefined
;
}
let
singletonInstance
:
DataSourceSrv
;
...
...
public/app/features/alerting/getAlertingValidationMessage.test.ts
View file @
319a0585
...
...
@@ -22,6 +22,7 @@ describe('getAlertingValidationMessage', () => {
const
getMock
=
jest
.
fn
().
mockResolvedValue
(
datasource
);
const
datasourceSrv
:
DataSourceSrv
=
{
get
:
getMock
,
getDataSourceSettingsByUid
():
any
{},
};
const
targets
:
ElasticsearchQuery
[]
=
[
{
refId
:
'A'
,
query
:
'@hostname:$hostname'
,
isLogsQuery
:
false
},
...
...
@@ -58,6 +59,7 @@ describe('getAlertingValidationMessage', () => {
return
Promise
.
resolve
(
alertingDatasource
);
},
getDataSourceSettingsByUid
():
any
{},
};
const
targets
:
any
[]
=
[
{
refId
:
'A'
,
query
:
'some query'
,
datasource
:
'alertingDatasource'
},
...
...
@@ -81,6 +83,7 @@ describe('getAlertingValidationMessage', () => {
const
getMock
=
jest
.
fn
().
mockResolvedValue
(
datasource
);
const
datasourceSrv
:
DataSourceSrv
=
{
get
:
getMock
,
getDataSourceSettingsByUid
():
any
{},
};
const
targets
:
ElasticsearchQuery
[]
=
[
{
refId
:
'A'
,
query
:
'@hostname:$hostname'
,
isLogsQuery
:
false
},
...
...
@@ -106,6 +109,7 @@ describe('getAlertingValidationMessage', () => {
const
getMock
=
jest
.
fn
().
mockResolvedValue
(
datasource
);
const
datasourceSrv
:
DataSourceSrv
=
{
get
:
getMock
,
getDataSourceSettingsByUid
():
any
{},
};
const
targets
:
ElasticsearchQuery
[]
=
[
{
refId
:
'A'
,
query
:
'@hostname:hostname'
,
isLogsQuery
:
false
},
...
...
@@ -131,6 +135,7 @@ describe('getAlertingValidationMessage', () => {
const
getMock
=
jest
.
fn
().
mockResolvedValue
(
datasource
);
const
datasourceSrv
:
DataSourceSrv
=
{
get
:
getMock
,
getDataSourceSettingsByUid
():
any
{},
};
const
targets
:
ElasticsearchQuery
[]
=
[
{
refId
:
'A'
,
query
:
'@hostname:hostname'
,
isLogsQuery
:
false
},
...
...
public/app/features/explore/LogsContainer.tsx
View file @
319a0585
...
...
@@ -4,23 +4,23 @@ import { connect } from 'react-redux';
import
{
Collapse
}
from
'@grafana/ui'
;
import
{
AbsoluteTimeRange
,
DataSourceApi
,
RawTimeRange
,
Field
,
GraphSeriesXY
,
LogLevel
,
TimeZone
,
AbsoluteTimeRange
,
LogRowModel
,
LogsDedupStrategy
,
TimeRange
,
LogsMetaItem
,
GraphSeriesXY
,
Field
,
RawTimeRange
,
TimeRange
,
TimeZone
,
}
from
'@grafana/data'
;
import
{
ExploreId
,
ExploreItemState
}
from
'app/types/explore'
;
import
{
StoreState
}
from
'app/types'
;
import
{
changeDedupStrategy
,
updateTimeRange
,
splitOpen
}
from
'./state/actions'
;
import
{
changeDedupStrategy
,
splitOpen
,
updateTimeRange
}
from
'./state/actions'
;
import
{
toggleLogLevelAction
}
from
'app/features/explore/state/actionTypes'
;
import
{
deduplicatedRowsSelector
}
from
'app/features/explore/state/selectors'
;
import
{
getTimeZone
}
from
'../profile/state/selectors'
;
...
...
@@ -28,7 +28,7 @@ import { LiveLogsWithTheme } from './LiveLogs';
import
{
Logs
}
from
'./Logs'
;
import
{
LogsCrossFadeTransition
}
from
'./utils/LogsCrossFadeTransition'
;
import
{
LiveTailControls
}
from
'./useLiveTailControls'
;
import
{
get
LinksFromLogsField
}
from
'../panel/panellinks/linkSupplier
s'
;
import
{
get
FieldLinksForExplore
}
from
'./utils/link
s'
;
interface
LogsContainerProps
{
datasourceInstance
?:
DataSourceApi
;
...
...
@@ -89,28 +89,8 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
return
[];
};
/**
* 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.
* @param field
* @param rowIndex
*/
getFieldLinks
=
(
field
:
Field
,
rowIndex
:
number
)
=>
{
const
data
=
getLinksFromLogsField
(
field
,
rowIndex
);
return
data
.
map
(
d
=>
{
if
(
d
.
link
.
meta
?.
datasourceUid
)
{
return
{
...
d
.
linkModel
,
onClick
:
()
=>
{
this
.
props
.
splitOpen
({
dataSourceUid
:
d
.
link
.
meta
.
datasourceUid
,
query
:
field
.
values
.
get
(
rowIndex
)
});
},
};
}
return
d
.
linkModel
;
});
return
getFieldLinksForExplore
(
field
,
rowIndex
,
this
.
props
.
splitOpen
,
this
.
props
.
range
);
};
render
()
{
...
...
public/app/features/explore/state/actions.ts
View file @
319a0585
...
...
@@ -702,7 +702,7 @@ export function splitClose(itemId: ExploreId): ThunkResult<void> {
* Otherwise it copies the left state to be the right state. The copy keeps all query modifications but wipes the query
* results.
*/
export function splitOpen(options?: { data
S
ourceUid: string; query: string }): ThunkResult<void> {
export function splitOpen(options?: { data
s
ourceUid: string; query: string }): ThunkResult<void> {
return async (dispatch, getState) => {
// Clone left state to become the right state
const leftState: ExploreItemState = getState().explore[ExploreId.left];
...
...
@@ -727,7 +727,7 @@ export function splitOpen(options?: { dataSourceUid: string; query: string }): T
} as DataQuery,
];
const dataSourceSettings = getDatasourceSrv().getDataSourceSettingsByUid(options.data
S
ourceUid);
const dataSourceSettings = getDatasourceSrv().getDataSourceSettingsByUid(options.data
s
ourceUid);
await dispatch(changeDatasource(ExploreId.right, dataSourceSettings.name));
await dispatch(setQueriesAction({ exploreId: ExploreId.right, queries }));
}
...
...
public/app/features/explore/utils/links.test.ts
0 → 100644
View file @
319a0585
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
};
}
public/app/features/explore/utils/links.ts
0 → 100644
View file @
319a0585
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
,
},
})}
`
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment