Compare commits

..
Author SHA1 Message Date
Thomas 062fda642c Merge branch 'release/v2' into feat/widget-integration-dx 2026-08-30 18:31:24 +02:00
Thomas b53042f055 Merge branch 'release/v2' into feat/widget-integration-dx 2026-08-28 14:08:34 +02:00
ajnart bf0eed7607 fix: preserve typed media translations 2026-08-27 14:50:06 +02:00
ajnart 8e29f7aa18 merge: sync release/v2 2026-08-27 14:47:01 +02:00
ajnart 5ac4a4cffc fix: address review feedback 2026-08-26 17:36:02 +02:00
ajnart ac7e3f2ef4 Merge remote-tracking branch 'origin/release/v2' into feat/pr-6691-hardening
# Conflicts:
#	apps/nextjs/src/app/[locale]/layout.tsx
#	packages/api/src/router/widgets/anchor-notes.ts
#	packages/api/src/router/widgets/archive-team-warrior.ts
#	packages/api/src/router/widgets/audio-stats.ts
#	packages/api/src/router/widgets/bazarr.ts
#	packages/api/src/router/widgets/coolify.ts
#	packages/api/src/router/widgets/firewall.ts
#	packages/api/src/router/widgets/immich.ts
#	packages/api/src/router/widgets/paperless-ngx.ts
#	packages/api/src/router/widgets/patchmon.ts
#	packages/api/src/router/widgets/speedtest-tracker.ts
#	packages/api/src/router/widgets/tracearr.ts
#	packages/api/src/router/widgets/traefik.ts
#	packages/api/src/router/widgets/umami.ts
#	packages/api/src/router/widgets/uptime-kuma.ts
#	packages/api/src/router/widgets/vpn.ts
#	packages/api/src/router/widgets/wud.ts
#	packages/definitions/src/widget-integration-map.ts
#	packages/widgets/src/anchor-note/index.ts
#	packages/widgets/src/archive-team-warrior/index.ts
#	packages/widgets/src/audio-stats/index.ts
#	packages/widgets/src/bazarr/index.ts
#	packages/widgets/src/coolify/index.ts
#	packages/widgets/src/firewall/index.ts
#	packages/widgets/src/immich/album-carousel/index.ts
#	packages/widgets/src/immich/server-stats/index.ts
#	packages/widgets/src/paperless-ngx/index.ts
#	packages/widgets/src/patchmon/index.ts
#	packages/widgets/src/speedtest-tracker/index.ts
#	packages/widgets/src/system-disks/index.ts
#	packages/widgets/src/system-resources/index.ts
#	packages/widgets/src/tracearr/index.ts
#	packages/widgets/src/traefik/index.ts
#	packages/widgets/src/umami/index.ts
#	packages/widgets/src/uptime-kuma/index.ts
#	packages/widgets/src/vpn/index.ts
#	packages/widgets/src/wud/index.ts
2026-08-26 15:12:49 +02:00
ajnart 47724f44eb fix: harden widget request caching 2026-08-26 14:57:53 +02:00
ajnart c81088d876 Merge remote-tracking branch 'origin/release/v2' into feat/widget-integration-dx
# Conflicts:
#	packages/api/src/router/board.ts
2026-08-25 10:09:03 +02:00
ajnart 9bf266935b refactor: address adversarial widget architecture review 2026-08-25 10:07:32 +02:00
Thomas Camlong 0ca62f1232 fix(request-handler): prevent shared-cache stampede while a refresh lock is held
Waiters that lost the refresh lock polled the shared cache for only 750ms
before falling through to the upstream, but the refresh lock lives for 15s.
On a cold cache with an upstream slower than 750ms, every waiting pod gave up
and stampeded the origin (each also writing L2). Extend the poll window to
match the lock TTL so waiters return the entry the holder publishes instead.

Adds a regression test that fails without the fix.
2026-08-24 15:26:30 +02:00
ajnart 4ca17d8e8b merge: sync release/v2 2026-08-24 09:53:48 +02:00
ajnart 24e6e4a47d refactor: tighten TypeScript boundaries 2026-08-24 09:38:30 +02:00
ajnart ad0120fe01 fix: guard service example timestamp 2026-08-24 03:15:23 +02:00
ajnart 17c47ac9d1 fix: harden custom widget AI authoring 2026-08-24 02:59:41 +02:00
ajnart 97e0adbb3a fix: separate timetable address families 2026-08-24 01:52:55 +02:00
ajnart addf1c7335 test: update Beszel Redis mocks 2026-08-24 01:36:29 +02:00
ajnart 8f9efd0074 refactor: simplify widget and integration architecture 2026-08-24 00:57:36 +02:00
ajnart c988c35b29 refactor: finish feature module tooling 2026-08-23 22:39:06 +02:00
ajnart 425cb653a1 refactor: streamline widget and integration architecture 2026-08-23 22:33:29 +02:00
8 changed files with 3 additions and 34 deletions

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 649 KiB

+1 -1
View File
@@ -18,7 +18,7 @@ Paste a URL and press Enter, paste several comma-separated or one-per-line URLs,
URLs do not need an App record; Homarr uses the site's favicon and falls back to a link icon when it cannot load one.
Bookmarks selected from Apps continue to use the App name, URL, icon, and description.
**Adaptive** layout is the practical default: it changes between icons, compact rows, and tiles as the widget changes shape. **Compact grid** keeps every card to a short row. Enable **Expand cards to fill row** when cards in an incomplete final row should use the remaining width. Every compact item exposes its destination on hover, while advanced view expands items into descriptive cards.
**Adaptive** layout is the practical default: it changes between icons, compact rows, and tiles as the widget changes shape. Every compact item exposes its destination on hover, while advanced view expands items into descriptive cards.
### Screenshots
@@ -56,12 +56,6 @@ export const bookmarksWidget: WidgetDefinition = {
values: { type: "boolean" },
defaultValue: "yes",
},
{
name: "Expand cards to fill row",
description: "Whether cards in an incomplete final row expand to use the remaining width.",
values: { type: "boolean" },
defaultValue: "no",
},
{
name: "Bookmarks",
description: "URLs and existing Apps shown by the widget.",
-3
View File
@@ -2272,9 +2272,6 @@
"withBorder": {
"label": "Show border"
},
"grow": {
"label": "Expand cards to fill row"
},
"customUrls": {
"label": "Custom links"
},
@@ -6,7 +6,6 @@ import {
Box,
Card,
Center,
Grid,
Group,
ScrollArea,
SimpleGrid,
@@ -157,14 +156,6 @@ export default function BookmarksWidget({
<Group gap={options.spacing} wrap="nowrap" mih="100%" align="stretch">
{cards}
</Group>
) : options.grow ? (
<Grid grow columns={plan.columns} gap={options.spacing}>
{cards.map((card) => (
<Grid.Col key={card.key} span={1}>
{card}
</Grid.Col>
))}
</Grid>
) : (
<SimpleGrid cols={plan.columns} spacing={options.spacing} verticalSpacing={options.spacing}>
{cards}
-1
View File
@@ -49,7 +49,6 @@ export const { definition, componentLoader } = createWidgetDefinition("bookmarks
hideHostname: factory.switch({ defaultValue: false }),
openNewTab: factory.switch({ defaultValue: true }),
withBorder: factory.switch({ defaultValue: false }),
grow: factory.switch({ defaultValue: false }),
customUrls: factory.internal({ defaultValue: [] as string[] }),
items: factory.sortableItemList<BookmarkSelectionItem, string>({
ItemComponent: ({ item, handle, removeItem, removeLabel, rootAttributes }) => {
+2 -14
View File
@@ -240,20 +240,8 @@ export const getBookmarkDisplayPlan = ({
};
}
if (layout === "gridHorizontal") {
return {
columns: Math.min(count, widthSettings.compactColumns),
horizontalScroll: false,
itemHeight: 56,
itemWidth: widthSettings.rowItemWidth,
orientation: "horizontal",
showHostname: widthSettings.showHostname && heightSettings.showHostname,
showTitle: widthSettings.showTitle && heightSettings.showTitle,
};
}
let columns: number = widthSettings.adaptiveColumns;
let orientation: BookmarkOrientation = widthSettings.adaptiveOrientation;
let columns: number = widthSettings.compactColumns;
let orientation: BookmarkOrientation = "horizontal";
if (layout === "grid") {
columns = widthSettings.gridColumns;
orientation = "vertical";