-
Notifications
You must be signed in to change notification settings - Fork 82
feat(webui): Add compression job submission for local files only. #1294
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
base: main
Are you sure you want to change the base?
Changes from all commits
af84f96
f148177
c763142
ef523af
8930af8
9b87c4e
30ced50
aea137c
d697a1b
dd64ac3
4d82aa2
cb291dc
d22eff7
9108763
8049e8d
e45ea84
138c553
b21b823
6aa742b
b8da979
ab1bef7
6d7a3af
67f571e
3a3654b
b2eefdf
ceb52a3
a1d314e
aab5486
285beb4
4bb46c4
d13fd52
44033bf
01cba4d
542a9f1
0bce379
c8a8065
23dcd12
e260129
1110684
d5ff9a7
ac26e2c
64a8d18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,23 @@ | ||||||||||||||||||
import { | ||||||||||||||||||
CompressionJob, | ||||||||||||||||||
CompressionJobCreation, | ||||||||||||||||||
} from "@webui/common/schemas/compression"; | ||||||||||||||||||
Comment on lines
+1
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick Use type‑only imports for TS types. Avoids emitting unused runtime imports under strict TS configs. -import {
+import type {
CompressionJob,
CompressionJobCreation,
} from "@webui/common/schemas/compression"; 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||
import axios from "axios"; | ||||||||||||||||||
|
||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Submits a compression job. | ||||||||||||||||||
* | ||||||||||||||||||
* @param payload | ||||||||||||||||||
* @return | ||||||||||||||||||
*/ | ||||||||||||||||||
const submitCompressionJob = async (payload: CompressionJobCreation) | ||||||||||||||||||
: Promise<CompressionJob> => { | ||||||||||||||||||
console.log("Submitting compression job:", JSON.stringify(payload)); | ||||||||||||||||||
const {data} = await axios.post<CompressionJob>("/api/compress", payload); | ||||||||||||||||||
|
||||||||||||||||||
return data; | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
|
||||||||||||||||||
export {submitCompressionJob}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,11 @@ | ||
import {CLP_QUERY_ENGINES} from "@webui/common/config"; | ||
import { | ||
CLP_QUERY_ENGINES, | ||
CLP_STORAGE_ENGINES, | ||
} from "@webui/common/config"; | ||
Comment on lines
+1
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick Good consolidation; add a small runtime guard for settings sanity. Defensively assert Add near the settings reads: const VALID_ENGINES = new Set(Object.values(CLP_STORAGE_ENGINES));
if (!VALID_ENGINES.has(SETTINGS_STORAGE_ENGINE)) {
throw new Error(`Invalid ClpStorageEngine: ${String(SETTINGS_STORAGE_ENGINE)}`);
} 🤖 Prompt for AI Agents
|
||
|
||
import {settings} from "../settings"; | ||
|
||
|
||
/** | ||
* CLP variants. | ||
*/ | ||
enum CLP_STORAGE_ENGINES { | ||
CLP = "clp", | ||
CLP_S = "clp-s", | ||
} | ||
|
||
const SETTINGS_STORAGE_ENGINE = settings.ClpStorageEngine as CLP_STORAGE_ENGINES; | ||
const SETTINGS_QUERY_ENGINE = settings.ClpQueryEngine as CLP_QUERY_ENGINES; | ||
|
||
|
@@ -22,8 +17,6 @@ const STREAM_TYPE = CLP_STORAGE_ENGINES.CLP === SETTINGS_STORAGE_ENGINE ? | |
"json"; | ||
|
||
export { | ||
CLP_QUERY_ENGINES, | ||
CLP_STORAGE_ENGINES, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should probably remove query engines export as well |
||
SETTINGS_QUERY_ENGINE, | ||
SETTINGS_STORAGE_ENGINE, | ||
STREAM_TYPE, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import {CLP_DEFAULT_DATASET_NAME} from "@webui/common/config"; | ||
import { | ||
Form, | ||
Input, | ||
} from "antd"; | ||
|
||
|
||
const DATASET_HELPER_TEXT = `If left empty, dataset "${CLP_DEFAULT_DATASET_NAME}" will be used.`; | ||
const DATASET_PLACEHOLDER_TEXT = "The dataset for new archives"; | ||
const TIMESTAMP_KEY_HELPER_TEXT = "If not provided, events will not have assigned" + | ||
" timestamps and can only be searched from the command line without a timestamp filter."; | ||
const TIMESTAMP_KEY_PLACEHOLDER_TEXT = | ||
"The path (e.g. x.y) for the field containing the log event's timestamp"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. putting this on a new line; otherwise the string has to be broken into two to avoid line length violations |
||
|
||
/** | ||
* Renders additional compression job submission form items for CLP-S storage engine. | ||
* | ||
* @return | ||
*/ | ||
const ClpSFormItems = () => ( | ||
<> | ||
<Form.Item | ||
label={"Dataset"} | ||
name={"dataset"} | ||
tooltip={DATASET_HELPER_TEXT} | ||
> | ||
<Input placeholder={DATASET_PLACEHOLDER_TEXT}/> | ||
</Form.Item> | ||
<Form.Item | ||
label={"Timestamp Key"} | ||
name={"timestampKey"} | ||
tooltip={TIMESTAMP_KEY_HELPER_TEXT} | ||
> | ||
<Input placeholder={TIMESTAMP_KEY_PLACEHOLDER_TEXT}/> | ||
</Form.Item> | ||
</> | ||
); | ||
|
||
|
||
export default ClpSFormItems; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { | ||
Form, | ||
Input, | ||
} from "antd"; | ||
|
||
|
||
/** | ||
* Renders a form item for inputting file paths for compression job submission. | ||
* | ||
* @return | ||
*/ | ||
const PathsInputFormItem = () => ( | ||
<Form.Item | ||
label={"Paths"} | ||
name={"paths"} | ||
rules={[{required: true, message: "Please enter at least one path"}]} | ||
> | ||
<Input.TextArea | ||
autoSize={{minRows: 4, maxRows: 10}} | ||
placeholder={"Enter paths to compress, one per line"}/> | ||
</Form.Item> | ||
); | ||
|
||
|
||
export default PathsInputFormItem; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { | ||
Button, | ||
Form, | ||
} from "antd"; | ||
|
||
|
||
interface SubmitFormItemProps { | ||
isSubmitting: boolean; | ||
} | ||
|
||
/** | ||
* Render a submit button for a form. | ||
* | ||
* @param props | ||
* @param props.isSubmitting | ||
* @return | ||
*/ | ||
const SubmitFormItem = ({isSubmitting}: SubmitFormItemProps) => ( | ||
<Form.Item> | ||
<Button | ||
htmlType={"submit"} | ||
loading={isSubmitting} | ||
type={"primary"} | ||
> | ||
Submit | ||
</Button> | ||
</Form.Item> | ||
); | ||
|
||
|
||
export default SubmitFormItem; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { | ||
useMutation, | ||
useQueryClient, | ||
} from "@tanstack/react-query"; | ||
import {CLP_STORAGE_ENGINES} from "@webui/common/config"; | ||
import {CompressionJobCreation} from "@webui/common/schemas/compression"; | ||
import { | ||
Form, | ||
Typography, | ||
} from "antd"; | ||
|
||
import {submitCompressionJob} from "../../../api/compress"; | ||
import {DashboardCard} from "../../../components/DashboardCard"; | ||
import {SETTINGS_STORAGE_ENGINE} from "../../../config"; | ||
import ClpSFormItems from "./ClpSFormItems"; | ||
import PathsInputFormItem from "./PathsInputFormItem"; | ||
import SubmitFormItem from "./SubmitFormItem"; | ||
|
||
|
||
type FormValues = { | ||
paths: string; | ||
dataset?: string; | ||
timestampKey?: string; | ||
}; | ||
|
||
|
||
/** | ||
* Renders a compression job submission form. | ||
* | ||
* @return | ||
*/ | ||
const Compress = () => { | ||
const [form] = Form.useForm<FormValues>(); | ||
|
||
const queryClient = useQueryClient(); | ||
const { | ||
mutate, | ||
isPending: isSubmitting, | ||
isSuccess, | ||
isError, | ||
data, | ||
error, | ||
} = useMutation({ | ||
mutationFn: submitCompressionJob, | ||
onSettled: async () => { | ||
// Invalidate queries that are affected by a new compression job. | ||
await queryClient.invalidateQueries({queryKey: ["jobs"]}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason not to put this in the success handler? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. while we don't expect contents in the job table to change if a row cannot be inserted into the table, i think we should always refresh the job table so it's less error prone and future proof. for example, if the |
||
}, | ||
onSuccess: () => { | ||
form.resetFields(); | ||
}, | ||
}); | ||
Comment on lines
+43
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick Optional: add explicit generics to useMutation for stronger typing. Keeps the mutation’s data/error/variables types explicit. - } = useMutation({
+ } = useMutation<{ jobId: string }, Error, CompressionJobCreation>({
mutationFn: submitCompressionJob,
onSettled: async () => {
// Invalidate queries that are affected by a new compression job.
await queryClient.invalidateQueries({queryKey: ["jobs"]});
},
onSuccess: () => {
form.resetFields();
},
});
|
||
|
||
const handleSubmit = (values: FormValues) => { | ||
// eslint-disable-next-line no-warning-comments | ||
// TODO: replace the UI with a file selector and remove below string manipulation. | ||
// Convert multiline input to array of paths. | ||
const paths = values.paths | ||
.split("\n") | ||
.map((path) => path.trim()) | ||
.filter((path) => 0 < path.length); | ||
|
||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const payload: CompressionJobCreation = {paths}; | ||
|
||
if ("undefined" !== typeof values.dataset) { | ||
payload.dataset = values.dataset; | ||
} | ||
if ("undefined" !== typeof values.timestampKey) { | ||
payload.timestampKey = values.timestampKey; | ||
} | ||
|
||
mutate(payload); | ||
}; | ||
|
||
return ( | ||
<DashboardCard title={"Start Ingestion"}> | ||
<Form | ||
form={form} | ||
layout={"vertical"} | ||
onFinish={handleSubmit} | ||
> | ||
<PathsInputFormItem/> | ||
{CLP_STORAGE_ENGINES.CLP_S === SETTINGS_STORAGE_ENGINE && <ClpSFormItems/>} | ||
<SubmitFormItem isSubmitting={isSubmitting}/> | ||
|
||
{isSuccess && ( | ||
<Typography.Text type={"success"}> | ||
Compression job submitted successfully with ID: | ||
{" "} | ||
{data.jobId} | ||
</Typography.Text> | ||
)} | ||
{isError && ( | ||
<Typography.Text type={"danger"}> | ||
Failed to submit compression job: | ||
{" "} | ||
{error instanceof Error ? | ||
error.message : | ||
"Unknown error"} | ||
</Typography.Text> | ||
)} | ||
</Form> | ||
</DashboardCard> | ||
); | ||
}; | ||
|
||
|
||
export default Compress; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,6 @@ | |
gap: 20px; | ||
} | ||
|
||
.jobsGrid { | ||
.fullRow { | ||
grid-column: 1 / -1; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,13 @@ | ||
import {useCallback} from "react"; | ||
|
||
import {SearchOutlined} from "@ant-design/icons"; | ||
import {CLP_STORAGE_ENGINES} from "@webui/common/config"; | ||
import { | ||
Button, | ||
Tooltip, | ||
} from "antd"; | ||
|
||
import { | ||
CLP_STORAGE_ENGINES, | ||
SETTINGS_STORAGE_ENGINE, | ||
} from "../../../../../config"; | ||
import {SETTINGS_STORAGE_ENGINE} from "../../../../../config"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick Avoid split config sources (consider co-locating). If @webui/common/config also exports SETTINGS_STORAGE_ENGINE, import both from there to prevent drift between modules; otherwise, consider re-exporting to keep a single source of truth. Can you confirm whether SETTINGS_STORAGE_ENGINE is (or can be) exported from @webui/common/config as part of this consolidation? 🤖 Prompt for AI Agents
|
||
import {computeTimelineConfig} from "../../../SearchResults/SearchResultsTimeline/utils"; | ||
import useSearchStore from "../../../SearchState/index"; | ||
import {SEARCH_UI_STATE} from "../../../SearchState/typings"; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import {CLP_STORAGE_ENGINES} from "@webui/common/config"; | ||
import { | ||
type QueryJob, | ||
type QueryJobCreation, | ||
|
@@ -9,10 +10,7 @@ import { | |
clearQueryResults, | ||
submitQuery, | ||
} from "../../../api/search"; | ||
import { | ||
CLP_STORAGE_ENGINES, | ||
SETTINGS_STORAGE_ENGINE, | ||
} from "../../../config"; | ||
import {SETTINGS_STORAGE_ENGINE} from "../../../config"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 🧩 Analysis chainMixed config sources; align types/values for engine comparison. Confirm SETTINGS_STORAGE_ENGINE is one of Object.values(CLP_STORAGE_ENGINES); otherwise the equality check will silently fail. Consider consolidating SETTINGS_STORAGE_ENGINE into @webui/common/config or exporting a shared StorageEngine type from there to enforce compatibility. 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Locate SETTINGS_STORAGE_ENGINE definition/initialization:"
rg -nC3 'SETTINGS_STORAGE_ENGINE' components/webui/client/src/config
echo; echo "Inspect CLP_STORAGE_ENGINES values:"
rg -nC3 'export\s+const\s+CLP_STORAGE_ENGINES' components/webui/common/src/config.ts Length of output: 1370 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Show client config ==="
sed -n '1,240p' components/webui/client/src/config/index.ts || true
echo
echo "=== Search repo for CLP_STORAGE_ENGINES occurrences ==="
rg -n --hidden --no-ignore -S 'CLP_STORAGE_ENGINES' -g '!*node_modules/*' -C2 || true
echo
echo "=== Look specifically for enum/const definitions for CLP_STORAGE_ENGINES ==="
rg -n --hidden --no-ignore -S 'export\s+(const|enum)\s+CLP_STORAGE_ENGINES|enum\s+CLP_STORAGE_ENGINES|CLP_STORAGE_ENGINES\s*=' -g '!*node_modules/*' -C2 || true
echo
echo "=== Search for CLP_QUERY_ENGINES occurrences ==="
rg -n --hidden --no-ignore -S 'CLP_QUERY_ENGINES' -g '!*node_modules/*' -C2 || true
echo
echo "=== Find where settings.ClpStorageEngine is defined/used ==="
rg -n --hidden --no-ignore -S 'ClpStorageEngine' -g '!*node_modules/*' -C2 || true
echo
echo "=== Print likely settings files (if present) ==="
sed -n '1,240p' components/webui/client/src/settings.ts || true
sed -n '1,240p' components/webui/client/src/settings/index.ts || true
sed -n '1,240p' components/webui/client/src/settings/index.tsx || true
echo
echo "=== Search common config directory for storage engine definitions ==="
rg -n --hidden --no-ignore -S 'CLP_STORAGE_ENGINES|CLP_QUERY_ENGINES' components/webui/common -g '!*node_modules/*' -C2 || true Length of output: 2694 Ensure runtime value of SETTINGS_STORAGE_ENGINE matches CLP_STORAGE_ENGINES settings.ClpStorageEngine is declared as string and loaded from settings.json but only type-asserted to CLP_STORAGE_ENGINES; the STREAM_TYPE equality can silently fail at runtime.
🤖 Prompt for AI Agents
|
||
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../SearchState/"; | ||
import {SEARCH_UI_STATE} from "../SearchState/typings"; | ||
import {unquoteString} from "./utils"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick
🧩 Analysis chain
New archive-output + storage-engine keys: verify server settings support; consider container_clp_config for consistency.
Apply:
Run:
🏁 Script executed:
Length of output: 3455
Verified: ArchiveOutput keys + ClpStorageEngine exist; optional refactor available
🤖 Prompt for AI Agents