Skip to content

Commit 4644c07

Browse files
committed
fix(control-ui): support raw edits from editable config
1 parent 669df88 commit 4644c07

3 files changed

Lines changed: 30 additions & 7 deletions

File tree

ui/src/ui/app-render.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1198,7 +1198,10 @@ export function renderApp(state: AppViewState) {
11981198
gatewayUrl: state.settings.gatewayUrl,
11991199
assistantName: state.assistantName,
12001200
configPath: state.configSnapshot?.path ?? null,
1201-
rawAvailable: typeof state.configSnapshot?.raw === "string",
1201+
rawAvailable:
1202+
typeof state.configSnapshot?.raw === "string" ||
1203+
!!state.configSnapshot?.config ||
1204+
!!state.configForm,
12021205
} satisfies Omit<
12031206
ConfigProps,
12041207
| "formMode"

ui/src/ui/controllers/config.test.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ describe("applyConfigSnapshot", () => {
183183
expect(state.configDraftBaseHash).toBe("hash-remote");
184184
});
185185

186-
it("forces form mode when the snapshot does not include raw text", () => {
186+
it("keeps raw mode when editable config can be serialized without raw text", () => {
187187
const state = createState();
188188
state.configFormMode = "raw";
189189

@@ -195,7 +195,7 @@ describe("applyConfigSnapshot", () => {
195195
raw: null,
196196
});
197197

198-
expect(state.configFormMode).toBe("form");
198+
expect(state.configFormMode).toBe("raw");
199199
expect(state.configRaw).toBe('{\n "gateway": {\n "mode": "local"\n }\n}\n');
200200
});
201201
});
@@ -707,6 +707,29 @@ describe("applyConfig", () => {
707707
});
708708

709709
describe("saveConfig", () => {
710+
it("submits generated raw text when the snapshot did not include raw text", async () => {
711+
const request = createRequestWithConfigGet();
712+
const state = createState();
713+
state.connected = true;
714+
state.client = { request } as unknown as ConfigState["client"];
715+
state.configFormMode = "raw";
716+
applyConfigSnapshot(state, {
717+
hash: "hash-generated-raw",
718+
sourceConfig: { gateway: { mode: "local" } },
719+
config: { gateway: { mode: "local", runtimeOnly: true } },
720+
valid: true,
721+
issues: [],
722+
raw: null,
723+
});
724+
725+
await saveConfig(state);
726+
727+
expect(request).toHaveBeenCalledWith("config.set", {
728+
raw: '{\n "gateway": {\n "mode": "local"\n }\n}\n',
729+
baseHash: "hash-generated-raw",
730+
});
731+
});
732+
710733
it("submits the original draft base hash after a dirty config refresh", async () => {
711734
const request = createRequestWithConfigGet();
712735
const state = createState();

ui/src/ui/controllers/config.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export function applyConfigSnapshot(
113113
const draftBaseHash = state.configDraftBaseHash ?? state.configSnapshot?.hash ?? null;
114114
state.configSnapshot = snapshot;
115115
const editableConfig = resolveEditableSnapshotConfig(snapshot);
116-
const rawAvailable = typeof snapshot.raw === "string";
116+
const rawAvailable = typeof snapshot.raw === "string" || !!editableConfig || !!state.configForm;
117117
if (!rawAvailable && state.configFormMode === "raw") {
118118
state.configFormMode = "form";
119119
}
@@ -161,9 +161,6 @@ function asJsonSchema(value: unknown): JsonSchema | null {
161161
* gateway's Zod validation always sees correctly typed values.
162162
*/
163163
function serializeFormForSubmit(state: ConfigState): string {
164-
if (state.configFormMode === "raw" && typeof state.configSnapshot?.raw !== "string") {
165-
throw new Error("Raw config editing is unavailable for this snapshot. Switch to Form mode.");
166-
}
167164
if (state.configFormMode !== "form" || !state.configForm) {
168165
return state.configRaw;
169166
}

0 commit comments

Comments
 (0)