Repository navigation
feat(new-webui): Integrate database queries for IngestPage dashboard components. #910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
c446289
feat(new-webui): Connect the ingestion page to SQL server.
hoophalab 977bdf3
Fix coderabbit comments.
hoophalab c3cc97f
fix: Query SQL in each widget.
hoophalab 2fc3f14
Fix coderabbit comments.
hoophalab 6d93f14
refactor: Move column names to `sqlConfig.ts`
hoophalab 68190ca
fix comments
hoophalab dc7ec64
rename zustand
hoophalab a873236
fix comments
hoophalab 03f6ae7
Merge branch 'main' into ingestion-data
hoophalab File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
8 changes: 3 additions & 5 deletions
8
components/log-viewer-webui/client/src/pages/IngestPage/Details/Files.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 3 additions & 5 deletions
8
components/log-viewer-webui/client/src/pages/IngestPage/Details/Messages.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
components/log-viewer-webui/client/src/pages/IngestPage/IngestState/QueryJobsResp.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| import dayjs from "dayjs"; | ||
|
|
||
| import {Nullable} from "../../../typings/common"; | ||
| import {JobData} from "../Jobs/typings"; | ||
|
|
||
|
|
||
| /** | ||
| * Enum of compression job statuses, matching the `CompressionJobStatus` class in | ||
| * `job_orchestration.scheduler.constants`. | ||
| * | ||
| * @enum {CompressionJobStatus} | ||
| */ | ||
| enum CompressionJobStatus { | ||
| PENDING = 0, | ||
| RUNNING = 1, | ||
| SUCCEEDED = 2, | ||
| FAILED = 3, | ||
| } | ||
|
|
||
| /** | ||
| * Convert JobStatus to Antd's badge string. | ||
| * | ||
| * @param status | ||
| * @return | ||
| * @throws an Error if status is not a CompressionJobStatus. | ||
| */ | ||
| const convertJobStatusToBadgeString = (status: CompressionJobStatus) => { | ||
| switch (status) { | ||
| case CompressionJobStatus.PENDING: | ||
| return "warning"; | ||
| case CompressionJobStatus.RUNNING: | ||
| return "processing"; | ||
| case CompressionJobStatus.SUCCEEDED: | ||
| return "success"; | ||
| case CompressionJobStatus.FAILED: | ||
| return "error"; | ||
| default: | ||
| throw new Error("Unexpected status value."); | ||
| } | ||
| }; | ||
|
|
||
| const BYTES_PER_KIBIBYTE = 1024; | ||
|
|
||
| /** | ||
| * Computes a human-readable representation of a size in bytes. | ||
| * | ||
| * @param num | ||
| * @return | ||
| */ | ||
| const computeHumanSize = (num: number) => { | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| const siPrefixes = ["", | ||
| "K", | ||
| "M", | ||
| "G", | ||
| "T", | ||
| "P", | ||
| "E", | ||
| "Z"]; | ||
|
|
||
| for (let i = 0; i < siPrefixes.length; ++i) { | ||
| if (BYTES_PER_KIBIBYTE > Math.abs(num)) { | ||
| return `${Math.round(num)} ${siPrefixes[i]}B`; | ||
| } | ||
| num /= BYTES_PER_KIBIBYTE; | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| return `${Math.round(num)} B`; | ||
| }; | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
|
|
||
| interface QueryJobsItem { | ||
| compressed_size: number; | ||
| duration: Nullable<number>; | ||
| retrieval_time: number; | ||
| start_time: Nullable<string>; | ||
| status: number; | ||
| status_msg: string; | ||
| uncompressed_size: number; | ||
| update_time: string; | ||
| _id: number; | ||
| } | ||
|
|
||
| type QueryJobsResp = QueryJobsItem[]; | ||
|
|
||
| /** | ||
| * Convert a QuryJobsItem to JobData | ||
| * | ||
| * @param job | ||
| * @return | ||
| */ | ||
| const convertQueryJobsItemToJobData = (job: QueryJobsItem): JobData => { | ||
| let uncompressedSizeText = ""; | ||
| let compressedSizeText = ""; | ||
| let speedText = ""; | ||
|
|
||
| if (null === job.duration && null !== job.start_time) { | ||
| job.duration = dayjs().unix() - dayjs(job.start_time).unix(); | ||
| } | ||
|
|
||
| const uncompressedSize = Number(job.uncompressed_size); | ||
| if (false === isNaN(uncompressedSize) && 0 !== uncompressedSize) { | ||
| uncompressedSizeText = computeHumanSize(uncompressedSize); | ||
| } | ||
|
|
||
| const compressedSize = Number(job.compressed_size); | ||
| if (false === isNaN(compressedSize) && 0 !== compressedSize) { | ||
| compressedSizeText = computeHumanSize(compressedSize); | ||
| } | ||
|
|
||
| if ( | ||
| false === isNaN(uncompressedSize) && | ||
| 0 !== uncompressedSize && | ||
| 0 < job.duration | ||
| ) { | ||
| speedText = `${computeHumanSize(job.uncompressed_size / job.duration)}/s`; | ||
| } | ||
|
|
||
| return { | ||
| compressedSize: compressedSizeText, | ||
| dataIngested: uncompressedSizeText, | ||
| jobId: String(job._id), | ||
| key: String(job._id), | ||
| speed: speedText, | ||
| status: convertJobStatusToBadgeString(job.status), | ||
| }; | ||
| }; | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
|
|
||
| export type {QueryJobsResp}; | ||
| export {convertQueryJobsItemToJobData}; | ||
100 changes: 100 additions & 0 deletions
100
components/log-viewer-webui/client/src/pages/IngestPage/IngestState/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import axios, {HttpStatusCode} from "axios"; | ||
| import dayjs from "dayjs"; | ||
| import {create} from "zustand"; | ||
|
|
||
| import {JobData} from "../Jobs/typings"; | ||
| import { | ||
| convertQueryJobsItemToJobData, | ||
| QueryJobsResp, | ||
| } from "./QueryJobsResp"; | ||
| import { | ||
| getQueryJobsSql, | ||
| getQueryStatsSql, | ||
| QueryStatsResp, | ||
| } from "./sql"; | ||
|
|
||
|
|
||
| interface IngestState { | ||
| compressedSize: number; | ||
| uncompressedSize: number; | ||
| timeRange: [dayjs.Dayjs, dayjs.Dayjs]; | ||
| numMessages: number; | ||
| numFiles: number; | ||
| jobs: JobData[]; | ||
| updateStats: () => Promise<void>; | ||
| updateJobs: () => Promise<void>; | ||
| } | ||
|
|
||
| /** | ||
| * Default values of the ingest state. | ||
| */ | ||
| const INGEST_STATE_DEFAULT = Object.freeze<IngestState>({ | ||
| compressedSize: 0, | ||
| jobs: [], | ||
| numFiles: 0, | ||
| numMessages: 0, | ||
| timeRange: [dayjs(), | ||
| dayjs()], | ||
| uncompressedSize: 0, | ||
| updateJobs: async () => { | ||
| }, | ||
| updateStats: async () => { | ||
| }, | ||
| }); | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
|
|
||
| const JOB_DAYS_TO_SHOW: number = 30; | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
|
|
||
| const useIngestStore = create<IngestState>((set) => ({ | ||
| ...INGEST_STATE_DEFAULT, | ||
| updateStats: async () => { | ||
| try { | ||
| const response = await axios.post<QueryStatsResp>("/query/sql", { | ||
| queryString: getQueryStatsSql(), | ||
| }); | ||
|
|
||
| if (Number(HttpStatusCode.Ok) !== response.status) { | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| throw new Error(); | ||
| } | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| const [resp] = response.data; | ||
| if ("undefined" === typeof resp) { | ||
| throw new Error(); | ||
| } | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| set(() => ({ | ||
| compressedSize: resp.total_compressed_size, | ||
| numFiles: resp.num_files, | ||
| numMessages: resp.num_messages, | ||
| timeRange: [dayjs(resp.begin_timestamp), | ||
| dayjs(resp.end_timestamp)], | ||
| uncompressedSize: resp.total_uncompressed_size, | ||
| })); | ||
| } catch (error: unknown) { | ||
| console.error("An error occurred when fetching stats: ", error); | ||
| } | ||
| }, | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| updateJobs: async () => { | ||
| try { | ||
| const beginTimestamp = dayjs().subtract(JOB_DAYS_TO_SHOW, "days") | ||
| .unix(); | ||
| const response = await axios.post<QueryJobsResp>("/query/sql", { | ||
| queryString: getQueryJobsSql(beginTimestamp), | ||
| }); | ||
|
|
||
| if (Number(HttpStatusCode.Ok) !== response.status) { | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| throw new Error(); | ||
| } | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| const resp = response.data; | ||
| const jobs = resp | ||
| .map((item): JobData => convertQueryJobsItemToJobData(item)) | ||
| .sort((a, b): number => Number(a.key) - Number(b.key)); | ||
|
|
||
| set(() => ({ | ||
| jobs: jobs, | ||
| })); | ||
| } catch (error: unknown) { | ||
| console.error("An error occurred when fetching stats: ", error); | ||
|
hoophalab marked this conversation as resolved.
Outdated
|
||
| } | ||
| }, | ||
| })); | ||
|
|
||
| export {INGEST_STATE_DEFAULT}; | ||
| export default useIngestStore; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.