diff --git a/.github/ISSUE_TEMPLATE/v2_beta_feedback.yml b/.github/ISSUE_TEMPLATE/v2_beta_feedback.yml index c403497dd..384c1a920 100644 --- a/.github/ISSUE_TEMPLATE/v2_beta_feedback.yml +++ b/.github/ISSUE_TEMPLATE/v2_beta_feedback.yml @@ -1,18 +1,12 @@ name: Homarr v2 beta feedback -description: Report a specific bug, unexpected behavior, or improvement for the Homarr v2 beta +description: Tell us what works, what breaks, or what could be clearer in the Homarr v2 beta title: "feedback(v2): " labels: ["needs triage"] body: - type: markdown attributes: value: | - Thanks for testing Homarr v2. It will become the default when it is ready, and every detailed report helps us get there. - - We cannot guess what you wanted from “this looks wrong.” Tell us exactly which feature is affected, what happened, why it is wrong for your use case, and what you expected instead. Add screenshots or a short recording whenever possible. - - **Not useful:** “The board looks wrong.” - - **Useful:** “The container changes from four columns to three after I move a widget at 1440 × 900 and 100% browser zoom. I expected it to keep four columns.” + Thanks for testing Homarr v2. It will become the default when it is ready, and every report helps us get there. - type: dropdown id: feedback-type @@ -31,100 +25,36 @@ body: id: version attributes: label: Homarr v2 version or image tag - description: Copy the version from the About page or provide the exact Docker image tag you tested. + description: You can find the version in the About page or provide the Docker image tag you tested. placeholder: ghcr.io/homarr-labs/homarr-test:v2 validations: required: true - - type: input - id: affected-area - attributes: - label: Affected page, feature, or widget - description: Name the exact page, widget, integration, container, sidebar, or action involved. - placeholder: Board editor — moving a widget into a container - validations: - required: true - - type: textarea - id: behavior + id: feedback attributes: - label: What happened, why is it wrong, and what should happen instead? - description: Describe the actual result, why it does not work for you, and the exact result you expected. - placeholder: | - What happened: - Why this is wrong for my use case: - What I expected instead: + label: What did you find? + description: Describe what happened, what you expected, or what you think could be improved. validations: required: true - type: textarea id: reproduction attributes: - label: Exact steps to reproduce - description: Start from the page you opened and list every click, keypress, drag, setting, and value needed to reproduce it. - placeholder: | - 1. Open... - 2. Set... - 3. Drag or click... - 4. Observe... - validations: - required: true - - - type: textarea - id: visual-evidence - attributes: - label: Screenshots or screen recordings - description: Drag screenshots or a recording into this field. Include the full page for context and a close-up of the problem. Blur secrets and personal data. If you cannot add visuals, explain why. - placeholder: Drag screenshots or a recording here, or explain why none are available. - validations: - required: true - - - type: textarea - id: environment - attributes: - label: Device and Homarr environment - description: Provide every detail that could affect the result. - placeholder: | - Device type and model: - Operating system and version: - Browser and version: - Installation method (Docker, Unraid, Kubernetes, other): - Database (SQLite, MySQL, PostgreSQL): - Reverse proxy and version, if used: - validations: - required: true - - - type: textarea - id: board-context - attributes: - label: Board and display context - description: Include the layout details even when you are not sure they matter. - placeholder: | - Display resolution: - Browser zoom: - Desktop or mobile layout: - Board column count: - Approximate number of items: - Container or sidebar nesting: - Relevant board or widget settings: - validations: - required: true + label: Steps to reproduce + description: For bugs, list the shortest steps that consistently reproduce the problem. - type: textarea id: additional-information attributes: - label: Logs and additional information - description: Add relevant browser console errors, Homarr logs, integration details, or anything else that may help. Remove secrets and personal information first. + label: Additional information + description: Add screenshots, logs, browser details, or anything else that may help. Remove secrets and personal information first. - type: checkboxes id: checks attributes: label: Before submitting options: - - label: I added screenshots or a recording where possible, or explained why I could not. - required: true - - label: I described both what happened and the exact result I expected. - required: true - label: I searched the existing issues for the same feedback. required: true - label: I removed passwords, API keys, tokens, and other private information. diff --git a/apps/docs/docs/getting-started/index.mdx b/apps/docs/docs/getting-started/index.mdx index 1033ba874..1a4722ff3 100644 --- a/apps/docs/docs/getting-started/index.mdx +++ b/apps/docs/docs/getting-started/index.mdx @@ -13,7 +13,7 @@ import { IconArrowRight } from '@tabler/icons-react'; :::info Homarr v2 beta is available -There is no release date yet: Homarr v2 will become the default when it is ready. Read [what is new](https://v2.preview.homarr.dev/blog), try the [hosted preview](https://app-v2.preview.homarr.dev), [join us on Discord](https://discord.com/invite/aCsmEV5RgA), and [share your feedback](https://github.com/homarr-labs/homarr/issues/new?template=v2_beta_feedback.yml). Everyone uses Homarr differently, so every report helps us find what breaks or does not feel right before release. SQLite administrators can download a full backup directly from the beta announcement before changing images. +There is no release date yet: Homarr v2 will become the default when it is ready. Read [what is new](https://v2.preview.homarr.dev/blog), try the [hosted preview](https://app-v2.preview.homarr.dev), [join us on Discord](https://discord.com/invite/aCsmEV5RgA), and [share your feedback](https://github.com/homarr-labs/homarr/issues/new?template=v2_beta_feedback.yml). Everyone uses Homarr differently, so every report helps us find what breaks or does not feel right before release. ::: diff --git a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx index bbe100e70..897563072 100644 --- a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx +++ b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx @@ -9,7 +9,6 @@ import { getRscUserSettingsAsync } from "@homarr/api/user-server"; import { auth } from "@homarr/auth/next"; import { BoardProvider } from "@homarr/boards/context"; import { EditModeProvider } from "@homarr/boards/edit-mode"; -import { dbEnv } from "@homarr/core/infrastructure/db/env"; import { createLogger } from "@homarr/core/infrastructure/logs"; import { v2BetaAnnouncementCookieKey } from "@homarr/definitions"; @@ -93,7 +92,6 @@ export const createBoardLayout = ({ const viewerHash = createHash("sha256").update(viewerIdentity).digest("hex").slice(0, 16); const dismissalCookieName = `${v2BetaAnnouncementCookieKey}.${viewerHash}`; const isAnnouncementDismissed = cookieStore.get(dismissalCookieName)?.value === "dismissed"; - const canExportBackup = dbEnv.DRIVER === "better-sqlite3" && Boolean(session?.user.permissions.includes("admin")); return ( @@ -103,7 +101,6 @@ export const createBoardLayout = ({ { const t = useScopedI18n("management.page.tool.backup.export"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showConfirm, setShowConfirm] = useState(false); + + const handleExport = async () => { + setLoading(true); + setError(null); + try { + const response = await fetch("/api/backup/export"); + if (!response.ok) { + const errorMessage = await response.json().then( + (data) => data.error, + () => `Server returned ${response.status}`, + ); + throw new Error(errorMessage ?? t("error")); + } + + const blob = await response.blob(); + const url = URL.createObjectURL(blob); + const filename = + response.headers.get("Content-Disposition")?.match(/filename="(.+)"/)?.[1] ?? "homarr-backup.zip"; + + const a = document.createElement("a"); + a.href = url; + a.download = filename; + a.click(); + URL.revokeObjectURL(url); + setShowConfirm(false); + } catch (err) { + setError(err instanceof Error ? err.message : t("error")); + } finally { + setLoading(false); + } + }; return ( @@ -20,7 +55,33 @@ export const BackupExportCard = () => { {t("description")} - + {error && ( + }> + {error} + + )} + + {showConfirm ? ( + } + cancelLabel={t("confirm.cancel")} + onConfirm={handleExport} + onCancel={() => setShowConfirm(false)} + disabled={loading} + color="orange" + /> + ) : ( + + + + )} ); diff --git a/apps/nextjs/src/components/backup/backup-export-button.tsx b/apps/nextjs/src/components/backup/backup-export-button.tsx deleted file mode 100644 index 6116d0a16..000000000 --- a/apps/nextjs/src/components/backup/backup-export-button.tsx +++ /dev/null @@ -1,79 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { Alert, Button, Group, Stack } from "@mantine/core"; -import { IconAlertTriangle, IconDownload } from "@tabler/icons-react"; - -import { useScopedI18n } from "@homarr/translation/client"; - -import { DangerousActionConfirmation } from "./dangerous-action-confirmation"; - -export const BackupExportButton = () => { - const t = useScopedI18n("management.page.tool.backup.export"); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [showConfirm, setShowConfirm] = useState(false); - - const handleExport = async () => { - setLoading(true); - setError(null); - try { - const response = await fetch("/api/backup/export"); - if (!response.ok) { - const errorMessage = await response.json().then( - (data) => data.error, - () => `Server returned ${response.status}`, - ); - throw new Error(errorMessage ?? t("error")); - } - - const blob = await response.blob(); - const url = URL.createObjectURL(blob); - const filename = - response.headers.get("Content-Disposition")?.match(/filename="(.+)"/)?.[1] ?? "homarr-backup.zip"; - - const anchor = document.createElement("a"); - anchor.href = url; - anchor.download = filename; - anchor.click(); - URL.revokeObjectURL(url); - setShowConfirm(false); - } catch (cause) { - setError(cause instanceof Error ? cause.message : t("error")); - } finally { - setLoading(false); - } - }; - - return ( - - {error && ( - }> - {error} - - )} - - {showConfirm ? ( - } - cancelLabel={t("confirm.cancel")} - onConfirm={handleExport} - onCancel={() => setShowConfirm(false)} - disabled={loading} - color="orange" - /> - ) : ( - - - - )} - - ); -}; diff --git a/apps/nextjs/src/components/backup/index.ts b/apps/nextjs/src/components/backup/index.ts index 1f6196125..accd1a935 100644 --- a/apps/nextjs/src/components/backup/index.ts +++ b/apps/nextjs/src/components/backup/index.ts @@ -1,4 +1,3 @@ -export { BackupExportButton } from "./backup-export-button"; export { DatabaseRestoreFlow } from "./database-restore-flow"; export { DangerousActionConfirmation } from "./dangerous-action-confirmation"; export type { BackupAnalysis, RestoreStep } from "./types"; diff --git a/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.module.css b/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.module.css index 8939f335d..bb3f45508 100644 --- a/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.module.css +++ b/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.module.css @@ -50,6 +50,11 @@ transform: rotate(5deg); } +.featureCard { + height: 100%; + background: light-dark(var(--mantine-color-white), var(--mantine-color-dark-7)); +} + .diffViewer { overflow: hidden; } diff --git a/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.tsx b/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.tsx index de73cf45f..50f36d4d5 100644 --- a/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.tsx +++ b/apps/nextjs/src/components/layout/v2-beta-announcement/v2-beta-announcement.tsx @@ -1,10 +1,8 @@ "use client"; import type { ReactNode } from "react"; -import { useState } from "react"; import { ActionIcon, - Accordion, Alert, Box, Button, @@ -24,7 +22,6 @@ import { IconBrandGithub, IconCheck, IconCopy, - IconDatabaseExport, IconExternalLink, IconHeartHandshake, IconRobot, @@ -37,7 +34,6 @@ import { import { setClientCookie } from "@homarr/common"; import { createModal, useModalAction } from "@homarr/modals"; -import { BackupExportButton } from "~/components/backup"; import { discordInviteUrl, v2BetaBlogUrl, v2BetaDiscussionUrl, v2BetaFeedbackUrl, v2BetaPreviewUrl } from "./constants"; import classes from "./v2-beta-announcement.module.css"; @@ -58,7 +54,7 @@ const composeDiffLines = [ { kind: "context", value: " - homarr-v2:/appdata" }, { kind: "context", value: " environment:" }, { kind: "context", value: " SECRET_ENCRYPTION_KEY: " }, - { kind: "added", value: "+ WORKSHOP_API_URL: https://v2.preview.homarr.dev/ # Only during the beta" }, + { kind: "context", value: " WORKSHOP_API_URL: https://v2.preview.homarr.dev/ # Only during the beta" }, { kind: "context", value: "" }, { kind: "context", value: " volumes:" }, { kind: "context", value: " homarr-v2:" }, @@ -80,12 +76,11 @@ volumes: `; interface V2BetaAnnouncementProps { - canExportBackup: boolean; dismissalCookieName: string; onDismiss: () => void; } -export const V2BetaAnnouncement = ({ canExportBackup, dismissalCookieName, onDismiss }: V2BetaAnnouncementProps) => { +export const V2BetaAnnouncement = ({ dismissalCookieName, onDismiss }: V2BetaAnnouncementProps) => { const { openModal } = useModalAction(V2BetaAnnouncementModal); const dismiss = () => { @@ -112,7 +107,7 @@ export const V2BetaAnnouncement = ({ canExportBackup, dismissalCookieName, onDis - @@ -124,12 +119,8 @@ export const V2BetaAnnouncement = ({ canExportBackup, dismissalCookieName, onDis ); }; -interface V2BetaAnnouncementModalProps { - canExportBackup: boolean; -} - -const V2BetaAnnouncementModal = createModal(({ innerProps }) => { - const [openedSection, setOpenedSection] = useState("workshop"); +const V2BetaAnnouncementModal = createModal(() => { + const { openModal: openInstallModal } = useModalAction(V2BetaInstallModal); return ( @@ -143,51 +134,27 @@ const V2BetaAnnouncementModal = createModal(({ inn - - } title="Homarr Workshop"> + + } title="Homarr Workshop"> Share and discover Custom Widgets and CSS made by the Homarr community. - - } - title="Complete drag-and-drop rewrite" - > + + } title="Complete drag-and-drop rewrite"> Move, resize, multi-select, and arrange your dashboard with a board editor rebuilt from the ground up. - - } title="Custom Widgets v2"> + + } title="Custom Widgets v2"> We think you can make almost any widget with live previews, API requests, options, actions, and validation. - - } title="Homarr Assistant"> + + } title="Homarr Assistant"> Ask questions, find what you need, and manage Homarr through permission-aware tools. - - - - - - } - aria-label="Test Homarr v2 on your server" - > - - Test Homarr v2 on your server - - Back up this instance, then update your Docker Compose file. - - - - - - - - + + } title="Your testing is essential"> Everyone uses Homarr in a different way. We’re counting on you to tell us anything that breaks or doesn’t feel right with this new version. Every report matters. - + +