Procházet zdrojové kódy

chore: add prev, next logs

Soham Parekh před 3 roky
rodič
revize
6a8723e3dc

+ 43 - 10
dashboard/src/main/home/cluster-dashboard/expanded-chart/logs-section/LogsSection.tsx

@@ -12,7 +12,7 @@ import RadioFilter from "components/RadioFilter";
 import filterOutline from "assets/filter-outline.svg";
 import { Context } from "shared/Context";
 import api from "shared/api";
-import { useLogs } from "./useAgentLogs";
+import { Direction, useLogs } from "./useAgentLogs";
 import Anser from "anser";
 import DateTimePicker from "components/date-time-picker/DateTimePicker";
 
@@ -44,7 +44,7 @@ const LogsSection: React.FC<Props> = ({
     podFilter,
     currentChart.namespace,
     enteredSearchText,
-    selectedDate,
+    selectedDate
   );
 
   useEffect(() => {
@@ -68,8 +68,8 @@ const LogsSection: React.FC<Props> = ({
   useEffect(() => {
     if (scrollToBottomRef.current && scrollToBottomEnabled) {
       scrollToBottomRef.current.scrollIntoView({
-        behavior: 'smooth',
-        block: 'end',
+        behavior: "smooth",
+        block: "end",
       });
     }
   }, [logs, scrollToBottomRef, scrollToBottomEnabled]);
@@ -78,7 +78,7 @@ const LogsSection: React.FC<Props> = ({
     return logs?.map((log, i) => {
       return (
         <Log key={[log.lineNumber, i].join(".")}>
-          <span className="line-number">{log.lineNumber}</span>
+          <span className="line-number">{log.lineNumber}.</span>
           {log.line.map((ansi, j) => {
             if (ansi.clearLine) {
               return null;
@@ -157,6 +157,14 @@ const LogsSection: React.FC<Props> = ({
           </Flex>
         </FlexRow>
         <StyledLogsSection isFullscreen={isFullscreen}>
+          <LoadMoreButton
+            active={selectedDate && logs.length !== 0}
+            role="button"
+            onClick={() => moveCursor(Direction.backward)}
+            ref={scrollToBottomRef}
+          >
+            Load Previous
+          </LoadMoreButton>
           {renderLogs()}
           {/* <Message>
             
@@ -166,7 +174,14 @@ const LogsSection: React.FC<Props> = ({
               Refresh
             </Highlight>
           </Message> */}
-          <div ref={scrollToBottomRef} />
+          <LoadMoreButton
+            active={selectedDate && logs.length !== 0}
+            role="button"
+            onClick={() => moveCursor(Direction.forward)}
+            ref={scrollToBottomRef}
+          >
+            Load more
+          </LoadMoreButton>
         </StyledLogsSection>
       </>
     );
@@ -394,8 +409,7 @@ const StyledLogsSection = styled.div<{ isFullscreen: boolean }>`
   border-radius: ${(props) => (props.isFullscreen ? "" : "8px")};
   border: ${(props) => (props.isFullscreen ? "" : "1px solid #ffffff33")};
   border-top: ${(props) => (props.isFullscreen ? "1px solid #ffffff33" : "")};
-  padding: 18px 22px;
-  background: #121318;
+  background: #101420;
   animation: floatIn 0.3s;
   animation-timing-function: ease-out;
   animation-fill-mode: forwards;
@@ -416,11 +430,19 @@ const StyledLogsSection = styled.div<{ isFullscreen: boolean }>`
 const Log = styled.div`
   font-family: monospace;
   user-select: text;
+  display: flex;
+  align-items: flex-end;
+  gap: 8px;
+  & > * {
+    padding-block: 5px;
+  }
   & > .line-number {
+    height: 100%;
+    background: #202538;
     display: inline-block;
     text-align: right;
-    min-width: 35px;
-    margin-right: 8px;
+    min-width: 45px;
+    padding-inline-end: 5px;
     opacity: 0.3;
     font-family: monospace;
   }
@@ -436,3 +458,14 @@ const LogSpan = styled.span`
   background-color: ${(props: { ansi: Anser.AnserJsonEntry }) =>
     props.ansi?.bg ? `rgb(${props.ansi?.bg})` : "transparent"};
 `;
+
+const LoadMoreButton = styled.div<{ active: boolean }>`
+  width: 100%;
+  display: ${(props) => (props.active ? "flex" : "none")};
+  justify-content: center;
+  align-items: center;
+  padding-block: 10px;
+  background: #1f2023;
+  cursor: pointer;
+  font-family: monospace;
+`;

+ 82 - 59
dashboard/src/main/home/cluster-dashboard/expanded-chart/logs-section/useAgentLogs.ts

@@ -46,14 +46,10 @@ export const useLogs = (
   // if setDate is set, results are not live
   setDate?: Date
 ) => {
-  const d = dayjs().subtract(14, "days");
-
   const isLive = !setDate;
   const logsBufferRef = useRef<Log[]>([]);
   const { currentCluster, currentProject } = useContext(Context);
   const [logs, setLogs] = useState<Log[]>([]);
-  const [startDate, setStartDate] = useState<dayjs.Dayjs>(d);
-  const [endDate, setEndDate] = useState<dayjs.Dayjs>(dayjs(setDate));
 
   // if we are live:
   // - start date is initially set to 2 weeks ago
@@ -73,7 +69,10 @@ export const useLogs = (
     closeAllWebsockets,
   } = useWebsockets();
 
-  const updateLogs = (newLogs: Log[]) => {
+  const updateLogs = (
+    newLogs: Log[],
+    direction: Direction = Direction.forward
+  ) => {
     // Nothing to update here
     if (!newLogs.length) {
       return;
@@ -81,19 +80,43 @@ export const useLogs = (
 
     setLogs((logs) => {
       let updatedLogs = _.cloneDeep(logs);
-      const lastLineNumber = updatedLogs.at(-1)?.lineNumber ?? 0;
 
-      updatedLogs.push(
-        ...newLogs.map((log) => ({
-          ...log,
-          lineNumber: lastLineNumber + log.lineNumber,
-        }))
-      );
+      /**
+       * If direction = Direction.forward, we want to append the new logs
+       * at the end of the current logs, else we want to append before the current logs
+       *
+       */
+      if (direction === Direction.forward) {
+        const lastLineNumber = updatedLogs.at(-1)?.lineNumber ?? 0;
+
+        updatedLogs.push(
+          ...newLogs.map((log) => ({
+            ...log,
+            lineNumber: lastLineNumber + log.lineNumber,
+          }))
+        );
+
+        // For direction = Direction.forward, remove logs from the front
+        if (updatedLogs.length > MAX_LOGS) {
+          const logsToBeRemoved =
+            newLogs.length < MAX_BUFFER_LOGS ? newLogs.length : MAX_BUFFER_LOGS;
+          updatedLogs = updatedLogs.slice(logsToBeRemoved);
+        }
+      } else {
+        updatedLogs = newLogs.concat(
+          updatedLogs.map((log) => ({
+            ...log,
+            lineNumber: log.lineNumber + newLogs.length,
+          }))
+        );
+
+        // For direction = Direction.backward, remove logs from the back
+        if (updatedLogs.length > MAX_LOGS) {
+          const logsToBeRemoved =
+            newLogs.length < MAX_BUFFER_LOGS ? newLogs.length : MAX_BUFFER_LOGS;
 
-      if (updatedLogs.length > MAX_LOGS) {
-        const logsToBeRemoved =
-          newLogs.length < MAX_BUFFER_LOGS ? newLogs.length : MAX_BUFFER_LOGS;
-        updatedLogs = updatedLogs.slice(logsToBeRemoved);
+          updatedLogs = updatedLogs.slice(0, logsToBeRemoved);
+        }
       }
 
       return updatedLogs;
@@ -142,13 +165,8 @@ export const useLogs = (
     openWebsocket(websocketKey);
   };
 
-  const queryLogs = (
-    startDate: Date,
-    endDate: Date,
-    direction: Direction,
-    cb?: () => void
-  ) => {
-    api
+  const queryLogs = (startDate: Date, endDate: Date, direction: Direction) => {
+    return api
       .getLogs(
         "<token>",
         {
@@ -170,55 +188,53 @@ export const useLogs = (
           res.data.logs?.filter(Boolean).map((logLine: any) => logLine.line)
         );
 
-        pushLogs(
-          direction === Direction.backward ? newLogs : newLogs.reverse()
-        );
-        cb && cb();
+        return newLogs;
       });
   };
 
-  const refresh = () => {
+  const refresh = async () => {
     if (!currentPod) {
       return;
     }
 
+    setLogs([]);
     flushLogsBuffer(true);
     const websocketKey = `${currentPod}-${namespace}-websocket`;
-    const newEndDate = dayjs(setDate);
-
-    queryLogs(
-      startDate.toDate(),
-      newEndDate.toDate(),
-      Direction.backward,
-      () => {
-        setEndDate(newEndDate);
-        closeWebsocket(websocketKey);
-
-        if (isLive) {
-          setupWebsocket(websocketKey);
-          return () => {
-            closeWebsocket(websocketKey);
-          };
-        }
-      }
+    const endDate = dayjs(setDate);
+    const twoWeeksAgo = endDate.subtract(14, "days");
+
+    const initialLogs = await queryLogs(
+      twoWeeksAgo.toDate(),
+      endDate.toDate(),
+      Direction.forward
     );
+
+    updateLogs(initialLogs);
+
+    closeWebsocket(websocketKey);
+
+    if (isLive) {
+      setupWebsocket(websocketKey);
+    }
+
+    return () => isLive && closeWebsocket(websocketKey);
   };
 
-  const moveCursor = (direction: number) => {
-    if (direction < 0) {
+  const moveCursor = async (direction: Direction) => {
+    if (direction === Direction.backward) {
       // we query by setting the endDate equal to the previous startDate, and setting the direction
       // to "backward"
-      const twoWeeksAgo = dayjs().subtract(14, "days");
+      const refDate = dayjs(logs[0]?.timestamp);
+      const twoWeeksAgo = refDate.subtract(14, "days");
 
-      queryLogs(
+      const newLogs = await queryLogs(
         twoWeeksAgo.toDate(),
-        startDate.toDate(),
-        Direction.backward,
-        () => {
-          setEndDate(startDate);
-          setStartDate(twoWeeksAgo);
-        }
+        refDate.toDate(),
+        Direction.backward
       );
+
+      // TODO For backwards query, we want to add to the front of the current logs rather than append at the end
+      updateLogs(newLogs);
     } else {
       if (isLive) {
         return;
@@ -226,15 +242,22 @@ export const useLogs = (
 
       // we query by setting the startDate equal to the previous endDate, setting the endDate equal to the
       // current time, and setting the direction to "forward"
+      const refDate = logs.length
+        ? dayjs(logs.at(-1).timestamp)
+        : dayjs(setDate);
       const currDate = dayjs();
-      queryLogs(endDate.toDate(), currDate.toDate(), Direction.forward, () => {
-        setStartDate(endDate);
-        setEndDate(currDate);
-      });
+      const newLogs = await queryLogs(
+        refDate.toDate(),
+        currDate.toDate(),
+        Direction.forward
+      );
+
+      updateLogs(newLogs);
     }
   };
 
   useEffect(() => {
+    setLogs([]);
     flushLogsBuffer(true);
   }, []);