chore: watch api
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
.logs-viewer-wrap-w2 {
|
||||
.wrap {
|
||||
padding: 5px 0 5px 10px;
|
||||
overflow: auto;
|
||||
background-color: var(--color-logs-bg);
|
||||
border-radius: var(--border-radius-small);
|
||||
|
||||
.content {
|
||||
word-wrap: break-word;
|
||||
|
||||
&.line-break {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
color: var(--color-logs-text);
|
||||
font-size: var(--font-size-small);
|
||||
line-height: 22px;
|
||||
white-space: pre-wrap;
|
||||
background-color: var(--color-logs-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import useSetChunkRequest from '@/hooks/use-chunk-request';
|
||||
import Convert from 'ansi-to-html';
|
||||
import classNames from 'classnames';
|
||||
import hasAnsi from 'has-ansi';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import './index.less';
|
||||
|
||||
interface LogsViewerProps {
|
||||
height: number;
|
||||
content: string;
|
||||
url: string;
|
||||
params?: object;
|
||||
}
|
||||
const LogsViewer: React.FC<LogsViewerProps> = (props) => {
|
||||
const { height, content, url } = props;
|
||||
const [nowrap, setNowrap] = useState(false);
|
||||
const [logsContent, setLogsContent] = useState(content);
|
||||
const { setChunkRequest } = useSetChunkRequest();
|
||||
const chunkRequedtRef = useRef<any>(null);
|
||||
|
||||
const convert = new Convert();
|
||||
|
||||
const updateContent = (newVal: string) => {
|
||||
if (hasAnsi(newVal)) {
|
||||
const htmlStr = `${convert.toHtml(newVal)}`;
|
||||
setLogsContent(htmlStr);
|
||||
} else {
|
||||
setLogsContent(newVal);
|
||||
}
|
||||
};
|
||||
|
||||
const createChunkConnection = async () => {
|
||||
chunkRequedtRef.current?.current?.cancel?.();
|
||||
chunkRequedtRef.current = setChunkRequest({
|
||||
url,
|
||||
params: {
|
||||
...props.params,
|
||||
watch: true
|
||||
},
|
||||
contentType: 'text',
|
||||
handler: updateContent
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
createChunkConnection();
|
||||
return () => {
|
||||
chunkRequedtRef.current?.current?.cancel?.();
|
||||
};
|
||||
}, [url, props.params]);
|
||||
|
||||
return (
|
||||
<div className="logs-viewer-wrap-w2">
|
||||
<div className="wrap" style={{ height: height }}>
|
||||
<div className={classNames('content', { 'line-break': nowrap })}>
|
||||
<div className="text">{logsContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogsViewer;
|
||||
@@ -1,9 +1,14 @@
|
||||
import { Progress } from 'antd';
|
||||
import { Progress, Tooltip } from 'antd';
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
const RenderProgress = memo(
|
||||
(props: { percent: number; steps?: number; download?: boolean }) => {
|
||||
const { percent, steps = 5, download } = props;
|
||||
(props: {
|
||||
percent: number;
|
||||
steps?: number;
|
||||
download?: boolean;
|
||||
label?: React.ReactNode;
|
||||
}) => {
|
||||
const { percent, steps = 5, download, label } = props;
|
||||
|
||||
const strokeColor = useMemo(() => {
|
||||
if (download) {
|
||||
@@ -19,16 +24,48 @@ const RenderProgress = memo(
|
||||
}, [percent]);
|
||||
|
||||
return (
|
||||
<Progress
|
||||
steps={steps}
|
||||
format={() => {
|
||||
return (
|
||||
<span style={{ color: 'var(--ant-color-text)' }}>{percent}%</span>
|
||||
);
|
||||
}}
|
||||
percent={percent}
|
||||
strokeColor={strokeColor}
|
||||
/>
|
||||
<>
|
||||
{label ? (
|
||||
<Tooltip title={label}>
|
||||
<Progress
|
||||
percentPosition={{ align: 'center', type: 'inner' }}
|
||||
size={[undefined, 12]}
|
||||
format={() => {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
color: 'var(--ant-color-text)'
|
||||
}}
|
||||
>
|
||||
{percent}%
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
percent={percent}
|
||||
strokeColor={strokeColor}
|
||||
></Progress>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Progress
|
||||
type="line"
|
||||
percentPosition={{ align: 'center', type: 'inner' }}
|
||||
size={[undefined, 12]}
|
||||
format={() => {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
color: 'var(--ant-color-text)'
|
||||
}}
|
||||
>
|
||||
{percent}%
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
percent={percent}
|
||||
strokeColor={strokeColor}
|
||||
></Progress>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@wrapheight: 54px;
|
||||
@inputheight: 32px;
|
||||
@borderRadius: 8px;
|
||||
@input-inner-padding: 12px;
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -115,7 +116,7 @@
|
||||
:global(.ant-select-selector) {
|
||||
border: none !important;
|
||||
padding-block: 5px;
|
||||
padding-inline: 12px;
|
||||
padding-inline: @input-inner-padding !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -167,7 +168,7 @@
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding-block: 5px;
|
||||
padding-inline: 12px;
|
||||
padding-inline: @input-inner-padding;
|
||||
height: @inputheight !important;
|
||||
|
||||
&.seal-textarea {
|
||||
@@ -182,7 +183,7 @@
|
||||
:global(input.ant-input-number-input) {
|
||||
height: @inputheight !important;
|
||||
padding-block: 5px;
|
||||
padding-inline: 12px;
|
||||
padding-inline: @input-inner-padding;
|
||||
}
|
||||
|
||||
:global(.ant-input-group) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
margin-bottom: 20px;
|
||||
border-radius: var(--ant-table-header-border-radius);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--box-shadow-base);
|
||||
}
|
||||
|
||||
.expanded-row {
|
||||
|
||||
Reference in New Issue
Block a user