Keep today close: signals first, controls beside them, distractions out.
Backups verified
Review active alerts
Connect your everyday services
Tune this board to your routine
Make it yours. Keep it useful.
`, + }, }, - // Row 3: mediaServer + mediaTranscoding + dnsHoleSummary = 12 - { kind: "mediaServer", width: 3, height: 2, needsIntegration: true }, - { kind: "mediaTranscoding", width: 3, height: 2, needsIntegration: true }, - { kind: "dnsHoleSummary", width: 6, height: 2, needsIntegration: true }, - // Row 4: dnsHoleControls + mediaReleases + notifications = 12 - { kind: "dnsHoleControls", width: 2, height: 1, needsIntegration: true }, - { kind: "mediaReleases", width: 4, height: 2, needsIntegration: true }, - { kind: "notifications", width: 6, height: 2, needsIntegration: true }, - // Row 5: requestList + requestStats + indexerManager = 12 - { kind: "mediaRequests-requestList", width: 4, height: 3, needsIntegration: true }, - { kind: "mediaRequests-requestStats", width: 4, height: 2, needsIntegration: true }, - { kind: "indexerManager", width: 4, height: 2, needsIntegration: true }, - // Row 6: networkControllerSummary + networkControllerStatus + rssFeed = 12 - { kind: "networkControllerSummary", width: 3, height: 2, needsIntegration: true }, - { kind: "networkControllerStatus", width: 3, height: 2, needsIntegration: true }, + { kind: "beszelSystemGrid", xOffset: 5, yOffset: 2, width: 4, height: 3, needsIntegration: true }, + { kind: "assistant", xOffset: 9, yOffset: 2, width: 3, height: 3, needsIntegration: false }, + + // Around the centered network container + { kind: "mediaRequests-requestList", xOffset: 0, yOffset: 5, width: 3, height: 2, needsIntegration: true }, + { kind: "mediaMissing", xOffset: 9, yOffset: 5, width: 3, height: 2, needsIntegration: true }, + { kind: "mediaServer", xOffset: 0, yOffset: 7, width: 3, height: 2, needsIntegration: true }, + { kind: "mediaRequests-requestStats", xOffset: 9, yOffset: 7, width: 3, height: 2, needsIntegration: true }, { kind: "rssFeed", - width: 6, + xOffset: 0, + yOffset: 9, + width: 3, height: 2, needsIntegration: false, options: { feedUrls: ["https://selfh.st/rss/", "https://hnrss.org/newest?q=self-hosted"], - maximumAmountPosts: 20, + maximumAmountPosts: 12, textLinesClamp: 2, - hideDescription: false, + hideDescription: true, }, }, - // Row 7-8: app widgets (2x1 each, 6 per row = 12) + { kind: "indexerManager", xOffset: 9, yOffset: 9, width: 3, height: 2, needsIntegration: true }, + + // Infrastructure and activity + { kind: "dockerContainers", xOffset: 0, yOffset: 11, width: 4, height: 3, needsIntegration: false }, + { kind: "mediaReleases", xOffset: 4, yOffset: 11, width: 4, height: 3, needsIntegration: true }, + + // Community Workshop + { + kind: "customApi", + xOffset: 8, + yOffset: 11, + width: 4, + height: 3, + needsIntegration: false, + options: { definitionId: customWidgetDefinitionId, refreshInterval: 300 }, + }, + + // Network stuff container + { + kind: "healthMonitoring", + section: "network", + xOffset: 0, + yOffset: 0, + width: 6, + height: 2, + needsIntegration: true, + }, + { + kind: "dnsHoleSummary", + section: "network", + xOffset: 0, + yOffset: 2, + width: 3, + height: 2, + needsIntegration: true, + options: { layout: "grid", usePiHoleColors: false }, + }, + { + kind: "beszelSystemStats", + section: "network", + xOffset: 3, + yOffset: 2, + width: 3, + height: 2, + needsIntegration: true, + }, + { kind: "notifications", section: "network", xOffset: 0, yOffset: 4, width: 2, height: 2, needsIntegration: true }, + { kind: "beszelAlerts", section: "network", xOffset: 2, yOffset: 4, width: 4, height: 2, needsIntegration: true }, + + // Right app rail ...appIds.map( - (appId): DemoWidget => ({ + (appId, index): DemoWidget => ({ kind: "app", - width: 2, + section: "right", + xOffset: 0, + yOffset: index, + width: 1, height: 1, needsIntegration: false, options: { appId, openInNewTab: true, showTitle: true, pingEnabled: false }, }), ), - // Row 9: beszelSystemGrid + beszelAlerts = 12 - { kind: "beszelSystemGrid", width: 8, height: 3, needsIntegration: true }, - { kind: "beszelAlerts", width: 4, height: 3, needsIntegration: true }, - // Row 10: beszelSystemTable + beszelSystemStats = 12 - { kind: "beszelSystemTable", width: 6, height: 3, needsIntegration: true }, - { kind: "beszelSystemStats", width: 6, height: 4, needsIntegration: true }, - // Row 11: notebook + dockerContainers + weather = 12 - { kind: "notebook", width: 4, height: 4, needsIntegration: false }, - { kind: "dockerContainers", width: 6, height: 2, needsIntegration: false }, - { kind: "weather", width: 2, height: 1, needsIntegration: false }, - // Row 12: assistant - { kind: "assistant", width: 3, height: 3, needsIntegration: false }, ]; const seedDemoUserAsync = async (db: Database) => { @@ -710,44 +810,128 @@ const seedDemoUserAsync = async (db: Database) => { }); } + const customWidgetDefinitionId = createId(); + const customWidgetDefinition = customWidgetDefinitionSchema.parse({ + $schema: "homarr-custom-widget-v2", + name: "Community Workshop", + description: "Live Custom Widget and Custom CSS submissions shared by the Homarr community.", + sources: { + default: { + name: "Homarr Workshop", + baseUrl: "https://v2.preview.homarr.dev", + networkScope: "public", + auth: "none", + }, + }, + requests: { + workshop: { + path: "/api/collections/workshop_listings/records", + query: { perPage: 50 }, + cacheSeconds: 300, + }, + }, + options: {}, + template: `