fix(beszel): widget transparency, error handling, and cache invalidation

- Remove hardcoded background colors from Beszel grid/table widgets so
  the board's opacity slider controls the background via the parent
  card's --background-color CSS variable
- Grid: set bg="transparent" on inner Card components
- Table: override mantine-datatable default backgrounds to transparent
- Stats: make system selector toggle only visible on hover
- Stats: fix chart width/height(-1) warning by setting minHeight: 1
- All Beszel widgets: throw query errors to trigger the ErrorBoundary
  instead of silently rendering an empty/black UI
- Add retry: false to beszel-system-stats queries
- Add invalidateIntegrationCacheAsync() to clear all cached data and
  session stores for an integration when it is updated or deleted,
  preventing stale/errored data from persisting after config changes
This commit is contained in:
Thomas Camlong committed 2026-06-17 23:39:14 +02:00
1 parent 4b85afbb87
commit f83ef563b0
10 files changed
+84 -20

No files matched your search

@@ -27,6 +27,7 @@ import {
integrationSecretKindObject,
} from "@homarr/definitions";
import { createIntegrationAsync } from "@homarr/integrations";
import { invalidateIntegrationCacheAsync } from "@homarr/redis";
import { byIdSchema } from "@homarr/validation/common";
import {
integrationCreateSchema,
@@ -469,6 +470,10 @@ export const integrationRouter = createTRPCRouter({
kind: integration.kind,
url: input.url,
});
// Invalidate all cached data for this integration so that widgets pick up the
// new configuration immediately instead of serving stale (or errored) data.
await invalidateIntegrationCacheAsync(input.id);
}),
delete: protectedProcedure
.meta({
@@ -490,6 +495,9 @@ export const integrationRouter = createTRPCRouter({
}
await ctx.db.delete(integrations).where(eq(integrations.id, input.id));
// Clean up any cached data left behind by the deleted integration.
await invalidateIntegrationCacheAsync(input.id);
}),
getIntegrationPermissions: protectedProcedure.input(byIdSchema).query(async ({ input, ctx }) => {
await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full");