Skip to content

Commit

Permalink
feat(web): optimize app log stream (#1811)
Browse files Browse the repository at this point in the history
* feat(web): add logs pause button

* change bottom button & add scroll up event

* add bg blur
  • Loading branch information
newfish-cmyk authored Jan 23, 2024
1 parent d490979 commit 59da485
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 16 deletions.
3 changes: 2 additions & 1 deletion web/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,8 @@
"Logs": {
"PodLogs": "App Instance Logs",
"Export": "Export",
"logs": "Logs"
"logs": "Logs",
"ScrollToBottom": "Scroll to bottom"
},
"KeyCannotBeEmpty": "Key can't be empty",
"ValueCannotBeEmpty": "Value can't be empty",
Expand Down
3 changes: 2 additions & 1 deletion web/public/locales/zh-CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,8 @@
"Logs": {
"PodLogs": "应用实例日志",
"Export": "导出",
"logs": "日志"
"logs": "日志",
"ScrollToBottom": "滚动到底部"
},
"KeyCannotBeEmpty": "Key 不能为空",
"ValueCannotBeEmpty": "Value 不能为空",
Expand Down
3 changes: 2 additions & 1 deletion web/public/locales/zh/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,8 @@
"Logs": {
"PodLogs": "应用实例日志",
"Export": "导出",
"logs": "日志"
"logs": "日志",
"ScrollToBottom": "滚动到底部"
},
"KeyCannotBeEmpty": "Key 不能为空",
"ValueCannotBeEmpty": "Value 不能为空",
Expand Down
2 changes: 1 addition & 1 deletion web/src/chakraThemeDark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const Button = defineStyleConfig({
text: {
color: "primary.500",
_hover: {
bg: "primary.100",
bg: "primary.900",
},
},

Expand Down
31 changes: 31 additions & 0 deletions web/src/components/CommonIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -741,3 +741,34 @@ export const CommonSettingIcon = createIcon({
viewBox: "0 0 16 16",
d: "M1.5 4.54688C1.5 4.38526 1.5642 4.23026 1.67848 4.11598C1.79276 4.0017 1.94776 3.9375 2.10938 3.9375H13.8906C14.0522 3.9375 14.2072 4.0017 14.3215 4.11598C14.4358 4.23026 14.5 4.38526 14.5 4.54688C14.5 4.70849 14.4358 4.86349 14.3215 4.97777C14.2072 5.09205 14.0522 5.15625 13.8906 5.15625H2.10938C1.94776 5.15625 1.79276 5.09205 1.67848 4.97777C1.5642 4.86349 1.5 4.70849 1.5 4.54688ZM1.5 8C1.5 7.83838 1.5642 7.68339 1.67848 7.56911C1.79276 7.45483 1.94776 7.39062 2.10938 7.39062H13.8906C14.0522 7.39062 14.2072 7.45483 14.3215 7.56911C14.4358 7.68339 14.5 7.83838 14.5 8C14.5 8.16162 14.4358 8.31661 14.3215 8.43089C14.2072 8.54517 14.0522 8.60938 13.8906 8.60938H2.10938C1.94776 8.60938 1.79276 8.54517 1.67848 8.43089C1.5642 8.31661 1.5 8.16162 1.5 8ZM2.10938 10.8438C1.94776 10.8438 1.79276 10.908 1.67848 11.0222C1.5642 11.1365 1.5 11.2915 1.5 11.4531C1.5 11.6147 1.5642 11.7697 1.67848 11.884C1.79276 11.9983 1.94776 12.0625 2.10938 12.0625H9.82812C9.98974 12.0625 10.1447 11.9983 10.259 11.884C10.3733 11.7697 10.4375 11.6147 10.4375 11.4531C10.4375 11.2915 10.3733 11.1365 10.259 11.0222C10.1447 10.908 9.98974 10.8438 9.82812 10.8438H2.10938Z",
});

export const PauseIcon = createIcon({
displayName: "PauseIcon",
viewBox: "0 0 1024 1024",
d: "M304 176h80v672h-80zM712 176h-64c-4.4 0-8 3.6-8 8v656c0 4.4 3.6 8 8 8h64c4.4 0 8-3.6 8-8V184c0-4.4-3.6-8-8-8z",
});

export const ContinueIcon = createIcon({
displayName: "ContinueIcon",
viewBox: "0 0 1024 1024",
d: "M104 0v1024l816-512z"
});

export const DownIcon = (props: any) => {
return (
<svg
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width={props.size}
height={props.size}
>
<path d="M486.4 537.6C492.8 544 505.6 544 512 544s19.2 0 25.6-6.4l224-224c12.8-12.8 12.8-32 0-44.8s-32-12.8-44.8 0L512 467.2 313.6 262.4C300.8 256 275.2 256 262.4 262.4S256 300.8 262.4 313.6L486.4 537.6z"
fill={props.color}
></path>
<path d="M710.4 486.4 512 691.2 313.6 486.4c-12.8-12.8-32-12.8-44.8 0S256 524.8 262.4 537.6l224 224C492.8 768 505.6 768 512 768s19.2 0 25.6-6.4l224-224c12.8-12.8 12.8-32 0-44.8S723.2 480 710.4 486.4z"
fill={props.color}
></path>

</svg>
);
};
82 changes: 70 additions & 12 deletions web/src/pages/app/mods/StatusBar/LogsModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from "react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import {
Button,
Expand All @@ -12,6 +12,7 @@ import {
ModalOverlay,
Select,
Spinner,
useColorMode,
useDisclosure,
} from "@chakra-ui/react";
import { LogViewer, LogViewerSearch } from "@patternfly/react-log-viewer";
Expand All @@ -25,6 +26,9 @@ import "./index.scss";
import { PodControllerGetContainerNameList, PodControllerGetPodNameList } from "@/apis/v1/apps";
import useCustomSettingStore from "@/pages/customSetting";
import useGlobalStore from "@/pages/globalStore";
import { DownIcon, RefreshIcon } from "@/components/CommonIcon";
import clsx from "clsx";
import { debounce } from "lodash";

export default function LogsModal(props: { children: React.ReactElement }) {
const { children } = props;
Expand All @@ -38,6 +42,34 @@ export default function LogsModal(props: { children: React.ReactElement }) {
const [podName, setPodName] = useState("");
const [containerName, setContainerName] = useState("");
const [isLoading, setIsLoading] = useState(true);
const [rowNumber, setRowNumber] = useState(0);
const [isPaused, setIsPaused] = useState(false);
const [pausedRowNumber, setPausedRowNumber] = useState(0);

const [renderLogs, setRenderLogs] = useState("");
const [refresh, setRefresh] = useState(true);

const darkMode = useColorMode().colorMode === "dark";

useEffect(() => {
const resizeHandler = debounce(() => {
if (!isPaused) {
setRefresh((pre) => !pre);
}
}, 200)

window.addEventListener("resize", resizeHandler);

return () => {
window.removeEventListener("resize", resizeHandler);
};
}, [isPaused])

useEffect(() => {
if (!isPaused) {
setRenderLogs(logs.trim());
}
}, [isPaused, logs]);

const { data: podData } = useQuery(
["GetPodQuery"],
Expand Down Expand Up @@ -90,10 +122,11 @@ export default function LogsModal(props: { children: React.ReactElement }) {
)
.join("\n");

setRowNumber((pre) => pre + logs.length);
setLogs((pre) => pre + logStr + "\n");
},
}).catch((e) => {
if (e.includes("BodyStreamBuffer was aborte")) {
if (e.includes("BodyStreamBuffer was aborted")) {
return;
}
throw e;
Expand All @@ -109,7 +142,7 @@ export default function LogsModal(props: { children: React.ReactElement }) {
return () => {
controller?.abort();
};
}, [podName, isOpen, fetchLogs]);
}, [podName, containerName, isOpen, refresh]);

return (
<>
Expand Down Expand Up @@ -167,11 +200,12 @@ export default function LogsModal(props: { children: React.ReactElement }) {
)}
<span>
<Button
variant={"outline"}
variant={"text"}
leftIcon={<RefreshIcon boxSize={5} />}
px={2}
onClick={() => {
setIsLoading(true);
setLogs("");
fetchLogs();
setRefresh((pre) => !pre);
setIsPaused(false);
}}
>
{t("Refresh")}
Expand All @@ -187,14 +221,25 @@ export default function LogsModal(props: { children: React.ReactElement }) {
) : (
<div
id="log-viewer-container"
className="text-sm flex flex-col overflow-y-auto px-2 font-mono"
style={{ height: "98%", fontSize: settingStore.commonSettings.fontSize - 1 }}
className="text-sm flex flex-col px-2 font-mono h-full"
style={{ fontSize: settingStore.commonSettings.fontSize - 1 }}
onWheel={(e) => {
if (e.deltaY < 0 && !isPaused) {
setIsPaused(true);
setPausedRowNumber(rowNumber);
}
}}
>
<LogViewer
data={logs.replace(/^\s*\n/, "")}
data={renderLogs}
hasLineNumbers={false}
scrollToRow={100000}
height={"100%"}
scrollToRow={isPaused ? pausedRowNumber : rowNumber + 1}
height={"98%"}
onScroll={(e) => {
if (e.scrollOffsetToBottom <= 0) {
setIsPaused(false);
}
}}
toolbar={
<div className="absolute right-24 top-4">
<LogViewerSearch
Expand All @@ -205,6 +250,19 @@ export default function LogsModal(props: { children: React.ReactElement }) {
</div>
}
/>
<div className="w-[95%] absolute bottom-1">
{isPaused && (
<HStack
onClick={() => { setIsPaused(false) }}
className={clsx("w-full flex justify-center items-center cursor-pointer",
darkMode ? "bg-[#212630]" : "bg-white"
)}
>
<DownIcon color={'#33BAB1'} size={24} />
<span className="text-primary-500 font-medium text-lg">{t("Logs.ScrollToBottom")}</span>
</HStack>
)}
</div>
</div>
)}
</ModalBody>
Expand Down

0 comments on commit 59da485

Please sign in to comment.