Compare commits

..
Author SHA1 Message Date
ajnart 04d01e3aa0 docs(apps): clarify ping URL only accepts http/https 2026-08-05 17:37:06 +02:00
ajnart 292dfbed8c style: auto-fix lint and format 2026-08-05 12:28:14 +00:00
ajnart 00fad39792 feat(apps): allow custom URI schemes in application links
Remove URL validation from app href field to support custom URI
schemes like vscode://, microsoft-edge:https://, and myapp://open.
Only javascript: URIs remain blocked for security.

Closes #6520
2026-08-05 14:25:53 +02:00
Thomas 778533a62e fix: revert regressions from recent integration/releases/app-href changes (#6514) 2026-08-03 17:37:53 +02:00
Thomas b4fba47a23 fix(releases): add success flag to successful response for correct error detection (#6512) 2026-08-03 17:10:35 +02:00
Thomas 76ddfceb13 fix: restore auto-refresh for docker and notifications widgets (#6511) 2026-08-03 17:07:46 +02:00
Thomas 2f6b96e5ba feat: restrict integrations management to integration-full-all permission (#6509) 2026-08-03 17:04:35 +02:00
Thomas f1b7a5146a fix: allow [homarr_base] template variables in app href validation (#6508) 2026-08-03 16:47:40 +02:00
Thomas Camlong 05292ae1f5 fix: map legacy media server options 2026-08-03 15:24:30 +02:00
homarr-renovate[bot] 48fc8db2b4 chore(deps): update semantic-release monorepo (major) (#6486) 2026-08-03 14:39:28 +02:00
Thomas 018f84f80d feat(dev): add Docker development CLI (#6495) 2026-08-03 14:38:56 +02:00
Thomas d58a47b776 fix: restrict system health monitoring integrations (#6505) 2026-08-02 10:17:05 +02:00
10 changed files with 1008 additions and 1064 deletions

No files matched your search

+3
View File
@@ -40,11 +40,14 @@ An optional description that can be shown as tooltip on the app widget.
The URL to the website you want to link to. Clicking on the app widget or bookmark will open this URL. The URL to the website you want to link to. Clicking on the app widget or bookmark will open this URL.
You can also use custom URI schemes such as `vscode://file/path`, `microsoft-edge:https://example.com`, or `myapp://open` to link to local applications or third-party programs. We trust that you know what you are doing — only `javascript:` URIs are blocked for security reasons.
### Ping URL ### Ping URL
When you want to use another url for the simple status check you can set it here. When you want to use another url for the simple status check you can set it here.
This will allow you to set a different URL for the ping than the URL that is opened when clicking on the app widget. This will allow you to set a different URL for the ping than the URL that is opened when clicking on the app widget.
It's useful when you want to ping the service internally for example with a custom ip but open the website externally. It's useful when you want to ping the service internally for example with a custom ip but open the website externally.
Note that the ping URL only accepts `http://` and `https://` URLs — custom URI schemes are not supported for pings.
## List of apps ## List of apps
+1 -1
View File
@@ -173,7 +173,7 @@ export const appRouter = createTRPCRouter({
mcp: { mcp: {
enabled: true, enabled: true,
description: description:
"Create a new app (bookmark/shortcut to a service). REQUIRED: name (string), iconUrl (icon URL string), href (app URL, http/https or blank). OPTIONAL: description (string or null), pingUrl (URL to check reachability, or empty string)", "Create a new app (bookmark/shortcut to a service). REQUIRED: name (string), iconUrl (icon URL string), href (app URL or custom URI scheme such as vscode://, or blank). OPTIONAL: description (string or null), pingUrl (URL to check reachability, or empty string)",
}, },
}) })
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
@@ -119,6 +119,7 @@ export type HomarrDocumentationPath =
| "/docs/tags/variables" | "/docs/tags/variables"
| "/docs/tags/widgets" | "/docs/tags/widgets"
| "/docs/advanced/command-line" | "/docs/advanced/command-line"
| "/docs/advanced/command-line/development"
| "/docs/advanced/command-line/fix-usernames" | "/docs/advanced/command-line/fix-usernames"
| "/docs/advanced/command-line/integrations" | "/docs/advanced/command-line/integrations"
| "/docs/advanced/command-line/password-recovery" | "/docs/advanced/command-line/password-recovery"
+2 -1
View File
@@ -442,7 +442,7 @@ export const integrationDefs = {
name: "Beszel", name: "Beszel",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/beszel.svg", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/beszel.svg",
category: ["healthMonitoring"], category: ["beszel"],
documentationUrl: createDocumentationLink("/docs/integrations/beszel"), documentationUrl: createDocumentationLink("/docs/integrations/beszel"),
defaultPort: 8090, defaultPort: 8090,
}, },
@@ -565,6 +565,7 @@ export const integrationCategories = [
"smartHomeServer", "smartHomeServer",
"indexerManager", "indexerManager",
"healthMonitoring", "healthMonitoring",
"beszel",
"search", "search",
"mediaTranscoding", "mediaTranscoding",
"networkController", "networkController",
@@ -148,6 +148,8 @@ const optionMapping: OptionMapping = {
}, },
mediaServer: { mediaServer: {
showOnlyPlaying: () => undefined, showOnlyPlaying: () => undefined,
showBitrate: () => undefined,
showLocation: () => undefined,
}, },
indexerManager: { indexerManager: {
openIndexerSiteInNewTab: (oldOptions) => oldOptions.openIndexerSiteInNewTab, openIndexerSiteInNewTab: (oldOptions) => oldOptions.openIndexerSiteInNewTab,
+1 -2
View File
@@ -3,8 +3,7 @@ import { z } from "zod/v4";
export const appHrefSchema = z export const appHrefSchema = z
.string() .string()
.trim() .trim()
.url() .refine((val) => !/^javascript:/i.test(val), "JavaScript URIs are not permitted")
.regex(/^(?!javascript)[a-zA-Z]*:\/\//i) // javascript: is not allowed, i for case insensitive (so Javascript: is also not allowed)
.or(z.literal("")) .or(z.literal(""))
.transform((value) => (value.length === 0 ? null : value)) .transform((value) => (value.length === 0 ? null : value))
.nullable(); .nullable();
+1
View File
@@ -26,6 +26,7 @@ const columnTranslationKeyMap = {
export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", { export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", {
icon: IconBrandDocker, icon: IconBrandDocker,
queryKey: [["docker", "getContainers"]], queryKey: [["docker", "getContainers"]],
refetchInterval: 30,
createOptions() { createOptions() {
return optionsBuilder.from( return optionsBuilder.from(
(factory) => ({ (factory) => ({
@@ -7,7 +7,6 @@ import { optionsBuilder } from "../options";
export const { componentLoader, definition } = createWidgetDefinition("notifications", { export const { componentLoader, definition } = createWidgetDefinition("notifications", {
icon: IconMessage, icon: IconMessage,
refetchInterval: null,
createOptions() { createOptions() {
return optionsBuilder.from((factory) => ({ return optionsBuilder.from((factory) => ({
hideLogos: factory.switch({ defaultValue: false }), hideLogos: factory.switch({ defaultValue: false }),
+995 -1057
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -37,9 +37,9 @@ catalog:
"@octokit/auth-app": ^8.2.0 "@octokit/auth-app": ^8.2.0
"@paralleldrive/cuid2": ^3.3.0 "@paralleldrive/cuid2": ^3.3.0
"@playwright/test": ^1.61.1 "@playwright/test": ^1.61.1
"@semantic-release/changelog": ^6.0.3 "@semantic-release/changelog": ^7.0.0
"@semantic-release/commit-analyzer": ^13.0.1 "@semantic-release/commit-analyzer": ^13.0.1
"@semantic-release/git": ^10.0.1 "@semantic-release/git": ^11.0.1
"@semantic-release/github": ^12.0.9 "@semantic-release/github": ^12.0.9
"@semantic-release/npm": ^13.1.5 "@semantic-release/npm": ^13.1.5
"@semantic-release/release-notes-generator": ^14.1.1 "@semantic-release/release-notes-generator": ^14.1.1