fix: optimize UI without clusters (#8)

Co-authored-by: yaojiping <yaojiping@infini.ltd>
This commit is contained in:
yaojp123 2024-12-06 15:28:55 +08:00 committed by GitHub
parent 46a5976bf3
commit 7dd3808942
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 169 additions and 127 deletions

View File

@ -100,7 +100,14 @@ export default [
path: "/data",
name: "data",
icon: "database",
authority: ["data"],
authority: [
"data.index:all",
"data.index:read",
"data.alias:all",
"data.alias:read",
"data.view:all",
"data.view:read",
],
routes: [
{
path: "/data/index",

View File

@ -333,7 +333,7 @@ export default class GlobalHeaderRight extends PureComponent {
topLeft: false,
}}> */}
{this.props.clusterList.length > 0 &&
this.props.selectedCluster.id != "" && (
this.props.selectedCluster?.id && (
<ConsoleUI
selectedCluster={this.props.selectedCluster}
clusterList={this.props.clusterList}

View File

@ -1,5 +1,5 @@
import React, { useState, useMemo, useEffect, useCallback } from "react";
import { Card, Tabs, Breadcrumb, Button, BackTop } from "antd";
import { Card, Tabs, Breadcrumb, Button, BackTop, Empty } from "antd";
import { calculateBounds } from "@/components/vendor/data/common/query/timefilter";
import { formatter } from "@/utils/format";
import moment from "moment";
@ -117,81 +117,88 @@ const Monitor = (props) => {
<BreadcrumbList data={breadcrumbList} />
<Card bodyStyle={{ padding: 15 }}>
<div style={{ marginBottom: 5 }}>
<div style={{ display: 'flex', gap: 8 }}>
<div style={{ flexGrow: 0 }}>
<DatePicker
locale={getLocale()}
start={state.timeRange.min}
end={state.timeRange.max}
onRangeChange={({ start, end }) => {
handleTimeChange({ start, end })
}}
{...refresh}
onRefreshChange={setRefresh}
onRefresh={handleTimeChange}
showTimeSetting={true}
showTimeInterval={true}
timeInterval={state.timeInterval}
showTimeout={true}
timeout={state.timeout}
onTimeSettingChange={(timeSetting) => {
localStorage.setItem(TIMEOUT_CACHE_KEY, timeSetting.timeout)
setState({
...state,
timeInterval: timeSetting.timeInterval,
timeout: timeSetting.timeout
});
}}
timeZone={timeZone}
onTimeZoneChange={setTimeZone}
recentlyUsedRangesKey={'monitor'}
/>
</div>
</div>
</div>
<Tabs
activeKey={param?.tab || panes[0]?.key}
onChange={(key) => {
setParam({ ...param, tab: key });
}}
tabBarGutter={10}
destroyInactiveTabPane
animated={false}
>
{panes.map((pane) => (
<TabPane tab={pane.title} key={pane.key}>
<StatisticBar
setSpinning={setSpinning}
onInfoChange={onInfoChange}
{...state}
{...extraParams}
/>
<div style={{ marginTop: 15 }}>
{checkPaneParams({
...state,
...extraParams,
}) ? (
typeof pane.component == "string" ? (
pane.component
) : (
<pane.component
selectedCluster={selectedCluster}
isAgent={isAgent}
{...state}
handleTimeChange={handleTimeChange}
setSpinning={setSpinning}
{...extraParams}
bucketSize={state.timeInterval}
{
selectedCluster ? (
<>
<div style={{ marginBottom: 5 }}>
<div style={{ display: 'flex', gap: 8 }}>
<div style={{ flexGrow: 0 }}>
<DatePicker
locale={getLocale()}
start={state.timeRange.min}
end={state.timeRange.max}
onRangeChange={({ start, end }) => {
handleTimeChange({ start, end })
}}
{...refresh}
onRefreshChange={setRefresh}
onRefresh={handleTimeChange}
showTimeSetting={true}
showTimeInterval={true}
timeInterval={state.timeInterval}
showTimeout={true}
timeout={state.timeout}
onTimeSettingChange={(timeSetting) => {
localStorage.setItem(TIMEOUT_CACHE_KEY, timeSetting.timeout)
setState({
...state,
timeInterval: timeSetting.timeInterval,
timeout: timeSetting.timeout
});
}}
timeZone={timeZone}
onTimeZoneChange={setTimeZone}
recentlyUsedRangesKey={'monitor'}
/>
)
) : null}
</div>
</div>
</div>
</TabPane>
))}
</Tabs>
<Tabs
activeKey={param?.tab || panes[0]?.key}
onChange={(key) => {
setParam({ ...param, tab: key });
}}
tabBarGutter={10}
destroyInactiveTabPane
animated={false}
>
{panes.map((pane) => (
<TabPane tab={pane.title} key={pane.key}>
<StatisticBar
setSpinning={setSpinning}
onInfoChange={onInfoChange}
{...state}
{...extraParams}
/>
<div style={{ marginTop: 15 }}>
{checkPaneParams({
...state,
...extraParams,
}) ? (
typeof pane.component == "string" ? (
pane.component
) : (
<pane.component
selectedCluster={selectedCluster}
isAgent={isAgent}
{...state}
handleTimeChange={handleTimeChange}
setSpinning={setSpinning}
{...extraParams}
bucketSize={state.timeInterval}
timeout={state.timeout}
/>
)
) : null}
</div>
</TabPane>
))}
</Tabs>
</>
) : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
}
</Card>
<BackTop />

View File

@ -1,6 +1,6 @@
import * as React from "react";
export default function useAsync(callback, dependencies = []) {
export default function useAsync(callback, dependencies = [], runInInit = true) {
const loadingRef = React.useRef(false);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState();
@ -24,8 +24,10 @@ export default function useAsync(callback, dependencies = []) {
}, dependencies);
React.useEffect(() => {
callbackMemoized();
}, [callbackMemoized]);
if (runInInit) {
callbackMemoized();
}
}, [callbackMemoized, runInInit]);
return { run: callbackMemoized, loading, error, value };
}

View File

@ -5,8 +5,9 @@ const DEFAULT_OPTIONS = {
headers: { "Content-Type": "application/json" },
};
export default function useFetch(url, options = {}, dependencies = []) {
export default function useFetch(url, options = {}, dependencies = [], runInInit = true) {
const { returnRawResponse, noticeable, ...rest } = options
return useAsync(() => {
return request(url, { ...DEFAULT_OPTIONS, ...options });
}, dependencies);
return request(url, { ...DEFAULT_OPTIONS, ...rest }, returnRawResponse, noticeable);
}, dependencies, runInInit);
}

View File

@ -189,13 +189,10 @@ class ClusterMonitor extends PureComponent {
};
componentDidUpdate(prevProps, prevState, snapshot) {
// console.log(this.props.selectedCluster)
// console.log(this.state.clusterID)
if (this.props.selectedCluster.id !== this.state.clusterID) {
if (this.props.selectedCluster?.id !== this.state.clusterID) {
console.log("cluster changed");
this.setState({ clusterID: this.props.selectedCluster.id }, () => {
this.setState({ clusterID: this.props.selectedCluster?.id }, () => {
//TODO 处理 cancel 事件,先把当前还在执行中的请求结束,避免更新完成之后,被晚到的之前的请求给覆盖了。
this.fetchData();
});
@ -225,10 +222,10 @@ class ClusterMonitor extends PureComponent {
},
});
} else if (
this.props.selectedCluster.id !== undefined &&
this.props.selectedCluster.id !== null
this.props.selectedCluster?.id !== undefined &&
this.props.selectedCluster?.id !== null
) {
this.setState({ clusterID: this.props.selectedCluster.id }, () => {});
this.setState({ clusterID: this.props.selectedCluster?.id }, () => {});
} else {
//alert("cluster ID is not set");
return;
@ -537,7 +534,7 @@ class ClusterMonitor extends PureComponent {
})}
>
<ClusterMetric
clusterID={this.props.selectedCluster.id}
clusterID={this.props.selectedCluster?.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
@ -550,7 +547,7 @@ class ClusterMonitor extends PureComponent {
})}
>
<NodeMetric
clusterID={this.props.selectedCluster.id}
clusterID={this.props.selectedCluster?.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
@ -565,7 +562,7 @@ class ClusterMonitor extends PureComponent {
})}
>
<IndexMetric
clusterID={this.props.selectedCluster.id}
clusterID={this.props.selectedCluster?.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
@ -580,7 +577,7 @@ class ClusterMonitor extends PureComponent {
})}
>
<QueueMetric
clusterID={this.props.selectedCluster.id}
clusterID={this.props.selectedCluster?.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
@ -595,7 +592,7 @@ class ClusterMonitor extends PureComponent {
})}
>
<StorageMetric
clusterID={this.props.selectedCluster.id}
clusterID={this.props.selectedCluster?.id}
timezone={timezone}
timeRange={this.state.timeRange}
/>

View File

@ -49,13 +49,13 @@ const Index = (props) => {
}, [state.timeRange]);
const [selectedClusterID] = React.useMemo(() => {
let selectedClusterID = props.selectedCluster.id;
let selectedClusterID = props.selectedCluster?.id;
if (selectedClusterID && selectedClusterID != state.clusterID) {
setState({ ...state, clusterID: selectedClusterID });
}
return [selectedClusterID];
}, [props.selectedCluster.id]);
}, [props.selectedCluster?.id]);
const handleTimeChange = ({ start, end }) => {
const bounds = calculateBounds({

View File

@ -213,7 +213,7 @@ const Discover = (props) => {
const IP = await services.indexPatternService.get(
id,
typ,
props.selectedCluster.id
props.selectedCluster?.id
);
subscriptions.unsubscribe();
props.changeIndexPattern(IP);
@ -247,7 +247,7 @@ const Discover = (props) => {
const IP = await services.indexPatternService.get(
indexPattern.id,
indexPattern.type,
props.selectedCluster.id
props.selectedCluster?.id
);
subscriptions.unsubscribe();
IP.timeFieldName = timeField;
@ -286,7 +286,7 @@ const Discover = (props) => {
async (_payload) => {
if (mode === "insight" && indexPattern.timeFieldName) {
visRef?.current?.refreshMeta(
props.selectedCluster.id,
props.selectedCluster?.id,
indexPattern.title,
indexPattern.timeFieldName,
getFilters()
@ -356,7 +356,7 @@ const Discover = (props) => {
const res = await fetchESRequest(
params,
props.selectedCluster.id,
props.selectedCluster?.id,
{
searchTimeout: localStorage.getItem('search_time_out') || '60s',
ignoreTimeout: true
@ -404,7 +404,7 @@ const Discover = (props) => {
const IP = await services.indexPatternService.get(
record.index_pattern,
"index",
props.selectedCluster.id
props.selectedCluster?.id
);
IP.timeFieldName = record.time_field;
subscriptions.unsubscribe();
@ -702,7 +702,7 @@ const Discover = (props) => {
async ({ _index, _id, _type, _source, is_new }) => {
const { http } = getContext();
const res = await http.put(
`/elasticsearch/${props.selectedCluster.id}/doc/${_index}/${_id}`,
`/elasticsearch/${props.selectedCluster?.id}/doc/${_index}/${_id}`,
{
prependBasePath: false,
query: {
@ -729,7 +729,7 @@ const Discover = (props) => {
async ({ _index, _id, _type }) => {
const { http } = getContext();
const res = await http.delete(
`/elasticsearch/${props.selectedCluster.id}/doc/${_index}/${_id}`,
`/elasticsearch/${props.selectedCluster?.id}/doc/${_index}/${_id}`,
{
prependBasePath: false,
query: {
@ -850,7 +850,7 @@ const Discover = (props) => {
}
}
const res = await getDataTips({
clusterId: props.selectedCluster.id,
clusterId: props.selectedCluster?.id,
indexPattern: indexPattern.title,
timeField: indexPattern.timeFieldName,
filter,
@ -980,7 +980,7 @@ const Discover = (props) => {
}
}
const res = await fetchESRequest(params, props.selectedCluster.id);
const res = await fetchESRequest(params, props.selectedCluster?.id);
if (afterFuc) {
const buckets = sampleRecords === 'all'
? res?.aggregations?.['top5']?.buckets
@ -994,11 +994,11 @@ const Discover = (props) => {
useEffect(() => {
if (indexPattern?.type === "view") {
fetchViewDefaultLayout(props.selectedCluster.id, indexPattern?.id);
fetchViewDefaultLayout(props.selectedCluster?.id, indexPattern?.id);
} else {
setViewLayout();
}
}, [indexPattern, props.selectedCluster.id]);
}, [indexPattern, props.selectedCluster?.id]);
useEffect(() => {
setMode(viewLayout ? "layout" : "table");
@ -1091,7 +1091,7 @@ const Discover = (props) => {
ref={insightBarRef}
loading={resultState === "loading"}
queries={{
clusterId: props.selectedCluster.id,
clusterId: props.selectedCluster?.id,
indexPattern: indexPattern,
query: {
language: "kuery",
@ -1194,7 +1194,7 @@ const Discover = (props) => {
<Visualization
ref={visRef}
indexPattern={indexPattern.title}
clusterId={props.selectedCluster.id}
clusterId={props.selectedCluster?.id}
timeField={indexPattern.timeFieldName}
getFilters={getSearchFilters}
getBucketSize={getBucketSize}
@ -1205,7 +1205,7 @@ const Discover = (props) => {
) : mode === "layout" ? (
<Layout
ref={layoutRef}
clusterId={props.selectedCluster.id}
clusterId={props.selectedCluster?.id}
indexPattern={indexPattern}
timeRange={timefilter?.getTime()}
query={getSearchFilters()}
@ -1354,7 +1354,7 @@ const Discover = (props) => {
};
const DiscoverUI = (props) => {
if (!props.selectedCluster.id) {
if (!props.selectedCluster?.id) {
return null;
}
const [loading, setLoading] = useState(false);
@ -1369,7 +1369,7 @@ const DiscoverUI = (props) => {
useMemo(() => {
const { http } = getContext();
http.getServerBasePath = () => {
return `${ESPrefix}/` + props.selectedCluster.id;
return `${ESPrefix}/` + props.selectedCluster?.id;
};
}, [props.selectedCluster]);
@ -1432,7 +1432,7 @@ const DiscoverUI = (props) => {
defaultIP = await services.indexPatternService.get(
index,
"index",
props.selectedCluster.id
props.selectedCluster?.id
);
} else {
if (ils.length > 0) {
@ -1455,7 +1455,7 @@ const DiscoverUI = (props) => {
defaultIP = await services.indexPatternService.get(
targetIndex,
"index",
props.selectedCluster.id
props.selectedCluster?.id
);
setIndex(targetIndex);
}
@ -1569,8 +1569,8 @@ const DiscoverUI = (props) => {
};
const DiscoverContainer = (props) => {
if (props.selectedCluster.id == "") {
return null;
if (!props.selectedCluster?.id) {
return <Card ><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></Card>;
}
return (
<QueryParamProvider ReactRouterRoute={Route}>

View File

@ -20,7 +20,7 @@ import { getAuthority, hasAuthority } from "@/utils/authority";
import EditLayout from "./View/EditLayout";
const IndexPatterns = (props) => {
if (!props.selectedCluster.id) {
if (!props.selectedCluster?.id) {
return null;
}
const history = useMemo(() => {
@ -30,7 +30,7 @@ const IndexPatterns = (props) => {
const createComponentKey = useMemo(() => {
const { http, uiSettings } = useGlobalContext();
http.getServerBasePath = () => {
return `${ESPrefix}/` + props.selectedCluster.id;
return `${ESPrefix}/` + props.selectedCluster?.id;
};
return "CreateIndexPatternWizard_" + Math.random();
}, [props.selectedCluster]);

View File

@ -7,6 +7,7 @@ import { connect } from "dva";
import { formatMessage } from "umi/locale";
import Monitor from "@/components/Overview/Monitor";
import StatisticBar from "./statistic_bar";
import { Empty } from "antd";
const panes = [
{ title: "Overview", component: Overview, key: "overview" },
@ -31,10 +32,10 @@ const Page = (props) => {
formatState={(state) => {
let clusterID = props.match.params?.cluster_id;
if (
props.selectedCluster.id &&
props.selectedCluster.id !== clusterID
props.selectedCluster?.id &&
props.selectedCluster?.id !== clusterID
) {
clusterID = props.selectedCluster.id;
clusterID = props.selectedCluster?.id;
}
return {
...state,
@ -62,9 +63,9 @@ const Page = (props) => {
clusterMonitored,
clusterName: selectedCluster?.name,
clusterID:
props.selectedCluster.id &&
props.selectedCluster.id !== props.match.params?.cluster_id
? props.selectedCluster.id
props.selectedCluster?.id &&
props.selectedCluster?.id !== props.match.params?.cluster_id
? props.selectedCluster?.id
: props.match.params?.cluster_id,
}}
panes={panes}

View File

@ -25,6 +25,9 @@ const StatisticBar = ({
clusterMonitored,
onInfoChange
}) => {
if (!clusterID) return null
const { loading, error, value } = useFetch(
`${ESPrefix}/${clusterID}/metrics`,
{},

View File

@ -4,6 +4,7 @@ import { formatMessage } from "umi/locale";
import useFetch from "@/lib/hooks/use_fetch";
import { formatESSearchResult } from "@/lib/elasticsearch/util";
import { MANUAL_VALUE } from "./steps";
import { hasAuthority } from "@/utils/authority";
export default (props) => {
const {
@ -63,7 +64,8 @@ export default (props) => {
size: 1000,
},
},
[]
[],
false
);
const onCredentialChange = (value) => {
@ -82,6 +84,12 @@ export default (props) => {
setIsManual(props.isManual);
}, [props.isManual]);
useEffect(() => {
if (hasAuthority('system.credential:all') || hasAuthority('system.credential:read')) {
run()
}
}, [])
if (!needAuth) {
return null;
}

View File

@ -4,6 +4,7 @@ import { formatMessage } from "umi/locale";
import useFetch from "@/lib/hooks/use_fetch";
import { formatESSearchResult } from "@/lib/elasticsearch/util";
import { MANUAL_VALUE } from "./steps";
import { hasAuthority } from "@/utils/authority";
export default (props) => {
const {
@ -27,7 +28,8 @@ export default (props) => {
size: 1000,
},
},
[]
[],
false
);
const onCredentialChange = (value) => {
@ -46,6 +48,12 @@ export default (props) => {
setIsManual(props.isManual);
}, [props.isManual]);
useEffect(() => {
if (hasAuthority('system.credential:all') || hasAuthority('system.credential:read')) {
run()
}
}, [])
if (!needAuth) {
return null;
}

View File

@ -3,6 +3,7 @@ import { Button, Divider, Form, Input, Select } from "antd";
import { formatMessage } from "umi/locale";
import useFetch from "@/lib/hooks/use_fetch";
import { formatESSearchResult } from "@/lib/elasticsearch/util";
import { hasAuthority } from "@/utils/authority";
const MANUAL_VALUE = 'manual'
@ -20,7 +21,8 @@ export default (props) => {
size: 1000,
},
},
[]
[],
false
);
const onCredentialChange = (value) => {
@ -39,6 +41,12 @@ export default (props) => {
setIsManual(initialValue.credential_id === MANUAL_VALUE)
}, [initialValue.credential_id])
useEffect(() => {
if (hasAuthority('system.credential:all') || hasAuthority('system.credential:read')) {
run()
}
}, [])
return (
<>
<Form.Item