From 4f4a0dbd62fe24909aed5780d63a84b374ba262b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 21 Feb 2026 12:54:39 +0100 Subject: [PATCH] fix: resolve EACCES permission issue and hydration error #418 --- Dockerfile | 9 ++++--- src/db/index.ts | 2 +- src/features/grid/components/heatmap-grid.tsx | 26 +++++++++++++++++-- src/features/settings/actions.ts | 21 ++++++++++----- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1257cbd..49f1089 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,15 +37,18 @@ RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public -# Set the correct permission for prerender cache -RUN mkdir .next -RUN chown nextjs:nodejs .next +# Set the correct permission for prerender cache and data storage +RUN mkdir .next data +RUN chown nextjs:nodejs .next data # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +# Grant write access to /app for settings persistence +RUN chown -R nextjs:nodejs /app + USER nextjs EXPOSE 5643 diff --git a/src/db/index.ts b/src/db/index.ts index 17f8182..d836a55 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -8,7 +8,7 @@ let connectionString = process.env.DATABASE_URL; // On tente de lire la config sauvegardée via l'UI try { - const CONFIG_PATH = path.join(process.cwd(), ".db-config.json"); + const CONFIG_PATH = path.join(process.cwd(), "data", ".db-config.json"); if (fs.existsSync(CONFIG_PATH)) { const config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); if (config.url) { diff --git a/src/features/grid/components/heatmap-grid.tsx b/src/features/grid/components/heatmap-grid.tsx index a927ee1..48df866 100644 --- a/src/features/grid/components/heatmap-grid.tsx +++ b/src/features/grid/components/heatmap-grid.tsx @@ -31,7 +31,7 @@ function getLast12Months(): string[] { return months; } -const MONTHS_12 = getLast12Months(); +// La constante est supprimée d'ici pour éviter le mismatch d'hydratation (new Date() au runtime module) function formatMonthLabel(key: string): string { const m = parseInt(key.slice(4, 6), 10); @@ -47,10 +47,17 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { const { rows, draftChanges, setDraftGamme, filters, displayDensity } = useGridStore(); const [sorting, setSorting] = useState([]); const [rowSelection, setRowSelection] = useState({}); + const [isMounted, setIsMounted] = useState(false); const tableContainerRef = useRef(null); + // Calculer les mois dynamiquement pour éviter le mismatch entre serveur et client + const MONTHS_12 = useMemo(() => getLast12Months(), []); + + useEffect(() => { + setIsMounted(true); + }, []); + const rowHeight = displayDensity === "compact" ? 32 : displayDensity === "normal" ? 40 : 48; - const cellPadding = displayDensity === "compact" ? "py-1" : displayDensity === "normal" ? "py-1.5" : "py-2.5"; const handleRowSelectionChange = useCallback( (updater: React.SetStateAction) => { @@ -241,6 +248,21 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { const totalWidth = columns.reduce((s, c) => s + ((c as { size?: number }).size ?? 150), 0); + if (!isMounted) { + return ( +
+
Chargement de la grille...
+
+ ); + } + return (