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
|
||||
|
||||
- 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)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ title: "版本历史"
|
|||
|
||||
### Improvements
|
||||
|
||||
- 告警规则新增分桶对比
|
||||
- 告警图表新增复制请求
|
||||
- 在注册 Agent 中新增 Agent 凭据设置
|
||||
- 在集群编辑中新增采集模式
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ export default (props) => {
|
|||
isEdit,
|
||||
fetchParamsCache,
|
||||
handleContextMenu,
|
||||
isFullScreen
|
||||
isFullScreen,
|
||||
onResultChange
|
||||
} = props;
|
||||
|
||||
const { series = [] } = record;
|
||||
|
@ -99,6 +100,7 @@ export default (props) => {
|
|||
if (!refresh) {
|
||||
setLoading(true)
|
||||
setData()
|
||||
onResultChange && onResultChange()
|
||||
}
|
||||
|
||||
if (isTimeSeries && !range) {
|
||||
|
@ -189,8 +191,10 @@ export default (props) => {
|
|||
}
|
||||
res.hits.hits = res.hits.hits || [];
|
||||
setData(res.hits)
|
||||
onResultChange && onResultChange(res)
|
||||
}
|
||||
} else {
|
||||
const index_pattern = indices.join(',')
|
||||
const bodys = metrics.map((item) => {
|
||||
const { groups = [] } = item;
|
||||
let newGroups = cloneDeep(groups);
|
||||
|
@ -204,7 +208,7 @@ export default (props) => {
|
|||
return {
|
||||
cluster_id,
|
||||
filter,
|
||||
index_pattern: indices.join(','),
|
||||
index_pattern,
|
||||
time_field: time_field,
|
||||
...item,
|
||||
items: item.items || [],
|
||||
|
@ -219,6 +223,7 @@ export default (props) => {
|
|||
if (res) {
|
||||
if (res.some((item) => item.status === 403)) {
|
||||
setData({ error: 403 })
|
||||
onResultChange && onResultChange()
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
@ -269,8 +274,15 @@ export default (props) => {
|
|||
}
|
||||
}
|
||||
setData(newData)
|
||||
onResultChange && onResultChange(res.map((item) => (
|
||||
{
|
||||
...item,
|
||||
request: item.request ? `GET ${index_pattern}/_search\n${item.request}` : undefined
|
||||
}
|
||||
)))
|
||||
} else {
|
||||
setData([])
|
||||
onResultChange && onResultChange()
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
|
|
|
@ -41,7 +41,8 @@ export default (props) => {
|
|||
queriesBarParams,
|
||||
isFullScreen,
|
||||
hideHeader,
|
||||
displayOptions={}
|
||||
displayOptions={},
|
||||
onResultChange,
|
||||
} = props;
|
||||
|
||||
const [cacheRecord, setCacheRecord] = useState(record)
|
||||
|
@ -252,6 +253,7 @@ export default (props) => {
|
|||
queriesBarParams={queriesBarParams}
|
||||
handleContextMenu={handleContextMenu}
|
||||
isFullScreen={isFullScreen}
|
||||
onResultChange={onResultChange}
|
||||
/>
|
||||
</Spin>
|
||||
<WidgetConfigDrawer
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import { useEffect, useMemo, useState } from "react"
|
||||
import Widget from "./Widget"
|
||||
import styles from "./WidgetLoader.less"
|
||||
import { Empty, Spin } from "antd"
|
||||
import { Empty, Icon, message, Spin, Tooltip } from "antd"
|
||||
import request from "@/utils/request"
|
||||
import { generateFilter, mergeFilters } from "./components/QueriesBar/generate_filters"
|
||||
import { calculateBounds } from "@/components/vendor/data/common/query/timefilter";
|
||||
import moment from "moment"
|
||||
import { getTimezone } from "@/utils/utils"
|
||||
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||
import { formatMessage } from "umi/locale";
|
||||
|
||||
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 [requests, setRequests] = useState([])
|
||||
|
||||
const filters = useMemo(() => {
|
||||
const newFilters = []
|
||||
|
@ -41,6 +44,18 @@ export const WidgetRender = (props) => {
|
|||
|
||||
return (
|
||||
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
|
||||
record={widget}
|
||||
globalQueries={{
|
||||
|
@ -66,7 +81,11 @@ export const WidgetRender = (props) => {
|
|||
clusterList={[]}
|
||||
highlightRange={highlightRange}
|
||||
onHighlightRangeChange={() => {}}
|
||||
onResultChange={(res) => {
|
||||
setRequests(Array.isArray(res) ? res.filter((item) => !!item.request).map((item) => item.request) : [])
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : <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:
|
||||
values.agent_credential_id !== MANUAL_VALUE && isAgentMode
|
||||
? values.agent_credential_id
|
||||
: agent_credential_id,
|
||||
agent_basic_auth: isAgentMode ? {
|
||||
: undefined,
|
||||
agent_basic_auth: {
|
||||
username: values.agent_username,
|
||||
password: values.agent_password,
|
||||
} : agent_basic_auth,
|
||||
},
|
||||
metric_collection_mode: values.metric_collection_mode || 'agentless',
|
||||
|
||||
description: values.description,
|
||||
|
@ -204,6 +204,7 @@ class ClusterForm extends React.Component {
|
|||
if (this.clusterUUID) {
|
||||
newVals.cluster_uuid = this.clusterUUID;
|
||||
}
|
||||
|
||||
if (clusterConfig.editMode === "NEW") {
|
||||
dispatch({
|
||||
type: "clusterConfig/addCluster",
|
||||
|
|
|
@ -90,7 +90,7 @@ export default {
|
|||
},
|
||||
*updateCluster({ payload }, { call, put, select }) {
|
||||
let res = yield call(updateClusterConfig, payload);
|
||||
if (res.error) {
|
||||
if (res?.error) {
|
||||
return false;
|
||||
}
|
||||
let { data } = yield select((state) => state.clusterConfig);
|
||||
|
|
Loading…
Reference in New Issue