mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-27 23:43:37 +00:00
fix: UI glitch: config is not visible
Co-authored-by: sunlit-deng <253064511+sunlit-deng@users.noreply.github.com>
This commit is contained in:
@@ -473,6 +473,36 @@ describe("config view", () => {
|
||||
expect(content.scrollLeft).toBe(0);
|
||||
});
|
||||
|
||||
it("resets config content scroll when switching from form to raw mode", async () => {
|
||||
const container = document.createElement("div");
|
||||
document.body.append(container);
|
||||
|
||||
try {
|
||||
const renderCase = (overrides: Partial<ConfigProps>) =>
|
||||
render(renderConfig({ ...baseProps(), ...overrides }), container);
|
||||
|
||||
renderCase({ formMode: "form" });
|
||||
|
||||
const content = queryRequired(container, ".config-content", HTMLElement);
|
||||
content.scrollTop = 320;
|
||||
content.scrollLeft = 18;
|
||||
content.scrollTo = vi.fn(({ top, left }: { top?: number; left?: number }) => {
|
||||
content.scrollTop = top ?? content.scrollTop;
|
||||
content.scrollLeft = left ?? content.scrollLeft;
|
||||
}) as typeof content.scrollTo;
|
||||
|
||||
renderCase({ formMode: "raw" });
|
||||
await Promise.resolve();
|
||||
|
||||
expect(content["scrollTo"]).toHaveBeenCalledOnce();
|
||||
expect(content["scrollTo"]).toHaveBeenCalledWith({ top: 0, left: 0, behavior: "auto" });
|
||||
expect(content.scrollTop).toBe(0);
|
||||
expect(content.scrollLeft).toBe(0);
|
||||
} finally {
|
||||
container.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it("can hide the root tab for scoped settings surfaces", () => {
|
||||
const { container } = renderConfigView({
|
||||
activeSection: "channels",
|
||||
|
||||
@@ -1184,6 +1184,7 @@ function createConfigEphemeralState(): ConfigEphemeralState {
|
||||
|
||||
const cvs = createConfigEphemeralState();
|
||||
let lastConfigContextKey: string | null = null;
|
||||
let lastFormModeForScroll: ConfigProps["formMode"] | null = null;
|
||||
|
||||
function resetConfigEphemeralState() {
|
||||
Object.assign(cvs, createConfigEphemeralState());
|
||||
@@ -1222,6 +1223,7 @@ function toggleSensitivePathReveal(path: Array<string | number>) {
|
||||
export function resetConfigViewStateForTests() {
|
||||
resetConfigEphemeralState();
|
||||
lastConfigContextKey = null;
|
||||
lastFormModeForScroll = null;
|
||||
}
|
||||
|
||||
export function renderConfig(props: ConfigProps) {
|
||||
@@ -1237,6 +1239,31 @@ export function renderConfig(props: ConfigProps) {
|
||||
const rawAvailable = props.rawAvailable ?? true;
|
||||
const formMode = showModeToggle && rawAvailable ? props.formMode : "form";
|
||||
const requestUpdate = props.onRequestUpdate ?? (() => {});
|
||||
// Scroll helper: target-based (nav clicks) with global fallback (form/raw toggle)
|
||||
const resetContentScroll = (target: EventTarget | null) => {
|
||||
queueMicrotask(() => {
|
||||
const origin = target instanceof Element ? target : null;
|
||||
const content =
|
||||
origin?.closest(".config-main")?.querySelector<HTMLElement>(".config-content") ??
|
||||
globalThis.document?.querySelector<HTMLElement>(".config-content");
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
if (typeof content.scrollTo === "function") {
|
||||
content.scrollTo({ top: 0, left: 0, behavior: "auto" });
|
||||
return;
|
||||
}
|
||||
content.scrollTop = 0;
|
||||
content.scrollLeft = 0;
|
||||
});
|
||||
};
|
||||
|
||||
// Reset scroll position when switching between form and raw mode
|
||||
if (lastFormModeForScroll !== null && lastFormModeForScroll !== formMode) {
|
||||
resetContentScroll(null);
|
||||
}
|
||||
lastFormModeForScroll = formMode;
|
||||
|
||||
const currentContextKey = configContextKey(props);
|
||||
if (lastConfigContextKey !== currentContextKey) {
|
||||
resetConfigEphemeralState();
|
||||
@@ -1301,24 +1328,6 @@ export function renderConfig(props: ConfigProps) {
|
||||
const settingsLayout = props.settingsLayout ?? "tabs";
|
||||
const allCategories = [...visibleCategories, ...(otherCategory ? [otherCategory] : [])];
|
||||
|
||||
const resetContentScroll = (target: EventTarget | null) => {
|
||||
queueMicrotask(() => {
|
||||
const origin = target instanceof Element ? target : null;
|
||||
const content = origin
|
||||
?.closest(".config-main")
|
||||
?.querySelector<HTMLElement>(".config-content");
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
if (typeof content.scrollTo === "function") {
|
||||
content.scrollTo({ top: 0, left: 0, behavior: "auto" });
|
||||
return;
|
||||
}
|
||||
content.scrollTop = 0;
|
||||
content.scrollLeft = 0;
|
||||
});
|
||||
};
|
||||
|
||||
function renderAccordionNav() {
|
||||
return html`
|
||||
<div class="config-accordion-nav">
|
||||
|
||||
Reference in New Issue
Block a user