fix: gate scrollbar resize guard on size, preserve parse causes

Address CodeRabbit review on #6510:
- gridstack: only suppress recalculation when the width delta is
  insignificant AND (non-dynamic OR height unchanged), so dynamic
  sections still rebuild on height changes
- beszel: propagate the response parse failure via { cause } in both
  error wrappers
- auth tests: cover invalid (non-string) OIDC groups claims
This commit is contained in:
ajnart committed 2026-08-08 11:35:42 +02:00
1 parent e0ebdd9047
commit 71b986f249
3 files changed
+44 -11

No files matched your search

@@ -319,23 +319,29 @@ const useCssVariableConfiguration = ({
columnCount,
isDynamic,
}: UseCssVariableConfiguration) => {
const prevWidthRef = useRef<number | null>(null);
const prevSizeRef = useRef<{ width: number; height: number } | null>(null);
const onResize = useCallback(() => {
if (!wrapperRef.current) return;
if (!gridRef.current) return;
const currentWidth = wrapperRef.current.clientWidth;
const prevWidth = prevWidthRef.current;
const currentHeight = wrapperRef.current.clientHeight;
const prevSize = prevSizeRef.current;
// Only recalculate if the width change is significant enough (> 20px)
// This prevents infinite feedback loops when the vertical scrollbar
// appears/disappears, causing clientWidth to oscillate by ~15px
if (prevWidth !== null && Math.abs(currentWidth - prevWidth) < 20) {
// Only skip recalculation when the width change is insignificant (< 20px)
// and, for dynamic sections, the height is unchanged. This prevents infinite
// feedback loops when the vertical scrollbar appears/disappears, causing
// clientWidth to oscillate by ~15px, while still reacting to height changes.
if (
prevSize !== null &&
Math.abs(currentWidth - prevSize.width) < 20 &&
(!isDynamic || currentHeight === prevSize.height)
) {
return;
}
prevWidthRef.current = currentWidth;
prevSizeRef.current = { width: currentWidth, height: currentHeight };
handleResizeChange(
wrapperRef.current,
+21
View File
@@ -172,6 +172,27 @@ describe("createSignInEventHandler should create signInEventHandler", () => {
});
expect(dbGroupMembers?.groupId).toBe("1");
});
test("should not change memberships for an invalid groups claim", async () => {
// Arrange
const db = createDb();
await createUserAsync(db, "oidc");
await createGroupAsync(db);
await db.insert(groupMembers).values({ userId: "1", groupId: "1" });
const eventHandler = createSignInEventHandler(db);
// Act
await eventHandler?.({
user: { id: "1", name: "test" },
profile: { preferred_username: "test", someRandomGroupsKey: 42 },
account: null,
});
// Assert
const dbGroupMembers = await db.query.groupMembers.findFirst({
where: eq(groupMembers.userId, "1"),
});
expect(dbGroupMembers?.groupId).toBe("1");
});
test("should remove group membership", async () => {
// Arrange
const db = createDb();
@@ -171,9 +171,11 @@ export class BeszelIntegration extends Integration {
integrationId: this.integration.id,
error: error instanceof Error ? error.message : String(error),
});
throw new ErrorWithMetadata("Beszel authentication response was not valid JSON", {
integrationId: this.integration.id,
});
throw new ErrorWithMetadata(
"Beszel authentication response was not valid JSON",
{ integrationId: this.integration.id },
{ cause: error instanceof Error ? error : new Error(String(error)) },
);
}
const expiresAt = parseTokenExpiration(data.token) ?? undefined;
@@ -626,7 +628,11 @@ export class BeszelIntegration extends Integration {
logger.warn("Failed to parse Beszel testing response JSON", {
error: error instanceof Error ? error.message : String(error),
});
return TestConnectionError.ParseResult(new ParseError("Beszel testing response was not valid JSON"));
return TestConnectionError.ParseResult(
new ParseError("Beszel testing response was not valid JSON", {
cause: error instanceof Error ? error : new Error(String(error)),
}),
);
}
if (!data.token) {
return TestConnectionError.UnauthorizedResult(401);