Compare commits
2 Commits
main
...
fix/ui-sav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbe59ae8e0 | ||
|
|
ffb25253b4 |
@ -25,6 +25,7 @@ Docs: https://docs.clawd.bot
|
|||||||
### Fixes
|
### Fixes
|
||||||
- BlueBubbles: keep part-index GUIDs in reply tags when short IDs are missing.
|
- BlueBubbles: keep part-index GUIDs in reply tags when short IDs are missing.
|
||||||
- Web UI: hide internal `message_id` hints in chat bubbles.
|
- Web UI: hide internal `message_id` hints in chat bubbles.
|
||||||
|
- Web UI: allow form saves with unsupported schema paths while blocking missing schema; clear stale disconnect banners on reconnect. (#1678) Thanks @Glucksberg.
|
||||||
- Web UI: show Stop button during active runs, swap back to New session when idle. (#1664) Thanks @ndbroadbent.
|
- Web UI: show Stop button during active runs, swap back to New session when idle. (#1664) Thanks @ndbroadbent.
|
||||||
- Heartbeat: normalize target identifiers for consistent routing.
|
- Heartbeat: normalize target identifiers for consistent routing.
|
||||||
- TUI: reload history after gateway reconnect to restore session state. (#1663)
|
- TUI: reload history after gateway reconnect to restore session state. (#1663)
|
||||||
|
|||||||
@ -124,6 +124,7 @@ export function connectGateway(host: GatewayHost) {
|
|||||||
mode: "webchat",
|
mode: "webchat",
|
||||||
onHello: (hello) => {
|
onHello: (hello) => {
|
||||||
host.connected = true;
|
host.connected = true;
|
||||||
|
host.lastError = null;
|
||||||
host.hello = hello;
|
host.hello = hello;
|
||||||
applySnapshot(host, hello);
|
applySnapshot(host, hello);
|
||||||
void loadAssistantIdentity(host as unknown as ClawdbotApp);
|
void loadAssistantIdentity(host as unknown as ClawdbotApp);
|
||||||
@ -134,7 +135,10 @@ export function connectGateway(host: GatewayHost) {
|
|||||||
},
|
},
|
||||||
onClose: ({ code, reason }) => {
|
onClose: ({ code, reason }) => {
|
||||||
host.connected = false;
|
host.connected = false;
|
||||||
host.lastError = `disconnected (${code}): ${reason || "no reason"}`;
|
// Code 1012 = Service Restart (expected during config saves, don't show as error)
|
||||||
|
if (code !== 1012) {
|
||||||
|
host.lastError = `disconnected (${code}): ${reason || "no reason"}`;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onEvent: (evt) => handleGatewayEvent(host, evt),
|
onEvent: (evt) => handleGatewayEvent(host, evt),
|
||||||
onGap: ({ expected, received }) => {
|
onGap: ({ expected, received }) => {
|
||||||
|
|||||||
@ -38,7 +38,7 @@ describe("config view", () => {
|
|||||||
onSubsectionChange: vi.fn(),
|
onSubsectionChange: vi.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
it("disables save when form is unsafe", () => {
|
it("allows save when form is unsafe", () => {
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
render(
|
render(
|
||||||
renderConfig({
|
renderConfig({
|
||||||
@ -59,6 +59,28 @@ describe("config view", () => {
|
|||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const saveButton = Array.from(
|
||||||
|
container.querySelectorAll("button"),
|
||||||
|
).find((btn) => btn.textContent?.trim() === "Save") as
|
||||||
|
| HTMLButtonElement
|
||||||
|
| undefined;
|
||||||
|
expect(saveButton).not.toBeUndefined();
|
||||||
|
expect(saveButton?.disabled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("disables save when schema is missing", () => {
|
||||||
|
const container = document.createElement("div");
|
||||||
|
render(
|
||||||
|
renderConfig({
|
||||||
|
...baseProps(),
|
||||||
|
schema: null,
|
||||||
|
formMode: "form",
|
||||||
|
formValue: { gateway: { mode: "local" } },
|
||||||
|
originalValue: {},
|
||||||
|
}),
|
||||||
|
container,
|
||||||
|
);
|
||||||
|
|
||||||
const saveButton = Array.from(
|
const saveButton = Array.from(
|
||||||
container.querySelectorAll("button"),
|
container.querySelectorAll("button"),
|
||||||
).find((btn) => btn.textContent?.trim() === "Save") as
|
).find((btn) => btn.textContent?.trim() === "Save") as
|
||||||
|
|||||||
@ -233,9 +233,10 @@ export function renderConfig(props: ConfigProps) {
|
|||||||
const hasRawChanges = props.formMode === "raw" && props.raw !== props.originalRaw;
|
const hasRawChanges = props.formMode === "raw" && props.raw !== props.originalRaw;
|
||||||
const hasChanges = props.formMode === "form" ? diff.length > 0 : hasRawChanges;
|
const hasChanges = props.formMode === "form" ? diff.length > 0 : hasRawChanges;
|
||||||
|
|
||||||
// Save/apply buttons require actual changes to be enabled
|
// Save/apply buttons require actual changes to be enabled.
|
||||||
|
// Note: formUnsafe warns about unsupported schema paths but shouldn't block saving.
|
||||||
const canSaveForm =
|
const canSaveForm =
|
||||||
Boolean(props.formValue) && !props.loading && !formUnsafe;
|
Boolean(props.formValue) && !props.loading && Boolean(analysis.schema);
|
||||||
const canSave =
|
const canSave =
|
||||||
props.connected &&
|
props.connected &&
|
||||||
!props.saving &&
|
!props.saving &&
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user