Skip to content

Commit 545eae0

Browse files
committed
[ui] allows to edit index config
1 parent 32b0ec9 commit 545eae0

File tree

4 files changed

+270
-47
lines changed

4 files changed

+270
-47
lines changed

quickwit/quickwit-ui/src/components/JsonEditor.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ import { EDITOR_THEME } from "../utils/theme";
1818

1919
export function JsonEditor({
2020
content,
21+
readOnly = true,
2122
resizeOnMount,
2223
jsonSchema,
24+
onContentEdited,
2325
}: {
2426
content: unknown;
27+
readOnly?: boolean;
2528
resizeOnMount: boolean;
2629
jsonSchema?: object;
30+
onContentEdited?: (value: unknown) => void;
2731
}) {
2832
const monaco = useMonaco();
2933
const arbitraryFilename = "inmemory://" + useId();
@@ -77,10 +81,15 @@ export function JsonEditor({
7781
path={arbitraryFilename}
7882
language="json"
7983
value={JSON.stringify(content, null, 2)}
84+
onChange={(value) => {
85+
try {
86+
if (value) onContentEdited?.(JSON.parse(value));
87+
} catch (err) {}
88+
}}
8089
beforeMount={beforeMount}
8190
onMount={onMount}
8291
options={{
83-
readOnly: true,
92+
readOnly: readOnly,
8493
fontFamily: "monospace",
8594
overviewRulerBorder: false,
8695
overviewRulerLanes: 0,
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2021-Present Datadog, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import CheckIcon from "@mui/icons-material/Check";
16+
import EditIcon from "@mui/icons-material/Edit";
17+
import { Box, Button, Chip, Stack } from "@mui/material";
18+
import { useEffect, useState } from "react";
19+
import { JsonEditor } from "./JsonEditor";
20+
21+
type JsonEditorEditableProps = {
22+
saving: boolean;
23+
pristine: boolean;
24+
onSave: () => void;
25+
} & React.ComponentProps<typeof JsonEditor>;
26+
27+
/**
28+
* wrapper around JsonEditor that displays edit actions
29+
*/
30+
export function JsonEditorEditable({
31+
saving,
32+
pristine,
33+
onSave,
34+
...jsonEditorProps
35+
}: JsonEditorEditableProps) {
36+
const wasSaving = useDelayedTruthyValue(saving, 1000);
37+
const showSuccess = !saving && wasSaving;
38+
39+
return (
40+
<Box style={{ height: "100%", position: "relative" }}>
41+
<JsonEditor readOnly={false} {...jsonEditorProps} />
42+
<Stack
43+
direction="row"
44+
spacing={1}
45+
style={{ position: "absolute", top: 8, right: 12, zIndex: 1001 }}
46+
>
47+
{pristine && !showSuccess && (
48+
<Chip
49+
icon={<EditIcon sx={{ fontSize: 16 }} />}
50+
label="Editable"
51+
size="small"
52+
variant="filled"
53+
/>
54+
)}
55+
{(!pristine || showSuccess) && (
56+
<Button
57+
variant="contained"
58+
size="small"
59+
onClick={onSave}
60+
disabled={saving || showSuccess}
61+
style={{ width: "100px" }}
62+
>
63+
{saving && "Saving..."}
64+
{showSuccess && (
65+
<>
66+
<CheckIcon sx={{ fontSize: 16, mr: 0.5 }} />
67+
Saved
68+
</>
69+
)}
70+
{!saving && !showSuccess && "Save"}
71+
</Button>
72+
)}
73+
</Stack>
74+
</Box>
75+
);
76+
}
77+
78+
/**
79+
* Returns the value immediately when truthy, but delays returning falsy values by delayMs.
80+
* Useful for showing success states briefly after an operation completes.
81+
*/
82+
function useDelayedTruthyValue<T>(value: T, delayMs: number): T {
83+
const [delayedValue, setDelayedValue] = useState<T>(value);
84+
85+
useEffect(() => {
86+
if (value) {
87+
setDelayedValue(value);
88+
} else {
89+
const timeout = setTimeout(() => {
90+
setDelayedValue(value);
91+
}, delayMs);
92+
93+
return () => clearTimeout(timeout);
94+
}
95+
}, [value, delayMs]);
96+
97+
return value || delayedValue;
98+
}

quickwit/quickwit-ui/src/services/client.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,25 @@ export class Client {
103103
return this.fetch(`${this.apiRoot()}indexes`, {});
104104
}
105105

106+
// TODO unit test
107+
async updateIndexConfig(
108+
indexId: string,
109+
indexConfig: IndexMetadata["index_config"],
110+
): Promise<IndexMetadata> {
111+
return this.fetch(
112+
`${this.apiRoot()}indexes/${indexId}`,
113+
{ method: "PUT" },
114+
JSON.stringify(indexConfig),
115+
);
116+
}
117+
106118
async fetch<T>(
107119
url: string,
108120
params: RequestInit,
109121
body: string | null = null,
110122
): Promise<T> {
111123
if (body !== null) {
112-
params.method = "POST";
124+
params.method = params.method ?? "POST";
113125
params.body = body;
114126
params.headers = {
115127
...params.headers,

0 commit comments

Comments
 (0)