diff --git a/dashboard/client/src/common/CodeDialogButton/CodeDialogButton.tsx b/dashboard/client/src/common/CodeDialogButton/CodeDialogButton.tsx
index 711616fa1092..0aea9c9f4d61 100644
--- a/dashboard/client/src/common/CodeDialogButton/CodeDialogButton.tsx
+++ b/dashboard/client/src/common/CodeDialogButton/CodeDialogButton.tsx
@@ -5,9 +5,11 @@ import {
makeStyles,
Typography,
} from "@material-ui/core";
+import classNames from "classnames";
import yaml from "js-yaml";
import React, { useState } from "react";
import DialogWithTitle from "../DialogWithTitle";
+import { ClassNameProps } from "../props";
const useStyles = makeStyles((theme) =>
createStyles({
@@ -15,7 +17,8 @@ const useStyles = makeStyles((theme) =>
whiteSpace: "pre",
fontFamily: "SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace",
padding: theme.spacing(2),
- // borderRadius: theme.spacing(1),
+ overflow: "scroll",
+ maxHeight: 600,
},
}),
);
@@ -92,13 +95,14 @@ const useCodeDialogButtonWithPreviewStyles = makeStyles((theme) =>
}),
);
-type CodeDialogButtonWithPreviewProps = CodeDialogButtonProps;
+type CodeDialogButtonWithPreviewProps = CodeDialogButtonProps & ClassNameProps;
/**
* Similar to CodeDialogButton but also shows a snippet of the expanded text next to the button.
*/
export const CodeDialogButtonWithPreview = ({
code,
buttonText,
+ className,
...props
}: CodeDialogButtonWithPreviewProps) => {
const classes = useCodeDialogButtonWithPreviewStyles();
@@ -109,7 +113,7 @@ export const CodeDialogButtonWithPreview = ({
const buttonTextToPass = buttonText ?? "Expand";
return (
-
+
{codeText}
+ createStyles({
+ contentContainer: {
+ padding: theme.spacing(2),
+ height: "100%",
+ },
+ }),
+);
+
+type SectionProps = {
+ title?: string;
+} & ClassNameProps &
+ BoxProps;
+
+export const Section = ({
+ title,
+ children,
+ className,
+ ...props
+}: PropsWithChildren) => {
+ const classes = useStyles();
+
+ return (
+
+ {title && (
+
+ {title}
+
+ )}
+
+ {children}
+
+
+ );
+};
diff --git a/dashboard/client/src/components/MetadataSection/MetadataSection.tsx b/dashboard/client/src/components/MetadataSection/MetadataSection.tsx
index eb2c8af78b50..91c73dc7723d 100644
--- a/dashboard/client/src/components/MetadataSection/MetadataSection.tsx
+++ b/dashboard/client/src/components/MetadataSection/MetadataSection.tsx
@@ -4,7 +4,6 @@ import {
IconButton,
Link,
makeStyles,
- Paper,
Tooltip,
Typography,
} from "@material-ui/core";
@@ -12,6 +11,7 @@ import copy from "copy-to-clipboard";
import React, { useState } from "react";
import { RiFileCopyLine } from "react-icons/ri";
import { Link as RouterLink } from "react-router-dom";
+import { Section } from "../../common/Section";
import { HelpInfo } from "../Tooltip";
export type StringOnlyMetadataContent = {
@@ -55,7 +55,6 @@ const useStyles = makeStyles((theme) =>
gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
rowGap: theme.spacing(1),
columnGap: theme.spacing(4),
- padding: theme.spacing(2),
},
label: {
color: theme.palette.text.secondary,
@@ -193,15 +192,8 @@ export const MetadataSection = ({
metadataList: Metadata[];
}) => {
return (
-
- {header && (
-
- {header}
-
- )}
-
-
-
-
+
);
};
diff --git a/dashboard/client/src/pages/job/JobDetail.tsx b/dashboard/client/src/pages/job/JobDetail.tsx
index e3721403dbc7..3e630c5e1c6f 100644
--- a/dashboard/client/src/pages/job/JobDetail.tsx
+++ b/dashboard/client/src/pages/job/JobDetail.tsx
@@ -1,31 +1,41 @@
-import { Box, Grid, makeStyles, Typography } from "@material-ui/core";
+import { Box, makeStyles, Typography } from "@material-ui/core";
import React, { useContext, useRef, useState } from "react";
import { Link } from "react-router-dom";
import { GlobalContext } from "../../App";
import { CollapsibleSection } from "../../common/CollapsibleSection";
-import { DurationText } from "../../common/DurationText";
-import { formatDateFromTimeMs } from "../../common/formatUtils";
-import {
- CpuProfilingLink,
- CpuStackTraceLink,
-} from "../../common/ProfilingLink";
+import { Section } from "../../common/Section";
import Loading from "../../components/Loading";
-import { MetadataSection } from "../../components/MetadataSection";
import { StatusChip } from "../../components/StatusChip";
import TitleCard from "../../components/TitleCard";
import { NestedJobProgressLink, UnifiedJob } from "../../type/job";
import ActorList from "../actor/ActorList";
+import { NodeCountCard } from "../overview/cards/NodeCountCard";
import PlacementGroupList from "../state/PlacementGroup";
import TaskList from "../state/task";
import { useRayStatus } from "./hook/useClusterStatus";
import { useJobDetail } from "./hook/useJobDetail";
+import { JobMetadataSection } from "./JobDetailInfoPage";
+import { JobDriverLogs } from "./JobDriverLogs";
import { JobProgressBar } from "./JobProgressBar";
import { TaskTimeline } from "./TaskTimeline";
const useStyle = makeStyles((theme) => ({
root: {
padding: theme.spacing(2),
+ backgroundColor: "white",
+ },
+ section: {
+ marginBottom: theme.spacing(4),
+ },
+ autoscalerSection: {
+ flexWrap: "wrap",
+ [theme.breakpoints.up("md")]: {
+ flexWrap: "nowrap",
+ },
+ },
+ nodeCountCard: {
+ flex: "1 0 500px",
},
}));
@@ -71,23 +81,21 @@ export const JobDetailChartsPage = () => {
return (
-
- {title}
-
+
+ {title}
+
{cluster_status_rows.map((i, key) => {
// Format the output.
// See format_info_string in util.py
- if (i.startsWith("-----") || i.startsWith("=====")) {
- // Separator
- return
;
+ if (i.startsWith("-----") || i.startsWith("=====") || i === "") {
+ // Ignore separators
+ return null;
} else if (i.endsWith(":")) {
return (
{i}
);
- } else if (i === "") {
- return
;
} else {
return
{i}
;
}
@@ -145,174 +153,132 @@ export const JobDetailChartsPage = () => {
return (
-
- ,
- },
- {
- label: "Job ID",
- content: job.job_id
- ? {
- value: job.job_id,
- copyableValue: job.job_id,
- }
- : { value: "-" },
- },
- {
- label: "Submission ID",
- content: job.submission_id
- ? {
- value: job.submission_id,
- copyableValue: job.submission_id,
- }
- : {
- value: "-",
- },
- },
- {
- label: "Duration",
- content: job.start_time ? (
-
- ) : (
- -
- ),
- },
- {
- label: "Started at",
- content: {
- value: job.start_time
- ? formatDateFromTimeMs(job.start_time)
- : "-",
- },
- },
- {
- label: "Ended at",
- content: {
- value: job.end_time ? formatDateFromTimeMs(job.end_time) : "-",
- },
- },
- {
- label: "Actions",
- content: (
-
-
-
-
-
-
-
- ),
- },
- ]}
- />
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ {job.type === "SUBMISSION" && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
{cluster_status?.data
? formatNodeStatus(cluster_status?.data.clusterStatus)
: "No cluster status."}
-
-
-
-
+
+
{cluster_status?.data
? formatResourcesStatus(cluster_status?.data.clusterStatus)
: "No cluster status."}
-
-
-
-
- {
- setTaskTableExpanded(!taskTableExpanded);
- }}
- >
+
+
+
+
+ {
+ setTaskTableExpanded(!taskTableExpanded);
+ }}
+ className={classes.section}
+ >
+
-
-
- {
- setActorTableExpanded(!actorTableExpanded);
- }}
- >
+
+
+
+ {
+ setActorTableExpanded(!actorTableExpanded);
+ }}
+ className={classes.section}
+ >
+
-
-
-
+
+
+
+
+
-
+
+
);
};
diff --git a/dashboard/client/src/pages/job/JobDetailActorPage.tsx b/dashboard/client/src/pages/job/JobDetailActorPage.tsx
index b31d653ca3ed..2a8ab3d9e1a6 100644
--- a/dashboard/client/src/pages/job/JobDetailActorPage.tsx
+++ b/dashboard/client/src/pages/job/JobDetailActorPage.tsx
@@ -1,7 +1,7 @@
import { makeStyles } from "@material-ui/core";
import React from "react";
-import TitleCard from "../../components/TitleCard";
+import { Section } from "../../common/Section";
import ActorList from "../actor/ActorList";
import { MainNavPageInfo } from "../layout/mainNavContext";
import { useJobDetail } from "./hook/useJobDetail";
@@ -9,6 +9,7 @@ import { useJobDetail } from "./hook/useJobDetail";
const useStyle = makeStyles((theme) => ({
root: {
padding: theme.spacing(2),
+ backgroundColor: "white",
},
}));
@@ -31,9 +32,9 @@ export const JobDetailActorsPage = () => {
return (
);
};
diff --git a/dashboard/client/src/pages/job/JobDetailInfoPage.tsx b/dashboard/client/src/pages/job/JobDetailInfoPage.tsx
index b8345e8d44e4..2d69d75d0d11 100644
--- a/dashboard/client/src/pages/job/JobDetailInfoPage.tsx
+++ b/dashboard/client/src/pages/job/JobDetailInfoPage.tsx
@@ -1,18 +1,26 @@
-import { makeStyles } from "@material-ui/core";
+import { createStyles, makeStyles, Typography } from "@material-ui/core";
import React from "react";
+import { CodeDialogButtonWithPreview } from "../../common/CodeDialogButton";
import { DurationText } from "../../common/DurationText";
import { formatDateFromTimeMs } from "../../common/formatUtils";
+import {
+ CpuProfilingLink,
+ CpuStackTraceLink,
+} from "../../common/ProfilingLink";
import Loading from "../../components/Loading";
import { MetadataSection } from "../../components/MetadataSection";
import { StatusChip } from "../../components/StatusChip";
import TitleCard from "../../components/TitleCard";
+import { UnifiedJob } from "../../type/job";
import { MainNavPageInfo } from "../layout/mainNavContext";
import { useJobDetail } from "./hook/useJobDetail";
+import { JobLogsLink } from "./JobDetail";
const useStyle = makeStyles((theme) => ({
root: {
padding: theme.spacing(2),
+ backgroundColor: "white",
},
}));
@@ -51,70 +59,120 @@ export const JobDetailInfoPage = () => {
path: job.job_id ? `/jobs/${job.job_id}/info` : undefined,
}}
/>
-
- ,
- },
- {
- label: "Job ID",
- content: job.job_id
- ? {
- value: job.job_id,
- copyableValue: job.job_id,
- }
- : { value: "-" },
- },
- {
- label: "Submission ID",
- content: job.submission_id
- ? {
- value: job.submission_id,
- copyableValue: job.submission_id,
- }
- : {
- value: "-",
- },
- },
- {
- label: "Duration",
- content: job.start_time ? (
-
- ) : (
- -
- ),
- },
- {
- label: "Started at",
- content: {
- value: job.start_time
- ? formatDateFromTimeMs(job.start_time)
- : "-",
+ {job.job_id}
+
+
+ );
+};
+
+const useJobMetadataSectionStyles = makeStyles((theme) =>
+ createStyles({
+ metadataButton: {
+ display: "inline-flex",
+ maxWidth: "100%",
+ },
+ }),
+);
+
+type JobMetadataSectionProps = {
+ job: UnifiedJob;
+};
+
+export const JobMetadataSection = ({ job }: JobMetadataSectionProps) => {
+ const classes = useJobMetadataSectionStyles();
+
+ return (
+ ,
+ },
+ {
+ label: "Job ID",
+ content: job.job_id
+ ? {
+ value: job.job_id,
+ copyableValue: job.job_id,
+ }
+ : { value: "-" },
+ },
+ {
+ label: "Submission ID",
+ content: job.submission_id
+ ? {
+ value: job.submission_id,
+ copyableValue: job.submission_id,
+ }
+ : {
+ value: "-",
},
- },
- {
- label: "Ended at",
- content: {
- value: job.end_time ? formatDateFromTimeMs(job.end_time) : "-",
+ },
+ {
+ label: "Duration",
+ content: job.start_time ? (
+
+ ) : (
+ -
+ ),
+ },
+ {
+ label: "Started at",
+ content: {
+ value: job.start_time ? formatDateFromTimeMs(job.start_time) : "-",
+ },
+ },
+ {
+ label: "Ended at",
+ content: {
+ value: job.end_time ? formatDateFromTimeMs(job.end_time) : "-",
+ },
+ },
+ ...(job.type === "SUBMISSION"
+ ? [
+ {
+ label: "User-provided metadata",
+ content:
+ job.metadata && Object.keys(job.metadata).length ? (
+
+ ) : undefined,
},
- },
- ]}
- />
-
-
+ ]
+ : []),
+ {
+ label: "Actions",
+ content: (
+
+
+
+
+
+
+
+ ),
+ },
+ ]}
+ />
);
};
diff --git a/dashboard/client/src/pages/job/JobDriverLogs.component.test.tsx b/dashboard/client/src/pages/job/JobDriverLogs.component.test.tsx
new file mode 100644
index 000000000000..1c526b1caccf
--- /dev/null
+++ b/dashboard/client/src/pages/job/JobDriverLogs.component.test.tsx
@@ -0,0 +1,47 @@
+import { render, screen } from "@testing-library/react";
+import React from "react";
+import { get } from "../../service/requestHandlers";
+import { JobDriverLogs } from "./JobDriverLogs";
+
+jest.mock("../../service/requestHandlers");
+
+const mockedGet = jest.mocked(get);
+
+describe("JobDriverLogs", () => {
+ it("renders", async () => {
+ expect.assertions(6);
+
+ mockedGet.mockResolvedValue({
+ headers: {
+ "content-type": "text/plain",
+ },
+ data: "log line\nthis is a line\nHi\n10\nfoo",
+ });
+
+ render(
+
,
+ );
+
+ await screen.findByText(/log line/);
+ expect(screen.getByText(/log line/)).toBeVisible();
+ expect(screen.getByText(/this is a line/)).toBeVisible();
+ expect(screen.getByText(/Hi/)).toBeVisible();
+ expect(screen.getByText(/10/)).toBeVisible();
+ expect(screen.getByText(/foo/)).toBeVisible();
+
+ expect(mockedGet).toBeCalledWith(
+ "log_proxy?url=http%3A%2F%2F127.0.0.1%3A52365%2Flogs%2Fjob-driver-raysubmit_12345.log",
+ );
+ });
+});
diff --git a/dashboard/client/src/pages/job/JobDriverLogs.tsx b/dashboard/client/src/pages/job/JobDriverLogs.tsx
new file mode 100644
index 000000000000..5d45b03bf1bb
--- /dev/null
+++ b/dashboard/client/src/pages/job/JobDriverLogs.tsx
@@ -0,0 +1,78 @@
+import { Typography } from "@material-ui/core";
+import React, { useContext } from "react";
+import useSWR from "swr";
+import { GlobalContext } from "../../App";
+import { getLogDetail, getLogDownloadUrl } from "../../service/log";
+import { UnifiedJob } from "../../type/job";
+import { LogViewer } from "../log/LogViewer";
+
+const useDriverLogs = (
+ job: Pick<
+ UnifiedJob,
+ "driver_agent_http_address" | "driver_info" | "submission_id"
+ >,
+) => {
+ const { ipLogMap } = useContext(GlobalContext);
+ const { driver_agent_http_address, driver_info, submission_id } = job;
+ const host = (() => {
+ if (driver_agent_http_address) {
+ return `${driver_agent_http_address}/logs/`;
+ } else if (driver_info && ipLogMap[driver_info.node_ip_address]) {
+ return `${ipLogMap[driver_info.node_ip_address]}/`;
+ }
+ })();
+ const path = `job-driver-${submission_id}.log`;
+
+ const url = host ? `${host}${path}` : undefined;
+ const downloadUrl = url ? getLogDownloadUrl(url) : undefined;
+
+ const {
+ data: log,
+ isLoading,
+ mutate,
+ } = useSWR(url ? ["useDriverLogs", url] : null, async ([_, url]) =>
+ getLogDetail(url)
+ .then((res) => {
+ if (res) {
+ return res;
+ } else {
+ return "(This file is empty.)";
+ }
+ })
+ .catch(() => {
+ return "(Failed to load)";
+ }),
+ );
+
+ return {
+ log: isLoading ? "Loading..." : log,
+ downloadUrl,
+ refresh: mutate,
+ host,
+ path,
+ };
+};
+
+type JobDriverLogsProps = {
+ job: Pick<
+ UnifiedJob,
+ "driver_agent_http_address" | "driver_info" | "submission_id"
+ >;
+};
+
+export const JobDriverLogs = ({ job }: JobDriverLogsProps) => {
+ const { downloadUrl, log, path, refresh } = useDriverLogs(job);
+ return typeof log === "string" ? (
+
{
+ refresh();
+ }}
+ />
+ ) : (
+ Failed to load
+ );
+};
diff --git a/dashboard/client/src/pages/job/TaskTimeline.tsx b/dashboard/client/src/pages/job/TaskTimeline.tsx
index 50e7fd2b3357..a3129636cb3f 100644
--- a/dashboard/client/src/pages/job/TaskTimeline.tsx
+++ b/dashboard/client/src/pages/job/TaskTimeline.tsx
@@ -10,9 +10,6 @@ import { ClassNameProps } from "../../common/props";
import { downloadTaskTimelineHref } from "../../service/task";
const useStyle = makeStyles((theme) => ({
- root: {
- padding: theme.spacing(2, 0, 0),
- },
button: {
marginTop: theme.spacing(2),
},
@@ -26,7 +23,7 @@ export const TaskTimeline = ({ jobId }: TaskTimelineProps) => {
const classes = useStyle();
return (
-
+
{/* TODO(aguo): Add link to external documentation about Timeline view. */}
Timeline view shows how tasks are executed across different nodes and
diff --git a/dashboard/client/src/pages/job/hook/useJobDetail.ts b/dashboard/client/src/pages/job/hook/useJobDetail.ts
index d473eb3cba31..9c31ab4ad1a0 100644
--- a/dashboard/client/src/pages/job/hook/useJobDetail.ts
+++ b/dashboard/client/src/pages/job/hook/useJobDetail.ts
@@ -11,10 +11,10 @@ export const useJobDetail = () => {
const [refreshing, setRefresh] = useState(true);
const { ipLogMap } = useContext(GlobalContext);
const { data: job, isLoading } = useSWR(
- "useJobDetail",
- async () => {
+ ["useJobDetail", params.id],
+ async ([_, jobId]) => {
try {
- const rsp = await getJobDetail(params.id);
+ const rsp = await getJobDetail(jobId);
return rsp.data;
} catch (e) {
setMsg("Job Query Error Please Check JobId");
diff --git a/dashboard/client/src/pages/log/LogViewer.tsx b/dashboard/client/src/pages/log/LogViewer.tsx
new file mode 100644
index 000000000000..cb155b9417c7
--- /dev/null
+++ b/dashboard/client/src/pages/log/LogViewer.tsx
@@ -0,0 +1,195 @@
+import {
+ Button,
+ createStyles,
+ InputAdornment,
+ LinearProgress,
+ makeStyles,
+ Switch,
+ TextField,
+} from "@material-ui/core";
+import { SearchOutlined } from "@material-ui/icons";
+import React, { useState } from "react";
+import LogVirtualView from "../../components/LogView/LogVirtualView";
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ search: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+const useLogViewer = () => {
+ const [search, setSearch] =
+ useState<{
+ keywords?: string;
+ lineNumber?: string;
+ fontSize?: number;
+ revert?: boolean;
+ }>();
+ const [startTime, setStart] = useState();
+ const [endTime, setEnd] = useState();
+
+ return {
+ search,
+ setSearch,
+ startTime,
+ setStart,
+ endTime,
+ setEnd,
+ };
+};
+
+type LogViewerProps = {
+ path?: string;
+ log: string;
+ downloadUrl?: string;
+ onRefreshClick?: () => void;
+ height?: number;
+};
+
+export const LogViewer = ({
+ path,
+ log,
+ downloadUrl,
+ onRefreshClick,
+ height = 600,
+}: LogViewerProps) => {
+ const classes = useStyles();
+
+ const { search, setSearch, startTime, setStart, endTime, setEnd } =
+ useLogViewer();
+
+ return (
+
+ {log !== "Loading..." && (
+
+
+
{
+ setSearch({ ...search, keywords: value });
+ },
+ type: "",
+ endAdornment: (
+
+
+
+ ),
+ }}
+ />
+ {
+ setSearch({ ...search, lineNumber: value });
+ },
+ type: "",
+ endAdornment: (
+
+
+
+ ),
+ }}
+ />
+ {
+ setSearch({ ...search, fontSize: Number(value) });
+ },
+ type: "",
+ }}
+ />
+ {
+ setStart(val.target.value);
+ }}
+ InputLabelProps={{
+ shrink: true,
+ }}
+ />
+ {
+ setEnd(val.target.value);
+ }}
+ InputLabelProps={{
+ shrink: true,
+ }}
+ />
+
+ Reverse:{" "}
+ setSearch({ ...search, revert: v })}
+ />
+ {onRefreshClick && (
+
+ )}
+
+ {downloadUrl && path && (
+
+ )}
+
+
+
+
+ )}
+ {log === "Loading..." && (
+
+
+
+
+ )}
+
+ );
+};
diff --git a/dashboard/client/src/pages/log/Logs.tsx b/dashboard/client/src/pages/log/Logs.tsx
index a44253595a51..61eb93468840 100644
--- a/dashboard/client/src/pages/log/Logs.tsx
+++ b/dashboard/client/src/pages/log/Logs.tsx
@@ -1,22 +1,11 @@
-import {
- Button,
- InputAdornment,
- LinearProgress,
- List,
- ListItem,
- makeStyles,
- Paper,
- Switch,
- TextField,
-} from "@material-ui/core";
-import { SearchOutlined } from "@material-ui/icons";
-import React, { useEffect, useRef, useState } from "react";
+import { Button, List, ListItem, makeStyles, Paper } from "@material-ui/core";
+import React, { useEffect, useState } from "react";
import { Outlet, useLocation, useParams } from "react-router-dom";
-import LogVirtualView from "../../components/LogView/LogVirtualView";
import { SearchInput } from "../../components/SearchComponent";
import TitleCard from "../../components/TitleCard";
import { getLogDetail, getLogDownloadUrl } from "../../service/log";
import { MainNavPageInfo } from "../layout/mainNavContext";
+import { LogViewer } from "./LogViewer";
const useStyles = makeStyles((theme) => ({
root: {
@@ -36,30 +25,16 @@ const useStyles = makeStyles((theme) => ({
},
}));
-type LogsProps = {
- theme?: "dark" | "light";
-};
-
-const useLogs = ({ theme }: LogsProps) => {
+const useLogs = () => {
const { search: urlSearch } = useLocation();
const { host, path } = useParams();
const searchMap = new URLSearchParams(urlSearch);
const urlFileName = searchMap.get("fileName");
- const el = useRef(null);
const [origin, setOrigin] = useState();
- const [search, setSearch] =
- useState<{
- keywords?: string;
- lineNumber?: string;
- fontSize?: number;
- revert?: boolean;
- }>();
const [fileName, setFileName] = useState(searchMap.get("fileName") || "");
const [log, setLogs] =
useState();
const [downloadUrl, setDownloadUrl] = useState();
- const [startTime, setStart] = useState();
- const [endTime, setEnd] = useState();
useEffect(() => {
setFileName(urlFileName || "");
@@ -97,37 +72,14 @@ const useLogs = ({ theme }: LogsProps) => {
downloadUrl,
host,
path,
- el,
- search,
- setSearch,
- theme,
fileName,
setFileName,
- startTime,
- setStart,
- endTime,
- setEnd,
};
};
-const Logs = (props: LogsProps) => {
+const Logs = () => {
const classes = useStyles();
- const {
- log,
- origin,
- downloadUrl,
- path,
- el,
- search,
- setSearch,
- theme,
- fileName,
- setFileName,
- startTime,
- setStart,
- endTime,
- setEnd,
- } = useLogs(props);
+ const { log, origin, downloadUrl, path, fileName, setFileName } = useLogs();
let href = "#/logs/";
if (origin) {
@@ -142,7 +94,7 @@ const Logs = (props: LogsProps) => {
}
}
return (
-
+
{!origin && Select a node to view logs
}
@@ -191,125 +143,8 @@ const Logs = (props: LogsProps) => {
))}
)}
- {typeof log === "string" && log !== "Loading..." && (
-
-
-
{
- setSearch({ ...search, keywords: value });
- },
- type: "",
- endAdornment: (
-
-
-
- ),
- }}
- />
- {
- setSearch({ ...search, lineNumber: value });
- },
- type: "",
- endAdornment: (
-
-
-
- ),
- }}
- />
- {
- setSearch({ ...search, fontSize: Number(value) });
- },
- type: "",
- }}
- />
- {
- setStart(val.target.value);
- }}
- InputLabelProps={{
- shrink: true,
- }}
- />
- {
- setEnd(val.target.value);
- }}
- InputLabelProps={{
- shrink: true,
- }}
- />
-
- Reverse:{" "}
- setSearch({ ...search, revert: v })}
- />
-
- {downloadUrl && path && (
-
- )}
-
-
-
-
- )}
- {log === "Loading..." && (
-
-
-
-
+ {typeof log === "string" && (
+
)}
diff --git a/dashboard/client/src/pages/node/ClusterLayout.tsx b/dashboard/client/src/pages/node/ClusterLayout.tsx
index c74f6d7a3909..16a02d05eb97 100644
--- a/dashboard/client/src/pages/node/ClusterLayout.tsx
+++ b/dashboard/client/src/pages/node/ClusterLayout.tsx
@@ -1,17 +1,12 @@
import React from "react";
-import { RiInformationLine, RiTableAltLine } from "react-icons/ri";
+import { RiInformationLine, RiTableLine } from "react-icons/ri";
import { SideTabLayout, SideTabRouteLink } from "../layout/SideTabLayout";
export const ClusterLayout = () => {
return (
-
+
);
};
diff --git a/dashboard/client/src/theme.ts b/dashboard/client/src/theme.ts
index 6259f9b65b22..a3ec06564f61 100644
--- a/dashboard/client/src/theme.ts
+++ b/dashboard/client/src/theme.ts
@@ -17,10 +17,12 @@ const basicTheme: ThemeOptions = {
'"Segoe UI Symbol"',
].join(","),
h1: {
- fontSize: "2rem",
+ fontSize: "1.5rem",
+ fontWeight: 500,
},
h2: {
- fontSize: "1.5rem",
+ fontSize: "1.25rem",
+ fontWeight: 500,
},
h3: {
fontSize: "1rem",
diff --git a/dashboard/modules/metrics/dashboards/serve_deployment_grafana_dashboard_base.json b/dashboard/modules/metrics/dashboards/serve_deployment_grafana_dashboard_base.json
index c66c41e5d50e..af9c611e8867 100644
--- a/dashboard/modules/metrics/dashboards/serve_deployment_grafana_dashboard_base.json
+++ b/dashboard/modules/metrics/dashboards/serve_deployment_grafana_dashboard_base.json
@@ -131,6 +131,7 @@
}
]
},
+ "rayMeta": ["excludesSystemRoutes"],
"time": {
"from": "now-30m",
"to": "now"