diff --git a/.env.example b/.env.example index d61111ebf..2dd98d36e 100644 --- a/.env.example +++ b/.env.example @@ -59,11 +59,11 @@ TURBO_TELEMETRY_DISABLED=1 # ENABLE_KUBERNETES=true # Enable mock integration -UNSAFE_ENABLE_MOCK_INTEGRATION=true +# UNSAFE_ENABLE_MOCK_INTEGRATION=true # Community workshop (PocketBase) base URL used by the in-app "Install from Workshop" buttons # In production this defaults to https://store.homarr.dev — override for local dev: -NEXT_PUBLIC_WIDGET_STORE_URL=http://localhost:8090 +# NEXT_PUBLIC_WIDGET_STORE_URL=http://localhost:8090 # Docs site workshop URL used for "Open Workshop" links # In production this defaults to https://homarr.dev/workshop # NEXT_PUBLIC_WORKSHOP_URL=http://localhost:3003/workshop diff --git a/.opencode/changelog/2026-07-03.md b/.opencode/changelog/2026-07-03.md index 6b9faf096..866b9e783 100644 --- a/.opencode/changelog/2026-07-03.md +++ b/.opencode/changelog/2026-07-03.md @@ -8,3 +8,12 @@ - **Tests**: `pnpm lint` passed with warnings, `pnpm typecheck` passed, `pnpm exec vitest run apps/docs/src/lib/store-schema.spec.ts` passed. Full `pnpm test` failed on unrelated timeout/external-dependency tests: Immich icon fetch, Pi-hole container, MySQL migration, and Nextcloud hook. - **Docs**: Updated workshop management docs with a stronger safety warning and submission guidelines. - **Risks**: The commit includes a large required `dev` merge, so review should distinguish upstream merge changes from the scoped CodeRabbit fixes. + +## PR #5984 Additional CodeRabbit Fixes + +- **Why**: Resolve the remaining actionable CodeRabbit comments before requesting Copilot review. +- **What**: Commented out opt-in example env flags, pinned the PocketBase image, ignored store-local env files, documented PocketBase admin bootstrap vars, enabled GitHub OAuth only when credentials are present, indexed `comments.submission`, added reduced-motion handling for submit-step animation, added accessible comment action labels, used created vote records directly on detail pages, tracked copy-failure timers for cleanup, prevented screenshot carousel controls from navigating card links, and normalized the `useStore` utils import alias. +- **Files**: `.env.example`, `apps/store/docker-compose.yml`, `apps/store/.gitignore`, `apps/store/README.md`, `apps/store/pb_migrations/1750000000_init_store.js`, `apps/docs/src/css/custom.css`, `apps/docs/src/components/store/DetailPage.tsx`, `apps/docs/src/components/store/StoreApp.tsx`, `apps/docs/src/components/store/useStore.ts`. +- **Tests**: `pnpm --filter @homarr/docs typecheck`, `pnpm --filter @homarr/docs lint`, `pnpm --filter nextjs typecheck`, and `pnpm exec vitest run apps/docs/src/lib/store-schema.spec.ts` passed; docs lint still reports pre-existing warnings outside this fix set. +- **Docs**: Updated `apps/store/README.md` with admin bootstrap variables. +- **Risks**: PocketBase image pin assumes `ghcr.io/muchobien/pocketbase:0.26.2` remains the intended runtime version for this new store service. diff --git a/apps/docs/src/components/store/DetailPage.tsx b/apps/docs/src/components/store/DetailPage.tsx index 0dd5bf9b2..3ec1ce11b 100644 --- a/apps/docs/src/components/store/DetailPage.tsx +++ b/apps/docs/src/components/store/DetailPage.tsx @@ -29,7 +29,7 @@ import type { SubmissionType } from "@site/src/lib/store-schema"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { cn, errorMessage } from "@/lib/utils"; +import { cn, errorMessage } from "@site/src/lib/utils"; const typeLabels: Record = { css: "CSS", widget: "Widget" }; const typeDotColors: Record = { css: "bg-blue-500", widget: "bg-yellow-500" }; @@ -284,6 +284,7 @@ const CommentsSection = ({
-
@@ -378,6 +380,7 @@ const MarketplaceDetail = ({ storeUrl }: { storeUrl: string }) => { const [copied, setCopied] = useState(false); const [copyFailed, setCopyFailed] = useState(false); const copyTimer = useRef>(null); + const copyFailedTimer = useRef>(null); const voting = useRef(false); const requireUserId = useCallback( @@ -411,6 +414,7 @@ const MarketplaceDetail = ({ storeUrl }: { storeUrl: string }) => { useEffect( () => () => { if (copyTimer.current) clearTimeout(copyTimer.current); + if (copyFailedTimer.current) clearTimeout(copyFailedTimer.current); }, [], ); @@ -485,11 +489,10 @@ const MarketplaceDetail = ({ storeUrl }: { storeUrl: string }) => { try { if (!prev) { - await pb.collection("votes").create({ submission: submission.id, value, user: userId }); - const votes = await pb.collection("votes").getFullList({ - filter: pb.filter("user = {:uid} && submission = {:sid}", { uid: userId, sid: submission.id }), - }); - setUserVote(votes[0]); + const created = await pb + .collection("votes") + .create({ submission: submission.id, value, user: userId }); + setUserVote(created); } else if (isToggleOff) { await pb.collection("votes").delete(prev.id); } else { @@ -521,10 +524,12 @@ const MarketplaceDetail = ({ storeUrl }: { storeUrl: string }) => { setCopied(true); setCopyFailed(false); if (copyTimer.current) clearTimeout(copyTimer.current); + if (copyFailedTimer.current) clearTimeout(copyFailedTimer.current); copyTimer.current = setTimeout(() => setCopied(false), 1500); } catch { setCopyFailed(true); - setTimeout(() => setCopyFailed(false), 2000); + if (copyFailedTimer.current) clearTimeout(copyFailedTimer.current); + copyFailedTimer.current = setTimeout(() => setCopyFailed(false), 2000); } }; diff --git a/apps/docs/src/components/store/StoreApp.tsx b/apps/docs/src/components/store/StoreApp.tsx index b40bf098a..1d934183e 100644 --- a/apps/docs/src/components/store/StoreApp.tsx +++ b/apps/docs/src/components/store/StoreApp.tsx @@ -87,6 +87,11 @@ const downloadJson = (s: StoreSubmission) => { URL.revokeObjectURL(url); }; +const stopCardNavigation = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); +}; + export const StoreApp = ({ storeUrl }: { storeUrl: string }) => { const store = useStore(storeUrl); const [typeFilter, setTypeFilter] = useState("all"); @@ -496,14 +501,20 @@ const ScreenshotGallery = ({ urls, title }: { urls: string[]; title: string }) = <>