Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import DetailsCard from "./DetailsCard";


// eslint-disable-next-line no-warning-comments
// TODO: Replace with values from database once api implemented.
const DUMMY_FILES = 124;
interface FilesProps {
numFiles: number;
}

/**
* Renders the files statistic.
*
* @param props
* @param props.numFiles
* @return
*/
const Files = () => {
const Files = ({numFiles}: FilesProps) => {
return (
<DetailsCard
stat={DUMMY_FILES.toString()}
stat={numFiles.toString()}
title={"Files"}/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import DetailsCard from "./DetailsCard";


// eslint-disable-next-line no-warning-comments
// TODO: Replace with values from database once api implemented.
const DUMMY_MESSAGES = 1235844;
interface MessagesProps {
numMessages: number;
}

/**
* Renders the messages statistic.
*
* @param props
* @param props.numMessages
* @return
*/
const Messages = () => {
const Messages = ({numMessages}: MessagesProps) => {
return (
<DetailsCard
stat={DUMMY_MESSAGES.toString()}
stat={numMessages.toString()}
title={"Messages"}/>
);
};
Expand Down
Comment thread
hoophalab marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import dayjs from "dayjs";
import {Dayjs} from "dayjs";
import {Nullable} from "src/typings/common";

import DetailsCard from "./DetailsCard";


// eslint-disable-next-line no-warning-comments
// TODO: Replace with values from database once api implemented.
const DUMMY_START_DATE = "2021-12-14";
const DUMMY_END_DATE = "2025-04-16";

const DATE_FORMAT = "MMMM D, YYYY";

interface TimeRangeProps {
beginDate: Nullable<Dayjs>;
endDate: Nullable<Dayjs>;
}

/**
* Renders the time range statistic.
*
* @param props
* @param props.beginDate
* @param props.endDate
* @return
*/
const TimeRange = () => {
const formattedStat = `${dayjs(DUMMY_START_DATE).format(DATE_FORMAT)} -
${dayjs(DUMMY_END_DATE).format(DATE_FORMAT)}`;
const TimeRange = ({beginDate, endDate}: TimeRangeProps) => {
const formattedStat = `${beginDate?.format(DATE_FORMAT) ?? "Unknown Begin Date"} -
${endDate?.format(DATE_FORMAT) ?? "Unknown End Date"}`;

return (
<DetailsCard
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,89 @@
import {
useCallback,
useEffect,
useRef,
useState,
} from "react";

import dayjs, {Dayjs} from "dayjs";
import {Nullable} from "src/typings/common";

import {SET_INTERVAL_INVALID_ID} from "../../../typings/time";
import useIngestStatsStore from "../ingestStatsStore";
import {querySql} from "../sqlConfig";
import Files from "./Files";
import styles from "./index.module.css";
import Messages from "./Messages";
import {
DetailsResp,
getDetailsSql,
} from "./sql";
import TimeRange from "./TimeRange";


/**
* Default state for details.
*/
const DETAILS_DEFAULT = Object.freeze({
beginDate: null,
endDate: null,

numFiles: 0,
numMessages: 0,
});

/**
* Renders grid with compression details.
*
* @return
*/
const Details = () => {
const {refreshInterval} = useIngestStatsStore();
const [beginDate, setBeginDate] = useState<Nullable<Dayjs>>(DETAILS_DEFAULT.beginDate);
const [endDate, setEndDate] = useState<Nullable<Dayjs>>(DETAILS_DEFAULT.endDate);
const [numFiles, setNumFiles] = useState<number>(DETAILS_DEFAULT.numFiles);
const [numMessages, setNumMessages] = useState<number>(DETAILS_DEFAULT.numMessages);
const intervalIdRef = useRef<ReturnType<typeof setInterval>>(SET_INTERVAL_INVALID_ID);

/**
* Fetches details stats from the server.
*
* @throws {Error} If the response is undefined.
*/
const fetchDetailsStats = useCallback(async () => {
const {data: [resp]} = await querySql<DetailsResp>(getDetailsSql());
if ("undefined" === typeof resp) {
throw new Error("Details response is undefined");
}
setBeginDate(dayjs(resp.begin_timestamp));
setEndDate(dayjs(resp.end_timestamp));
setNumFiles(resp.num_files);
setNumMessages(resp.num_messages);
}, []);
Comment thread
hoophalab marked this conversation as resolved.

useEffect(() => {
// eslint-disable-next-line no-void
void fetchDetailsStats();
intervalIdRef.current = setInterval(fetchDetailsStats, refreshInterval);

return () => {
clearInterval(intervalIdRef.current);
};
}, [
refreshInterval,
fetchDetailsStats,
]);


return (
<div className={styles["detailsGrid"]}>
<div className={styles["timeRange"]}>
<TimeRange/>
<TimeRange
beginDate={beginDate}
endDate={endDate}/>
</div>
<Messages/>
<Files/>
<Messages numMessages={numMessages}/>
<Files numFiles={numFiles}/>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
CLP_ARCHIVES_TABLE_COLUMN_NAMES,
CLP_FILES_TABLE_COLUMN_NAMES,
SQL_CONFIG,
} from "../sqlConfig";


/**
* Builds the query string to query stats.
*
* @return
*/
Comment thread
hoophalab marked this conversation as resolved.
const getDetailsSql = () => `
SELECT
a.begin_timestamp AS begin_timestamp,
a.end_timestamp AS end_timestamp,
b.num_files AS num_files,
b.num_messages AS num_messages
FROM
(
SELECT
MIN(${CLP_ARCHIVES_TABLE_COLUMN_NAMES.BEGIN_TIMESTAMP}) AS begin_timestamp,
MAX(${CLP_ARCHIVES_TABLE_COLUMN_NAMES.END_TIMESTAMP}) AS end_timestamp
FROM ${SQL_CONFIG.SqlDbClpArchivesTableName}
) a,
(
SELECT
NULLIF(COUNT(DISTINCT ${CLP_FILES_TABLE_COLUMN_NAMES.ORIG_FILE_ID}), 0) AS num_files,
SUM(${CLP_FILES_TABLE_COLUMN_NAMES.NUM_MESSAGES}) AS num_messages
FROM ${SQL_CONFIG.SqlDbClpFilesTableName}
) b;
Comment thread
hoophalab marked this conversation as resolved.
`;
Comment thread
hoophalab marked this conversation as resolved.

Comment thread
hoophalab marked this conversation as resolved.
interface DetailsItem {
begin_timestamp: number;
end_timestamp: number;
num_files: number;
num_messages: number;
}
Comment thread
hoophalab marked this conversation as resolved.

type DetailsResp = DetailsItem[];

export type {
DetailsItem,
DetailsResp,
};
export {getDetailsSql};
Original file line number Diff line number Diff line change
@@ -1,76 +1,40 @@
import {
useCallback,
useEffect,
useRef,
useState,
} from "react";

import {Table} from "antd";
import dayjs from "dayjs";

import {DashboardCard} from "../../../components/DashboardCard";
import {SET_INTERVAL_INVALID_ID} from "../../../typings/time";
import useIngestStatsStore from "../ingestStatsStore";
import {querySql} from "../sqlConfig";
import styles from "./index.module.css";
import {
getQueryJobsSql,
QueryJobsResp,
} from "./sql";
import {
jobColumns,
JobData,
} from "./typings";
import {convertQueryJobsItemToJobData} from "./utils";


// eslint-disable-next-line no-warning-comments
// TODO: Replace with values from database once api implemented.
const DUMMY_DATA: JobData[] = [
{
compressedSize: "460 B",
dataIngested: "267 B",
jobId: "1",
key: "1",
speed: "66 B/s",
status: "success",
},
{
compressedSize: "5 KB",
dataIngested: "50 KB",
jobId: "3",
key: "3",
speed: "10 KB/s",
status: "success",
},
{
compressedSize: "800 B",
dataIngested: "1 KB",
jobId: "5",
key: "5",
speed: "500 B/s",
status: "success",
},
{
compressedSize: "1 KB",
dataIngested: "17 KB",
jobId: "2",
key: "2",
speed: "5 KB/s",
status: "processing",
},
{
compressedSize: "8 MB",
dataIngested: "10 MB",
jobId: "4",
key: "4",
speed: "1 MB/s",
status: "processing",
},
{
compressedSize: "0 B",
dataIngested: "0 B",
jobId: "6",
key: "6",
speed: "0 B/s",
status: "error",
},
{
compressedSize: "450 B",
dataIngested: "500 B",
jobId: "7",
key: "7",
speed: "100 B/s",
status: "warning",
},
];
const DAYS_TO_SHOW: number = 30;

/**
* Default state for jobs.
*/
const JOBS_DEFAULT = Object.freeze({
jobs: [],
});

interface JobsProps {
className?: string;
className: string;
}

/**
Expand All @@ -81,13 +45,47 @@ interface JobsProps {
* @return
*/
const Jobs = ({className}: JobsProps) => {
const {refreshInterval} = useIngestStatsStore();
const [jobs, setJobs] = useState<JobData[]>(JOBS_DEFAULT.jobs);
const intervalIdRef = useRef<ReturnType<typeof setInterval>>(SET_INTERVAL_INVALID_ID);

/**
* Fetches jobs stats from the server.
*
* @throws {Error} If the response is undefined.
*/
const fetchJobsStats = useCallback(async () => {
const beginTimestamp = dayjs().subtract(DAYS_TO_SHOW, "days")
.unix();
const {data: resp} = await querySql<QueryJobsResp>(getQueryJobsSql(beginTimestamp));
const newJobs = resp
.map((item): JobData => convertQueryJobsItemToJobData(item));

setJobs(newJobs);
}, []);
Comment thread
hoophalab marked this conversation as resolved.


useEffect(() => {
// eslint-disable-next-line no-void
void fetchJobsStats();
intervalIdRef.current = setInterval(fetchJobsStats, refreshInterval);

return () => {
clearInterval(intervalIdRef.current);
};
}, [
refreshInterval,
fetchJobsStats,
]);


return (
<div className={className}>
<DashboardCard title={"Ingestion Jobs"}>
<Table<JobData>
className={styles["jobs"] || ""}
columns={jobColumns}
dataSource={DUMMY_DATA}
dataSource={jobs}
Comment thread
hoophalab marked this conversation as resolved.
pagination={false}/>
</DashboardCard>
</div>
Expand Down
Loading