chore: add Copy request to alerting chart (#121)
* chore: add `Copy request` to alerting chart * chore: update release notes --------- Co-authored-by: yaojiping <yaojiping@infini.ltd>
This commit is contained in:
parent
9d120276d1
commit
4e8215482c
|
@ -18,7 +18,9 @@ Information about release notes of INFINI Console is provided here.
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
- add Buckets Diff to alerting rule
|
- add Copy request to alerting chart
|
||||||
|
- add credential settings for agent in enrolling agent
|
||||||
|
- add collection mode to cluster editing
|
||||||
|
|
||||||
## 1.28.1 (2025-01-24)
|
## 1.28.1 (2025-01-24)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ title: "版本历史"
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
- 告警规则新增分桶对比
|
- 告警图表新增复制请求
|
||||||
- 在注册 Agent 中新增 Agent 凭据设置
|
- 在注册 Agent 中新增 Agent 凭据设置
|
||||||
- 在集群编辑中新增采集模式
|
- 在集群编辑中新增采集模式
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@ export default (props) => {
|
||||||
isEdit,
|
isEdit,
|
||||||
fetchParamsCache,
|
fetchParamsCache,
|
||||||
handleContextMenu,
|
handleContextMenu,
|
||||||
isFullScreen
|
isFullScreen,
|
||||||
|
onResultChange
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { series = [] } = record;
|
const { series = [] } = record;
|
||||||
|
@ -99,6 +100,7 @@ export default (props) => {
|
||||||
if (!refresh) {
|
if (!refresh) {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setData()
|
setData()
|
||||||
|
onResultChange && onResultChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTimeSeries && !range) {
|
if (isTimeSeries && !range) {
|
||||||
|
@ -189,8 +191,10 @@ export default (props) => {
|
||||||
}
|
}
|
||||||
res.hits.hits = res.hits.hits || [];
|
res.hits.hits = res.hits.hits || [];
|
||||||
setData(res.hits)
|
setData(res.hits)
|
||||||
|
onResultChange && onResultChange(res)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const index_pattern = indices.join(',')
|
||||||
const bodys = metrics.map((item) => {
|
const bodys = metrics.map((item) => {
|
||||||
const { groups = [] } = item;
|
const { groups = [] } = item;
|
||||||
let newGroups = cloneDeep(groups);
|
let newGroups = cloneDeep(groups);
|
||||||
|
@ -204,7 +208,7 @@ export default (props) => {
|
||||||
return {
|
return {
|
||||||
cluster_id,
|
cluster_id,
|
||||||
filter,
|
filter,
|
||||||
index_pattern: indices.join(','),
|
index_pattern,
|
||||||
time_field: time_field,
|
time_field: time_field,
|
||||||
...item,
|
...item,
|
||||||
items: item.items || [],
|
items: item.items || [],
|
||||||
|
@ -219,6 +223,7 @@ export default (props) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
if (res.some((item) => item.status === 403)) {
|
if (res.some((item) => item.status === 403)) {
|
||||||
setData({ error: 403 })
|
setData({ error: 403 })
|
||||||
|
onResultChange && onResultChange()
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -269,8 +274,15 @@ export default (props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setData(newData)
|
setData(newData)
|
||||||
|
onResultChange && onResultChange(res.map((item) => (
|
||||||
|
{
|
||||||
|
...item,
|
||||||
|
request: item.request ? `GET ${index_pattern}/_search\n${item.request}` : undefined
|
||||||
|
}
|
||||||
|
)))
|
||||||
} else {
|
} else {
|
||||||
setData([])
|
setData([])
|
||||||
|
onResultChange && onResultChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
|
@ -41,7 +41,8 @@ export default (props) => {
|
||||||
queriesBarParams,
|
queriesBarParams,
|
||||||
isFullScreen,
|
isFullScreen,
|
||||||
hideHeader,
|
hideHeader,
|
||||||
displayOptions={}
|
displayOptions={},
|
||||||
|
onResultChange,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [cacheRecord, setCacheRecord] = useState(record)
|
const [cacheRecord, setCacheRecord] = useState(record)
|
||||||
|
@ -252,6 +253,7 @@ export default (props) => {
|
||||||
queriesBarParams={queriesBarParams}
|
queriesBarParams={queriesBarParams}
|
||||||
handleContextMenu={handleContextMenu}
|
handleContextMenu={handleContextMenu}
|
||||||
isFullScreen={isFullScreen}
|
isFullScreen={isFullScreen}
|
||||||
|
onResultChange={onResultChange}
|
||||||
/>
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
<WidgetConfigDrawer
|
<WidgetConfigDrawer
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import { useEffect, useMemo, useState } from "react"
|
import { useEffect, useMemo, useState } from "react"
|
||||||
import Widget from "./Widget"
|
import Widget from "./Widget"
|
||||||
import styles from "./WidgetLoader.less"
|
import styles from "./WidgetLoader.less"
|
||||||
import { Empty, Spin } from "antd"
|
import { Empty, Icon, message, Spin, Tooltip } from "antd"
|
||||||
import request from "@/utils/request"
|
import request from "@/utils/request"
|
||||||
import { generateFilter, mergeFilters } from "./components/QueriesBar/generate_filters"
|
import { generateFilter, mergeFilters } from "./components/QueriesBar/generate_filters"
|
||||||
import { calculateBounds } from "@/components/vendor/data/common/query/timefilter";
|
import { calculateBounds } from "@/components/vendor/data/common/query/timefilter";
|
||||||
import moment from "moment"
|
import moment from "moment"
|
||||||
import { getTimezone } from "@/utils/utils"
|
import { getTimezone } from "@/utils/utils"
|
||||||
|
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||||
|
import { formatMessage } from "umi/locale";
|
||||||
|
|
||||||
export const WidgetRender = (props) => {
|
export const WidgetRender = (props) => {
|
||||||
|
|
||||||
const { widget, range, query, queryParams = {}, highlightRange = {}, refresh } = props;
|
const { widget, range, query, queryParams = {}, highlightRange = {}, refresh, showCopy = true } = props;
|
||||||
const [globalRangeCache, setGlobalRangeCache] = useState()
|
const [globalRangeCache, setGlobalRangeCache] = useState()
|
||||||
|
const [requests, setRequests] = useState([])
|
||||||
|
|
||||||
const filters = useMemo(() => {
|
const filters = useMemo(() => {
|
||||||
const newFilters = []
|
const newFilters = []
|
||||||
|
@ -41,6 +44,18 @@ export const WidgetRender = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
widget ? (
|
widget ? (
|
||||||
|
<div className={styles.content}>
|
||||||
|
{
|
||||||
|
showCopy && requests.length > 0 && (
|
||||||
|
<CopyToClipboard text={requests.join('\n')}>
|
||||||
|
<Tooltip placement="left" title={formatMessage({id: "cluster.metrics.request.copy"})}>
|
||||||
|
<div className={styles.copy} onClick={() => message.success(formatMessage({id: "cluster.metrics.request.copy.success"}))}>
|
||||||
|
<Icon type="copy" />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</CopyToClipboard>
|
||||||
|
)
|
||||||
|
}
|
||||||
<Widget
|
<Widget
|
||||||
record={widget}
|
record={widget}
|
||||||
globalQueries={{
|
globalQueries={{
|
||||||
|
@ -66,7 +81,11 @@ export const WidgetRender = (props) => {
|
||||||
clusterList={[]}
|
clusterList={[]}
|
||||||
highlightRange={highlightRange}
|
highlightRange={highlightRange}
|
||||||
onHighlightRangeChange={() => {}}
|
onHighlightRangeChange={() => {}}
|
||||||
|
onResultChange={(res) => {
|
||||||
|
setRequests(Array.isArray(res) ? res.filter((item) => !!item.request).map((item) => item.request) : [])
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
) : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
) : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,3 +11,50 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
.copy {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
right: 0px;
|
||||||
|
top: 0px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.16) 0px 0px 5px 0px;
|
||||||
|
background: #fff;
|
||||||
|
z-index: 11;
|
||||||
|
cursor: pointer;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1890ff;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 5px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.copy {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyTooltip {
|
||||||
|
:global {
|
||||||
|
.ant-tooltip-inner {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -179,11 +179,11 @@ class ClusterForm extends React.Component {
|
||||||
agent_credential_id:
|
agent_credential_id:
|
||||||
values.agent_credential_id !== MANUAL_VALUE && isAgentMode
|
values.agent_credential_id !== MANUAL_VALUE && isAgentMode
|
||||||
? values.agent_credential_id
|
? values.agent_credential_id
|
||||||
: agent_credential_id,
|
: undefined,
|
||||||
agent_basic_auth: isAgentMode ? {
|
agent_basic_auth: {
|
||||||
username: values.agent_username,
|
username: values.agent_username,
|
||||||
password: values.agent_password,
|
password: values.agent_password,
|
||||||
} : agent_basic_auth,
|
},
|
||||||
metric_collection_mode: values.metric_collection_mode || 'agentless',
|
metric_collection_mode: values.metric_collection_mode || 'agentless',
|
||||||
|
|
||||||
description: values.description,
|
description: values.description,
|
||||||
|
@ -204,6 +204,7 @@ class ClusterForm extends React.Component {
|
||||||
if (this.clusterUUID) {
|
if (this.clusterUUID) {
|
||||||
newVals.cluster_uuid = this.clusterUUID;
|
newVals.cluster_uuid = this.clusterUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clusterConfig.editMode === "NEW") {
|
if (clusterConfig.editMode === "NEW") {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "clusterConfig/addCluster",
|
type: "clusterConfig/addCluster",
|
||||||
|
|
|
@ -90,7 +90,7 @@ export default {
|
||||||
},
|
},
|
||||||
*updateCluster({ payload }, { call, put, select }) {
|
*updateCluster({ payload }, { call, put, select }) {
|
||||||
let res = yield call(updateClusterConfig, payload);
|
let res = yield call(updateClusterConfig, payload);
|
||||||
if (res.error) {
|
if (res?.error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let { data } = yield select((state) => state.clusterConfig);
|
let { data } = yield select((state) => state.clusterConfig);
|
||||||
|
|
Loading…
Reference in New Issue