From 2f276e04b06b9646e64fc17d486c56b38ecbab3f Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 13:57:51 +0100 Subject: [PATCH 01/28] Implement version selector state persistence and URL updates in Content component --- xp-archive/client/content/Content.tsx | 48 +++++++++++++--- .../versionSelector/VersionSelector.tsx | 56 ++++++++++++++++++- 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 2702491..fa6e15f 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -18,10 +18,8 @@ const getDefaultView = (isWebpage: boolean, hasAttachment: boolean): ViewVariant return undefined; }; -const updateContentUrl = (nodeId: string, locale: string, versionId?: string) => { - const newUrl = `${xpArchiveConfig.basePath}/${nodeId}/${locale}/${versionId ?? ''}`; - window.history.pushState({}, '', newUrl); -}; +// Storage key for persisting version selector state +const STORAGE_KEY = 'versionSelector_state'; export const Content = () => { const { selectedContentId, selectedLocale, selectedVersion, setSelectedVersion } = @@ -44,11 +42,13 @@ export const Content = () => { useEffect(() => { if (selectedVersion) { - updateContentUrl(selectedContentId ?? '', selectedLocale, selectedVersion); + const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${selectedVersion}`; + window.history.replaceState({}, '', newUrl); } else if (data?.versions?.[0]) { const latestVersionId = data.versions[0].versionId; setSelectedVersion(latestVersionId); - updateContentUrl(selectedContentId ?? '', selectedLocale, latestVersionId); + const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${latestVersionId}`; + window.history.replaceState({}, '', newUrl); } }, [data, selectedContentId, selectedLocale, selectedVersion]); @@ -57,7 +57,41 @@ export const Content = () => { const [selectedView, setSelectedView] = useState( getDefaultView(isWebpage, hasAttachment) ); - const [isVersionPanelOpen, setIsVersionPanelOpen] = useState(false); + + // Initialize version panel state from localStorage + const [isVersionPanelOpen, setIsVersionPanelOpen] = useState(() => { + try { + const savedState = localStorage.getItem(STORAGE_KEY); + if (savedState) { + const { keepOpen } = JSON.parse(savedState); + return !!keepOpen; + } + } catch (e) { + console.error('Failed to load version selector state', e); + } + return false; + }); + + // Check localStorage when data changes to see if we should keep panel open + useEffect(() => { + if (data) { + try { + const savedState = localStorage.getItem(STORAGE_KEY); + if (savedState) { + const { keepOpen } = JSON.parse(savedState); + if (keepOpen) { + setIsVersionPanelOpen(true); + // Clear the keepOpen flag after opening + const updatedState = JSON.parse(savedState); + updatedState.keepOpen = false; + localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState)); + } + } + } catch (e) { + console.error('Failed to load version selector state', e); + } + } + }, [data]); useEffect(() => { setSelectedView(getDefaultView(isWebpage, hasAttachment)); diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index 5a77e4f..1bb1e5b 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { Heading, Button, Search } from '@navikt/ds-react'; import { VersionReference } from 'shared/types'; import { formatTimestamp } from '@common/shared/timestamp'; @@ -32,12 +32,49 @@ const VersionButton = ({ isSelected, onClick, children }: VersionButtonProps) => ); +// Storage key for persisting version selector state +const STORAGE_KEY = 'versionSelector_state'; + export const VersionSelector = ({ versions, isOpen, onClose }: Props) => { const [searchQuery, setSearchQuery] = useState(''); const { setSelectedContentId, selectedVersion, setSelectedVersion } = useAppState(); + // Load search query from localStorage on mount + useEffect(() => { + if (isOpen) { + try { + const savedState = localStorage.getItem(STORAGE_KEY); + if (savedState) { + const { searchQuery: savedQuery } = JSON.parse(savedState); + if (savedQuery) { + setSearchQuery(savedQuery); + } + } + } catch (e) { + console.error('Failed to load version selector state', e); + } + } + }, [isOpen]); + + // Save state to localStorage when it changes + useEffect(() => { + if (isOpen) { + try { + localStorage.setItem( + STORAGE_KEY, + JSON.stringify({ + searchQuery, + selectedVersion, + }) + ); + } catch (e) { + console.error('Failed to save version selector state', e); + } + } + }, [isOpen, searchQuery, selectedVersion]); + const handleClose = () => { - setSearchQuery(''); + // Don't clear search query when closing onClose(); }; @@ -45,7 +82,20 @@ export const VersionSelector = ({ versions, isOpen, onClose }: Props) => { const nodeId = versions.find((v) => v.versionId === versionId)?.nodeId; if (nodeId) setSelectedContentId(nodeId); setSelectedVersion(versionId); - handleClose(); + + // Save selected version to localStorage + try { + localStorage.setItem( + STORAGE_KEY, + JSON.stringify({ + searchQuery, + selectedVersion: versionId, + keepOpen: true, // Flag to keep panel open + }) + ); + } catch (e) { + console.error('Failed to save version selection', e); + } }; const filteredVersions = versions.filter((version) => From e982a01bf64d25e39876e8d81c90943b13617522 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 14:04:18 +0100 Subject: [PATCH 02/28] Refactor version selector state management in Content component and introduce caching mechanism - Replace localStorage usage with a caching system for version selector state. - Update version selector to utilize cached state and handle component mounting. - Enhance VersionSelector component to support onMount callback for caching rendered instances. --- xp-archive/client/content/Content.tsx | 90 +++++++++++-------- .../versionSelector/VersionSelector.tsx | 39 +++++++- .../versionSelector/VersionSelectorCache.tsx | 23 +++++ 3 files changed, 116 insertions(+), 36 deletions(-) create mode 100644 xp-archive/client/versionSelector/VersionSelectorCache.tsx diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index fa6e15f..c22178f 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -9,6 +9,10 @@ import { VersionSelector } from 'client/versionSelector/VersionSelector'; import { ContentView } from '../contentView/ContentView'; import { formatTimestamp } from '@common/shared/timestamp'; import { EmptyState } from '@common/shared/EmptyState/EmptyState'; +import { + setCachedVersionSelector, + getCachedVersionSelector, +} from 'client/versionSelector/VersionSelectorCache'; import style from './Content.module.css'; @@ -58,40 +62,28 @@ export const Content = () => { getDefaultView(isWebpage, hasAttachment) ); - // Initialize version panel state from localStorage - const [isVersionPanelOpen, setIsVersionPanelOpen] = useState(() => { - try { - const savedState = localStorage.getItem(STORAGE_KEY); - if (savedState) { - const { keepOpen } = JSON.parse(savedState); - return !!keepOpen; - } - } catch (e) { - console.error('Failed to load version selector state', e); - } - return false; + // Get cached state or initialize + const [versionSelectorCache, setVersionSelectorCache] = useState(() => { + const cache = getCachedVersionSelector(); + return { + component: cache.component, + versions: cache.versions, + isOpen: cache.isOpen, + }; }); - // Check localStorage when data changes to see if we should keep panel open + // Update the cache when versions change useEffect(() => { - if (data) { - try { - const savedState = localStorage.getItem(STORAGE_KEY); - if (savedState) { - const { keepOpen } = JSON.parse(savedState); - if (keepOpen) { - setIsVersionPanelOpen(true); - // Clear the keepOpen flag after opening - const updatedState = JSON.parse(savedState); - updatedState.keepOpen = false; - localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState)); - } - } - } catch (e) { - console.error('Failed to load version selector state', e); + if (data?.versions && data.versions.length > 0) { + // Only update versions in cache if we don't have any yet + if (versionSelectorCache.versions.length === 0) { + setVersionSelectorCache((prev) => ({ + ...prev, + versions: data.versions, + })); } } - }, [data]); + }, [data?.versions]); useEffect(() => { setSelectedView(getDefaultView(isWebpage, hasAttachment)); @@ -125,15 +117,43 @@ export const Content = () => { variant={'secondary'} icon={} iconPosition={'right'} - onClick={() => setIsVersionPanelOpen(true)} + onClick={() => { + setVersionSelectorCache((prev) => ({ + ...prev, + isOpen: true, + })); + }} > {getVersionDisplay()} - setIsVersionPanelOpen(false)} - /> + + {/* Use the cached component if available */} + {versionSelectorCache.component || ( + 0 + ? versionSelectorCache.versions + : data?.versions || [] + } + isOpen={versionSelectorCache.isOpen} + onClose={() => { + setVersionSelectorCache((prev) => ({ + ...prev, + isOpen: false, + })); + }} + onMount={(component) => { + // Cache the rendered component + setCachedVersionSelector( + component, + versionSelectorCache.versions.length > 0 + ? versionSelectorCache.versions + : data?.versions || [], + versionSelectorCache.isOpen + ); + }} + /> + )}
diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index 1bb1e5b..a4d26e4 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -12,6 +12,7 @@ type Props = { versions: VersionReference[]; isOpen: boolean; onClose: () => void; + onMount?: (component: React.ReactNode) => void; }; type VersionButtonProps = { @@ -35,7 +36,7 @@ const VersionButton = ({ isSelected, onClick, children }: VersionButtonProps) => // Storage key for persisting version selector state const STORAGE_KEY = 'versionSelector_state'; -export const VersionSelector = ({ versions, isOpen, onClose }: Props) => { +export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) => { const [searchQuery, setSearchQuery] = useState(''); const { setSelectedContentId, selectedVersion, setSelectedVersion } = useAppState(); @@ -102,6 +103,42 @@ export const VersionSelector = ({ versions, isOpen, onClose }: Props) => { formatTimestamp(version.timestamp).toLowerCase().includes(searchQuery.toLowerCase()) ); + // Call onMount with the rendered component + useEffect(() => { + if (onMount) { + const component = ( + + + Versjoner + + +
+ {filteredVersions.map((version, index) => ( + selectVersion(version.versionId)} + > + {formatTimestamp(version.timestamp)} + {index === 0 && ( + (Siste versjon) + )} + + ))} +
+
+ ); + onMount(component); + } + }, [versions, isOpen, searchQuery, selectedVersion]); + + // Return the same component return ( diff --git a/xp-archive/client/versionSelector/VersionSelectorCache.tsx b/xp-archive/client/versionSelector/VersionSelectorCache.tsx new file mode 100644 index 0000000..d5e1a44 --- /dev/null +++ b/xp-archive/client/versionSelector/VersionSelectorCache.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { VersionReference } from 'shared/types'; + +// Global cache for the version selector component +let cachedVersionSelector: React.ReactNode | null = null; +let cachedVersions: VersionReference[] = []; +let cachedIsOpen = false; + +export const setCachedVersionSelector = ( + component: React.ReactNode, + versions: VersionReference[], + isOpen: boolean +) => { + cachedVersionSelector = component; + cachedVersions = versions; + cachedIsOpen = isOpen; +}; + +export const getCachedVersionSelector = () => ({ + component: cachedVersionSelector, + versions: cachedVersions, + isOpen: cachedIsOpen, +}); From d60d2212660f329171467ba2fdb96d6ede9a6761 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 14:18:38 +0100 Subject: [PATCH 03/28] Enhance version selector caching and state management in Content component - Introduce content-specific caching for version selector state. - Clear cache when content ID changes to ensure accurate state management. - Update localStorage handling to use dynamic storage keys based on content ID. --- xp-archive/client/content/Content.tsx | 16 ++++++- .../versionSelector/VersionSelector.tsx | 16 +++---- .../versionSelector/VersionSelectorCache.tsx | 42 +++++++++++++------ 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index c22178f..4104c30 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -12,6 +12,7 @@ import { EmptyState } from '@common/shared/EmptyState/EmptyState'; import { setCachedVersionSelector, getCachedVersionSelector, + clearCachedVersionSelector, } from 'client/versionSelector/VersionSelectorCache'; import style from './Content.module.css'; @@ -64,7 +65,7 @@ export const Content = () => { // Get cached state or initialize const [versionSelectorCache, setVersionSelectorCache] = useState(() => { - const cache = getCachedVersionSelector(); + const cache = getCachedVersionSelector(selectedContentId || ''); return { component: cache.component, versions: cache.versions, @@ -72,6 +73,16 @@ export const Content = () => { }; }); + // Clear cache when content changes + useEffect(() => { + // When content ID changes, reset the cache for the previous content + return () => { + if (selectedContentId) { + clearCachedVersionSelector(selectedContentId); + } + }; + }, [selectedContentId]); + // Update the cache when versions change useEffect(() => { if (data?.versions && data.versions.length > 0) { @@ -143,8 +154,9 @@ export const Content = () => { })); }} onMount={(component) => { - // Cache the rendered component + // Cache the rendered component with the content ID setCachedVersionSelector( + selectedContentId || '', component, versionSelectorCache.versions.length > 0 ? versionSelectorCache.versions diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index a4d26e4..99e86c1 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -34,17 +34,19 @@ const VersionButton = ({ isSelected, onClick, children }: VersionButtonProps) => ); // Storage key for persisting version selector state -const STORAGE_KEY = 'versionSelector_state'; +const getStorageKey = (contentId: string) => `versionSelector_state_${contentId}`; export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) => { const [searchQuery, setSearchQuery] = useState(''); - const { setSelectedContentId, selectedVersion, setSelectedVersion } = useAppState(); + const { setSelectedContentId, selectedVersion, setSelectedVersion, selectedContentId } = + useAppState(); + const storageKey = getStorageKey(selectedContentId || ''); // Load search query from localStorage on mount useEffect(() => { if (isOpen) { try { - const savedState = localStorage.getItem(STORAGE_KEY); + const savedState = localStorage.getItem(storageKey); if (savedState) { const { searchQuery: savedQuery } = JSON.parse(savedState); if (savedQuery) { @@ -55,14 +57,14 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = console.error('Failed to load version selector state', e); } } - }, [isOpen]); + }, [isOpen, storageKey]); // Save state to localStorage when it changes useEffect(() => { if (isOpen) { try { localStorage.setItem( - STORAGE_KEY, + storageKey, JSON.stringify({ searchQuery, selectedVersion, @@ -72,7 +74,7 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = console.error('Failed to save version selector state', e); } } - }, [isOpen, searchQuery, selectedVersion]); + }, [isOpen, searchQuery, selectedVersion, storageKey]); const handleClose = () => { // Don't clear search query when closing @@ -87,7 +89,7 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = // Save selected version to localStorage try { localStorage.setItem( - STORAGE_KEY, + storageKey, JSON.stringify({ searchQuery, selectedVersion: versionId, diff --git a/xp-archive/client/versionSelector/VersionSelectorCache.tsx b/xp-archive/client/versionSelector/VersionSelectorCache.tsx index d5e1a44..cf05bd7 100644 --- a/xp-archive/client/versionSelector/VersionSelectorCache.tsx +++ b/xp-archive/client/versionSelector/VersionSelectorCache.tsx @@ -1,23 +1,41 @@ import React from 'react'; import { VersionReference } from 'shared/types'; -// Global cache for the version selector component -let cachedVersionSelector: React.ReactNode | null = null; -let cachedVersions: VersionReference[] = []; -let cachedIsOpen = false; +// Content-specific cache for the version selector component +const contentCache: Record< + string, + { + component: React.ReactNode | null; + versions: VersionReference[]; + isOpen: boolean; + } +> = {}; export const setCachedVersionSelector = ( + contentId: string, component: React.ReactNode, versions: VersionReference[], isOpen: boolean ) => { - cachedVersionSelector = component; - cachedVersions = versions; - cachedIsOpen = isOpen; + contentCache[contentId] = { + component, + versions, + isOpen, + }; }; -export const getCachedVersionSelector = () => ({ - component: cachedVersionSelector, - versions: cachedVersions, - isOpen: cachedIsOpen, -}); +export const getCachedVersionSelector = (contentId: string) => { + return ( + contentCache[contentId] || { + component: null, + versions: [], + isOpen: false, + } + ); +}; + +export const clearCachedVersionSelector = (contentId: string) => { + if (contentId in contentCache) { + delete contentCache[contentId]; + } +}; From 34bd8822fd7ecb1f1d29639e392411132111a5f0 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 14:26:55 +0100 Subject: [PATCH 04/28] Refactor cache management in Content and VersionSelector components - Update cache clearing logic to immediately clear previous content ID when it changes. - Reset local cache state when content ID changes to ensure accurate version data. - Add effect to reset search query in VersionSelector when input versions change. --- xp-archive/client/content/Content.tsx | 36 +++++++++---------- .../versionSelector/VersionSelector.tsx | 12 +++++++ .../versionSelector/VersionSelectorCache.tsx | 7 ++++ 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 4104c30..d66d304 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -73,28 +73,26 @@ export const Content = () => { }; }); - // Clear cache when content changes + // Update this effect to clear the cache immediately when content ID changes useEffect(() => { - // When content ID changes, reset the cache for the previous content - return () => { - if (selectedContentId) { - clearCachedVersionSelector(selectedContentId); - } - }; - }, [selectedContentId]); + // Clear the cache for the previous content ID when it changes + const prevContentId = React.useRef(selectedContentId); - // Update the cache when versions change - useEffect(() => { - if (data?.versions && data.versions.length > 0) { - // Only update versions in cache if we don't have any yet - if (versionSelectorCache.versions.length === 0) { - setVersionSelectorCache((prev) => ({ - ...prev, - versions: data.versions, - })); - } + if (prevContentId.current && prevContentId.current !== selectedContentId) { + clearCachedVersionSelector(prevContentId.current); + } + + prevContentId.current = selectedContentId; + + // Also reset the local cache state when content ID changes + if (data?.versions && selectedContentId) { + setVersionSelectorCache({ + component: null, + versions: data.versions, + isOpen: false, + }); } - }, [data?.versions]); + }, [selectedContentId, data?.versions]); useEffect(() => { setSelectedView(getDefaultView(isWebpage, hasAttachment)); diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index 99e86c1..6090f13 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -140,6 +140,18 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = } }, [versions, isOpen, searchQuery, selectedVersion]); + // Add a useEffect to update the filtered versions when the input versions change + useEffect(() => { + // Reset search query when versions change completely (different content) + if ( + versions.length > 0 && + filteredVersions.length > 0 && + versions[0].nodeId !== filteredVersions[0].nodeId + ) { + setSearchQuery(''); + } + }, [versions]); + // Return the same component return ( diff --git a/xp-archive/client/versionSelector/VersionSelectorCache.tsx b/xp-archive/client/versionSelector/VersionSelectorCache.tsx index cf05bd7..45c9076 100644 --- a/xp-archive/client/versionSelector/VersionSelectorCache.tsx +++ b/xp-archive/client/versionSelector/VersionSelectorCache.tsx @@ -17,6 +17,13 @@ export const setCachedVersionSelector = ( versions: VersionReference[], isOpen: boolean ) => { + // Clear all other caches first to prevent stale data + Object.keys(contentCache).forEach((key) => { + if (key !== contentId) { + delete contentCache[key]; + } + }); + contentCache[contentId] = { component, versions, From e6085c14e9556841bd27b6ec007d2ff4fd3a5d18 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 14:53:05 +0100 Subject: [PATCH 05/28] Refactor cache management in Content component - Replace local reference for previous content ID with a React ref to improve cache clearing logic. - Ensure cache is cleared immediately when content ID changes, maintaining accurate version data. --- xp-archive/client/content/Content.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index d66d304..13c0a52 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -30,6 +30,8 @@ export const Content = () => { const { selectedContentId, selectedLocale, selectedVersion, setSelectedVersion } = useAppState(); + const prevContentIdRef = React.useRef(selectedContentId); + useEffect(() => { const pathSegments = window.location.pathname.split('/'); if (pathSegments.length >= 5) { @@ -76,13 +78,11 @@ export const Content = () => { // Update this effect to clear the cache immediately when content ID changes useEffect(() => { // Clear the cache for the previous content ID when it changes - const prevContentId = React.useRef(selectedContentId); - - if (prevContentId.current && prevContentId.current !== selectedContentId) { - clearCachedVersionSelector(prevContentId.current); + if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { + clearCachedVersionSelector(prevContentIdRef.current); } - prevContentId.current = selectedContentId; + prevContentIdRef.current = selectedContentId; // Also reset the local cache state when content ID changes if (data?.versions && selectedContentId) { From ba86b3b6736d547746ebf00db00e332858ee5c43 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:04:00 +0100 Subject: [PATCH 06/28] Enhance cache management in Content component - Preserve the isOpen state when resetting the local cache on content ID changes. - Introduce a separate effect to handle data loading without affecting the panel state, ensuring accurate version data is maintained. --- xp-archive/client/content/Content.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 13c0a52..b8e09b6 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -84,16 +84,26 @@ export const Content = () => { prevContentIdRef.current = selectedContentId; - // Also reset the local cache state when content ID changes + // Also reset the local cache state when content ID changes, but preserve isOpen state if (data?.versions && selectedContentId) { - setVersionSelectorCache({ + setVersionSelectorCache((prev) => ({ component: null, versions: data.versions, - isOpen: false, - }); + isOpen: prev.isOpen, // Preserve the open state + })); } }, [selectedContentId, data?.versions]); + // Add a separate effect to handle data loading without affecting panel state + useEffect(() => { + if (data?.versions && selectedContentId) { + setVersionSelectorCache((prev) => ({ + ...prev, + versions: data.versions, + })); + } + }, [data?.versions, selectedContentId]); + useEffect(() => { setSelectedView(getDefaultView(isWebpage, hasAttachment)); }, [isWebpage, hasAttachment, selectedContentId]); From e5f723fb15fb07210acd26e7455f5c6ec67f94ae Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:17:43 +0100 Subject: [PATCH 07/28] Update rendering logic for VersionSelector in Content component - Modify the rendering condition to display either the cached VersionSelector component or a new instance based on availability. - Enhance clarity in the code by improving comments related to component rendering. --- xp-archive/client/content/Content.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index b8e09b6..0d56877 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -146,8 +146,10 @@ export const Content = () => { {getVersionDisplay()} - {/* Use the cached component if available */} - {versionSelectorCache.component || ( + {/* Render either the cached component or a new VersionSelector */} + {versionSelectorCache.component ? ( + versionSelectorCache.component + ) : ( 0 From e2d215e7daea698f6431e45ab4855018b54ca3e4 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:19:49 +0100 Subject: [PATCH 08/28] Refactor URL management in Content component - Simplify version selection logic by consolidating URL update conditions. - Ensure the selected version is set correctly based on available data, improving user experience with accurate URL states. --- xp-archive/client/content/Content.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 0d56877..8e26997 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -48,13 +48,12 @@ export const Content = () => { }); useEffect(() => { - if (selectedVersion) { - const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${selectedVersion}`; - window.history.replaceState({}, '', newUrl); - } else if (data?.versions?.[0]) { - const latestVersionId = data.versions[0].versionId; - setSelectedVersion(latestVersionId); - const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${latestVersionId}`; + const versionId = selectedVersion ?? data?.versions?.[0]?.versionId; + if (versionId) { + if (!selectedVersion) { + setSelectedVersion(versionId); + } + const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${versionId}`; window.history.replaceState({}, '', newUrl); } }, [data, selectedContentId, selectedLocale, selectedVersion]); From 313e142372e8429f4d58890a654cc12533808332 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:22:52 +0100 Subject: [PATCH 09/28] Refactor version selector state management in VersionSelector component - Remove localStorage handling for version selector state to simplify state management. - Streamline the component by eliminating unnecessary storage key logic and effects. - Ensure the selected version is set correctly without persisting state across sessions. --- xp-archive/client/content/Content.tsx | 3 - .../versionSelector/VersionSelector.tsx | 56 +------------------ 2 files changed, 1 insertion(+), 58 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 8e26997..083d58d 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -23,9 +23,6 @@ const getDefaultView = (isWebpage: boolean, hasAttachment: boolean): ViewVariant return undefined; }; -// Storage key for persisting version selector state -const STORAGE_KEY = 'versionSelector_state'; - export const Content = () => { const { selectedContentId, selectedLocale, selectedVersion, setSelectedVersion } = useAppState(); diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index 6090f13..d5443ca 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -33,51 +33,11 @@ const VersionButton = ({ isSelected, onClick, children }: VersionButtonProps) => ); -// Storage key for persisting version selector state -const getStorageKey = (contentId: string) => `versionSelector_state_${contentId}`; - export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) => { const [searchQuery, setSearchQuery] = useState(''); - const { setSelectedContentId, selectedVersion, setSelectedVersion, selectedContentId } = - useAppState(); - const storageKey = getStorageKey(selectedContentId || ''); - - // Load search query from localStorage on mount - useEffect(() => { - if (isOpen) { - try { - const savedState = localStorage.getItem(storageKey); - if (savedState) { - const { searchQuery: savedQuery } = JSON.parse(savedState); - if (savedQuery) { - setSearchQuery(savedQuery); - } - } - } catch (e) { - console.error('Failed to load version selector state', e); - } - } - }, [isOpen, storageKey]); - - // Save state to localStorage when it changes - useEffect(() => { - if (isOpen) { - try { - localStorage.setItem( - storageKey, - JSON.stringify({ - searchQuery, - selectedVersion, - }) - ); - } catch (e) { - console.error('Failed to save version selector state', e); - } - } - }, [isOpen, searchQuery, selectedVersion, storageKey]); + const { setSelectedContentId, selectedVersion, setSelectedVersion } = useAppState(); const handleClose = () => { - // Don't clear search query when closing onClose(); }; @@ -85,20 +45,6 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = const nodeId = versions.find((v) => v.versionId === versionId)?.nodeId; if (nodeId) setSelectedContentId(nodeId); setSelectedVersion(versionId); - - // Save selected version to localStorage - try { - localStorage.setItem( - storageKey, - JSON.stringify({ - searchQuery, - selectedVersion: versionId, - keepOpen: true, // Flag to keep panel open - }) - ); - } catch (e) { - console.error('Failed to save version selection', e); - } }; const filteredVersions = versions.filter((version) => From 31bdc5e3e525f67fca652e90fe39c7d27ba50b34 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:32:06 +0100 Subject: [PATCH 10/28] Refactor cache and search management in Content and VersionSelector components - Update cache handling to clear and reset based on content ID changes, ensuring accurate version data. - Simplify the search query reset logic in VersionSelector when versions change, improving user experience. - Streamline the useEffect hooks for better clarity and performance in both components. --- xp-archive/client/content/Content.tsx | 20 ++------ .../versionSelector/VersionSelector.tsx | 50 ++++--------------- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 083d58d..d65a235 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -71,34 +71,22 @@ export const Content = () => { }; }); - // Update this effect to clear the cache immediately when content ID changes + // Update cache when content ID changes or new versions arrive useEffect(() => { - // Clear the cache for the previous content ID when it changes if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); } - prevContentIdRef.current = selectedContentId; - - // Also reset the local cache state when content ID changes, but preserve isOpen state if (data?.versions && selectedContentId) { setVersionSelectorCache((prev) => ({ component: null, versions: data.versions, - isOpen: prev.isOpen, // Preserve the open state + isOpen: prev.isOpen, // Always preserve open state })); } - }, [selectedContentId, data?.versions]); - // Add a separate effect to handle data loading without affecting panel state - useEffect(() => { - if (data?.versions && selectedContentId) { - setVersionSelectorCache((prev) => ({ - ...prev, - versions: data.versions, - })); - } - }, [data?.versions, selectedContentId]); + prevContentIdRef.current = selectedContentId; + }, [selectedContentId, data?.versions]); useEffect(() => { setSelectedView(getDefaultView(isWebpage, hasAttachment)); diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index d5443ca..e4261d8 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -51,44 +51,8 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = formatTimestamp(version.timestamp).toLowerCase().includes(searchQuery.toLowerCase()) ); - // Call onMount with the rendered component + // Reset search when versions change completely useEffect(() => { - if (onMount) { - const component = ( - - - Versjoner - - -
- {filteredVersions.map((version, index) => ( - selectVersion(version.versionId)} - > - {formatTimestamp(version.timestamp)} - {index === 0 && ( - (Siste versjon) - )} - - ))} -
-
- ); - onMount(component); - } - }, [versions, isOpen, searchQuery, selectedVersion]); - - // Add a useEffect to update the filtered versions when the input versions change - useEffect(() => { - // Reset search query when versions change completely (different content) if ( versions.length > 0 && filteredVersions.length > 0 && @@ -98,8 +62,7 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = } }, [versions]); - // Return the same component - return ( + const component = ( Versjoner @@ -127,4 +90,13 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) =
); + + // Call onMount with the component + useEffect(() => { + if (onMount) { + onMount(component); + } + }, [versions, isOpen, searchQuery, selectedVersion]); + + return component; }; From cf0aa3e58b44eaed419302e24ee39e4f03955eb1 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:41:11 +0100 Subject: [PATCH 11/28] Refactor URL and version handling in Content component - Simplify version ID and URL management logic to enhance clarity and performance. - Consolidate useEffect dependencies for better data handling and state updates. - Improve comments for better understanding of cache management and rendering logic. --- xp-archive/client/content/Content.tsx | 30 ++++++++++----------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index d65a235..7a56c75 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -44,16 +44,16 @@ export const Content = () => { versionId: selectedVersion ?? '', }); + // Simplified version ID and URL handling useEffect(() => { - const versionId = selectedVersion ?? data?.versions?.[0]?.versionId; - if (versionId) { - if (!selectedVersion) { - setSelectedVersion(versionId); - } - const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${versionId}`; + if (!selectedVersion && data?.versions?.[0]) { + setSelectedVersion(data.versions[0].versionId); + } + if (selectedContentId && selectedLocale && selectedVersion) { + const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${selectedVersion}`; window.history.replaceState({}, '', newUrl); } - }, [data, selectedContentId, selectedLocale, selectedVersion]); + }, [data?.versions, selectedContentId, selectedLocale, selectedVersion]); const isWebpage = !!data?.html && !data.json.attachment; const hasAttachment = !!data?.json.attachment; @@ -71,7 +71,7 @@ export const Content = () => { }; }); - // Update cache when content ID changes or new versions arrive + // Single effect for cache management useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -81,7 +81,7 @@ export const Content = () => { setVersionSelectorCache((prev) => ({ component: null, versions: data.versions, - isOpen: prev.isOpen, // Always preserve open state + isOpen: prev.isOpen, })); } @@ -130,16 +130,11 @@ export const Content = () => { {getVersionDisplay()} - {/* Render either the cached component or a new VersionSelector */} {versionSelectorCache.component ? ( versionSelectorCache.component ) : ( 0 - ? versionSelectorCache.versions - : data?.versions || [] - } + versions={data?.versions || []} isOpen={versionSelectorCache.isOpen} onClose={() => { setVersionSelectorCache((prev) => ({ @@ -148,13 +143,10 @@ export const Content = () => { })); }} onMount={(component) => { - // Cache the rendered component with the content ID setCachedVersionSelector( selectedContentId || '', component, - versionSelectorCache.versions.length > 0 - ? versionSelectorCache.versions - : data?.versions || [], + data?.versions || [], versionSelectorCache.isOpen ); }} From cafcab87d63f92c6eefb19bfdfe004df484e8a32 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 13 Mar 2025 15:45:00 +0100 Subject: [PATCH 12/28] Revert "Refactor URL and version handling in Content component" This reverts commit cf0aa3e58b44eaed419302e24ee39e4f03955eb1. --- xp-archive/client/content/Content.tsx | 30 +++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 7a56c75..d65a235 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -44,16 +44,16 @@ export const Content = () => { versionId: selectedVersion ?? '', }); - // Simplified version ID and URL handling useEffect(() => { - if (!selectedVersion && data?.versions?.[0]) { - setSelectedVersion(data.versions[0].versionId); - } - if (selectedContentId && selectedLocale && selectedVersion) { - const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${selectedVersion}`; + const versionId = selectedVersion ?? data?.versions?.[0]?.versionId; + if (versionId) { + if (!selectedVersion) { + setSelectedVersion(versionId); + } + const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${versionId}`; window.history.replaceState({}, '', newUrl); } - }, [data?.versions, selectedContentId, selectedLocale, selectedVersion]); + }, [data, selectedContentId, selectedLocale, selectedVersion]); const isWebpage = !!data?.html && !data.json.attachment; const hasAttachment = !!data?.json.attachment; @@ -71,7 +71,7 @@ export const Content = () => { }; }); - // Single effect for cache management + // Update cache when content ID changes or new versions arrive useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -81,7 +81,7 @@ export const Content = () => { setVersionSelectorCache((prev) => ({ component: null, versions: data.versions, - isOpen: prev.isOpen, + isOpen: prev.isOpen, // Always preserve open state })); } @@ -130,11 +130,16 @@ export const Content = () => { {getVersionDisplay()} + {/* Render either the cached component or a new VersionSelector */} {versionSelectorCache.component ? ( versionSelectorCache.component ) : ( 0 + ? versionSelectorCache.versions + : data?.versions || [] + } isOpen={versionSelectorCache.isOpen} onClose={() => { setVersionSelectorCache((prev) => ({ @@ -143,10 +148,13 @@ export const Content = () => { })); }} onMount={(component) => { + // Cache the rendered component with the content ID setCachedVersionSelector( selectedContentId || '', component, - data?.versions || [], + versionSelectorCache.versions.length > 0 + ? versionSelectorCache.versions + : data?.versions || [], versionSelectorCache.isOpen ); }} From 529d29c1610dc8b3ce67caaed3fc07a1ec16cc55 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 10:55:32 +0100 Subject: [PATCH 13/28] fjern kommentarer og || --- xp-archive/client/content/Content.tsx | 10 +++------- xp-archive/client/versionSelector/VersionSelector.tsx | 2 -- .../client/versionSelector/VersionSelectorCache.tsx | 2 -- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index d65a235..c303b81 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -61,9 +61,8 @@ export const Content = () => { getDefaultView(isWebpage, hasAttachment) ); - // Get cached state or initialize const [versionSelectorCache, setVersionSelectorCache] = useState(() => { - const cache = getCachedVersionSelector(selectedContentId || ''); + const cache = getCachedVersionSelector(selectedContentId ?? ''); return { component: cache.component, versions: cache.versions, @@ -71,7 +70,6 @@ export const Content = () => { }; }); - // Update cache when content ID changes or new versions arrive useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -81,7 +79,7 @@ export const Content = () => { setVersionSelectorCache((prev) => ({ component: null, versions: data.versions, - isOpen: prev.isOpen, // Always preserve open state + isOpen: prev.isOpen, })); } @@ -130,7 +128,6 @@ export const Content = () => { {getVersionDisplay()} - {/* Render either the cached component or a new VersionSelector */} {versionSelectorCache.component ? ( versionSelectorCache.component ) : ( @@ -148,9 +145,8 @@ export const Content = () => { })); }} onMount={(component) => { - // Cache the rendered component with the content ID setCachedVersionSelector( - selectedContentId || '', + selectedContentId ?? '', component, versionSelectorCache.versions.length > 0 ? versionSelectorCache.versions diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index e4261d8..07dd689 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -51,7 +51,6 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = formatTimestamp(version.timestamp).toLowerCase().includes(searchQuery.toLowerCase()) ); - // Reset search when versions change completely useEffect(() => { if ( versions.length > 0 && @@ -91,7 +90,6 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = ); - // Call onMount with the component useEffect(() => { if (onMount) { onMount(component); diff --git a/xp-archive/client/versionSelector/VersionSelectorCache.tsx b/xp-archive/client/versionSelector/VersionSelectorCache.tsx index 45c9076..cdf912a 100644 --- a/xp-archive/client/versionSelector/VersionSelectorCache.tsx +++ b/xp-archive/client/versionSelector/VersionSelectorCache.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { VersionReference } from 'shared/types'; -// Content-specific cache for the version selector component const contentCache: Record< string, { @@ -17,7 +16,6 @@ export const setCachedVersionSelector = ( versions: VersionReference[], isOpen: boolean ) => { - // Clear all other caches first to prevent stale data Object.keys(contentCache).forEach((key) => { if (key !== contentId) { delete contentCache[key]; From 1297c75944bc5916758e320c1592d9a8935a22a7 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:09:37 +0100 Subject: [PATCH 14/28] hindre dobbel linje og hopping i versjonsvelgeren --- .../client/versionSelector/SlidePanel/SlidePanel.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css b/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css index d1298b5..6d4f982 100644 --- a/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css +++ b/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css @@ -19,7 +19,7 @@ .panel { position: relative; z-index: 1; - width: 400px; + width: 460px; height: 100vh; background: var(--a-surface-default); box-shadow: 4px 0 8px rgba(0, 0, 0, 0.1); From f6c1f2c473987ebb95f64cf8f4265a73a2a15988 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:21:34 +0100 Subject: [PATCH 15/28] =?UTF-8?q?test=20cached=20versjon=20i=20=C3=A5pne-k?= =?UTF-8?q?nappen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xp-archive/client/content/Content.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index c303b81..eae1aca 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -95,6 +95,17 @@ export const Content = () => { }`; const getVersionDisplay = () => { + // First check if we have the version in our cache + if (selectedVersion && versionSelectorCache.versions.length > 0) { + const cachedVersion = versionSelectorCache.versions.find( + (v) => v.versionId === selectedVersion + ); + if (cachedVersion?.timestamp) { + return formatTimestamp(cachedVersion.timestamp); + } + } + + // Fall back to data if cache doesn't have it if (selectedVersion && data?.versions) { return formatTimestamp( data.versions.find((v) => v.versionId === selectedVersion)?.timestamp ?? '' From e7df0920086e15aa5cf4b280734d470a2c896b1e Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:31:41 +0100 Subject: [PATCH 16/28] cache tittel og url --- xp-archive/client/content/Content.tsx | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index eae1aca..c887db7 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -70,6 +70,13 @@ export const Content = () => { }; }); + // Add this new state to cache display values + const [cachedDisplayData, setCachedDisplayData] = useState({ + displayName: '', + path: '', + }); + + // Update this useEffect to also cache display data when data loads useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -81,10 +88,18 @@ export const Content = () => { versions: data.versions, isOpen: prev.isOpen, })); + + // Cache display data when it's available + if (data.json?.displayName || data.json?._path) { + setCachedDisplayData({ + displayName: data.json.displayName || '', + path: data.json._path || '', + }); + } } prevContentIdRef.current = selectedContentId; - }, [selectedContentId, data?.versions]); + }, [selectedContentId, data?.versions, data?.json]); useEffect(() => { setSelectedView(getDefaultView(isWebpage, hasAttachment)); @@ -114,6 +129,15 @@ export const Content = () => { return 'Laster...'; }; + // Add helper functions to get title and URL with fallbacks + const getDisplayName = () => { + return data?.json.displayName || cachedDisplayData.displayName || 'Laster...'; + }; + + const getPath = () => { + return data?.json._path || cachedDisplayData.path || ''; + }; + if (!selectedContentId) { return ; } @@ -195,10 +219,10 @@ export const Content = () => {
- {data?.json.displayName ?? ''} + {getDisplayName()}
- {data?.json._path ?? ''} + {getPath()}
From 86eae8ea06b1e9e5297a8d9b7cfdf168bf05c477 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:42:40 +0100 Subject: [PATCH 17/28] =?UTF-8?q?cache=20"Visning"=20og=20pr=C3=B8v=20?= =?UTF-8?q?=C3=A5=20forenkle=20det=20hele?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xp-archive/client/content/Content.tsx | 108 ++++++++++++-------------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index c887db7..19aea0a 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -55,64 +55,55 @@ export const Content = () => { } }, [data, selectedContentId, selectedLocale, selectedVersion]); - const isWebpage = !!data?.html && !data.json.attachment; - const hasAttachment = !!data?.json.attachment; - const [selectedView, setSelectedView] = useState( + // Calculate derived properties + const isWebpage = !!data?.html && !data?.json?.attachment; + const hasAttachment = !!data?.json?.attachment; + + // State for view selector + const [selectedView, setSelectedView] = useState(() => getDefaultView(isWebpage, hasAttachment) ); - const [versionSelectorCache, setVersionSelectorCache] = useState(() => { - const cache = getCachedVersionSelector(selectedContentId ?? ''); - return { - component: cache.component, - versions: cache.versions, - isOpen: cache.isOpen, - }; - }); + // Update view when content type changes + useEffect(() => { + setSelectedView(getDefaultView(isWebpage, hasAttachment)); + }, [isWebpage, hasAttachment, selectedContentId]); + + // Single cache for content-related data + const [contentCache, setContentCache] = useState(() => ({ + // Version selector + versions: getCachedVersionSelector(selectedContentId ?? '').versions, + versionComponent: getCachedVersionSelector(selectedContentId ?? '').component, + isVersionPanelOpen: getCachedVersionSelector(selectedContentId ?? '').isOpen, - // Add this new state to cache display values - const [cachedDisplayData, setCachedDisplayData] = useState({ + // Display data displayName: '', path: '', - }); + })); - // Update this useEffect to also cache display data when data loads + // Update cache when content changes useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); } if (data?.versions && selectedContentId) { - setVersionSelectorCache((prev) => ({ - component: null, + setContentCache((prev) => ({ + ...prev, versions: data.versions, - isOpen: prev.isOpen, + versionComponent: null, + displayName: data.json?.displayName || prev.displayName, + path: data.json?._path || prev.path, })); - - // Cache display data when it's available - if (data.json?.displayName || data.json?._path) { - setCachedDisplayData({ - displayName: data.json.displayName || '', - path: data.json._path || '', - }); - } } prevContentIdRef.current = selectedContentId; }, [selectedContentId, data?.versions, data?.json]); - useEffect(() => { - setSelectedView(getDefaultView(isWebpage, hasAttachment)); - }, [isWebpage, hasAttachment, selectedContentId]); - - const htmlPath = `${xpArchiveConfig.basePath}/html/${selectedContentId}/${selectedLocale}/${ - data?.json._versionKey - }`; - + // Helper functions to get data with fallbacks const getVersionDisplay = () => { - // First check if we have the version in our cache - if (selectedVersion && versionSelectorCache.versions.length > 0) { - const cachedVersion = versionSelectorCache.versions.find( + if (selectedVersion && contentCache.versions.length > 0) { + const cachedVersion = contentCache.versions.find( (v) => v.versionId === selectedVersion ); if (cachedVersion?.timestamp) { @@ -120,23 +111,21 @@ export const Content = () => { } } - // Fall back to data if cache doesn't have it if (selectedVersion && data?.versions) { return formatTimestamp( data.versions.find((v) => v.versionId === selectedVersion)?.timestamp ?? '' ); } + return 'Laster...'; }; - // Add helper functions to get title and URL with fallbacks - const getDisplayName = () => { - return data?.json.displayName || cachedDisplayData.displayName || 'Laster...'; - }; + const getDisplayName = () => data?.json?.displayName || contentCache.displayName || 'Laster...'; + const getPath = () => data?.json?._path || contentCache.path || ''; - const getPath = () => { - return data?.json._path || cachedDisplayData.path || ''; - }; + const htmlPath = `${xpArchiveConfig.basePath}/html/${selectedContentId}/${selectedLocale}/${ + data?.json._versionKey + }`; if (!selectedContentId) { return ; @@ -154,40 +143,45 @@ export const Content = () => { icon={} iconPosition={'right'} onClick={() => { - setVersionSelectorCache((prev) => ({ + setContentCache((prev) => ({ ...prev, - isOpen: true, + isVersionPanelOpen: true, })); }} > {getVersionDisplay()} - {versionSelectorCache.component ? ( - versionSelectorCache.component + {contentCache.versionComponent ? ( + contentCache.versionComponent ) : ( 0 - ? versionSelectorCache.versions + contentCache.versions.length > 0 + ? contentCache.versions : data?.versions || [] } - isOpen={versionSelectorCache.isOpen} + isOpen={contentCache.isVersionPanelOpen} onClose={() => { - setVersionSelectorCache((prev) => ({ + setContentCache((prev) => ({ ...prev, - isOpen: false, + isVersionPanelOpen: false, })); }} onMount={(component) => { setCachedVersionSelector( selectedContentId ?? '', component, - versionSelectorCache.versions.length > 0 - ? versionSelectorCache.versions + contentCache.versions.length > 0 + ? contentCache.versions : data?.versions || [], - versionSelectorCache.isOpen + contentCache.isVersionPanelOpen ); + + setContentCache((prev) => ({ + ...prev, + versionComponent: component, + })); }} /> )} From 73f4d40e571ff80787ad836b42ce060d5d355609 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:46:26 +0100 Subject: [PATCH 18/28] =?UTF-8?q?Revert=20"cache=20"Visning"=20og=20pr?= =?UTF-8?q?=C3=B8v=20=C3=A5=20forenkle=20det=20hele"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 86eae8ea06b1e9e5297a8d9b7cfdf168bf05c477. --- xp-archive/client/content/Content.tsx | 108 ++++++++++++++------------ 1 file changed, 57 insertions(+), 51 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 19aea0a..c887db7 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -55,55 +55,64 @@ export const Content = () => { } }, [data, selectedContentId, selectedLocale, selectedVersion]); - // Calculate derived properties - const isWebpage = !!data?.html && !data?.json?.attachment; - const hasAttachment = !!data?.json?.attachment; - - // State for view selector - const [selectedView, setSelectedView] = useState(() => + const isWebpage = !!data?.html && !data.json.attachment; + const hasAttachment = !!data?.json.attachment; + const [selectedView, setSelectedView] = useState( getDefaultView(isWebpage, hasAttachment) ); - // Update view when content type changes - useEffect(() => { - setSelectedView(getDefaultView(isWebpage, hasAttachment)); - }, [isWebpage, hasAttachment, selectedContentId]); - - // Single cache for content-related data - const [contentCache, setContentCache] = useState(() => ({ - // Version selector - versions: getCachedVersionSelector(selectedContentId ?? '').versions, - versionComponent: getCachedVersionSelector(selectedContentId ?? '').component, - isVersionPanelOpen: getCachedVersionSelector(selectedContentId ?? '').isOpen, + const [versionSelectorCache, setVersionSelectorCache] = useState(() => { + const cache = getCachedVersionSelector(selectedContentId ?? ''); + return { + component: cache.component, + versions: cache.versions, + isOpen: cache.isOpen, + }; + }); - // Display data + // Add this new state to cache display values + const [cachedDisplayData, setCachedDisplayData] = useState({ displayName: '', path: '', - })); + }); - // Update cache when content changes + // Update this useEffect to also cache display data when data loads useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); } if (data?.versions && selectedContentId) { - setContentCache((prev) => ({ - ...prev, + setVersionSelectorCache((prev) => ({ + component: null, versions: data.versions, - versionComponent: null, - displayName: data.json?.displayName || prev.displayName, - path: data.json?._path || prev.path, + isOpen: prev.isOpen, })); + + // Cache display data when it's available + if (data.json?.displayName || data.json?._path) { + setCachedDisplayData({ + displayName: data.json.displayName || '', + path: data.json._path || '', + }); + } } prevContentIdRef.current = selectedContentId; }, [selectedContentId, data?.versions, data?.json]); - // Helper functions to get data with fallbacks + useEffect(() => { + setSelectedView(getDefaultView(isWebpage, hasAttachment)); + }, [isWebpage, hasAttachment, selectedContentId]); + + const htmlPath = `${xpArchiveConfig.basePath}/html/${selectedContentId}/${selectedLocale}/${ + data?.json._versionKey + }`; + const getVersionDisplay = () => { - if (selectedVersion && contentCache.versions.length > 0) { - const cachedVersion = contentCache.versions.find( + // First check if we have the version in our cache + if (selectedVersion && versionSelectorCache.versions.length > 0) { + const cachedVersion = versionSelectorCache.versions.find( (v) => v.versionId === selectedVersion ); if (cachedVersion?.timestamp) { @@ -111,21 +120,23 @@ export const Content = () => { } } + // Fall back to data if cache doesn't have it if (selectedVersion && data?.versions) { return formatTimestamp( data.versions.find((v) => v.versionId === selectedVersion)?.timestamp ?? '' ); } - return 'Laster...'; }; - const getDisplayName = () => data?.json?.displayName || contentCache.displayName || 'Laster...'; - const getPath = () => data?.json?._path || contentCache.path || ''; + // Add helper functions to get title and URL with fallbacks + const getDisplayName = () => { + return data?.json.displayName || cachedDisplayData.displayName || 'Laster...'; + }; - const htmlPath = `${xpArchiveConfig.basePath}/html/${selectedContentId}/${selectedLocale}/${ - data?.json._versionKey - }`; + const getPath = () => { + return data?.json._path || cachedDisplayData.path || ''; + }; if (!selectedContentId) { return ; @@ -143,45 +154,40 @@ export const Content = () => { icon={} iconPosition={'right'} onClick={() => { - setContentCache((prev) => ({ + setVersionSelectorCache((prev) => ({ ...prev, - isVersionPanelOpen: true, + isOpen: true, })); }} > {getVersionDisplay()} - {contentCache.versionComponent ? ( - contentCache.versionComponent + {versionSelectorCache.component ? ( + versionSelectorCache.component ) : ( 0 - ? contentCache.versions + versionSelectorCache.versions.length > 0 + ? versionSelectorCache.versions : data?.versions || [] } - isOpen={contentCache.isVersionPanelOpen} + isOpen={versionSelectorCache.isOpen} onClose={() => { - setContentCache((prev) => ({ + setVersionSelectorCache((prev) => ({ ...prev, - isVersionPanelOpen: false, + isOpen: false, })); }} onMount={(component) => { setCachedVersionSelector( selectedContentId ?? '', component, - contentCache.versions.length > 0 - ? contentCache.versions + versionSelectorCache.versions.length > 0 + ? versionSelectorCache.versions : data?.versions || [], - contentCache.isVersionPanelOpen + versionSelectorCache.isOpen ); - - setContentCache((prev) => ({ - ...prev, - versionComponent: component, - })); }} /> )} From e44edce0e7a512d1bb339ae7f5af58e7a317da16 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:48:57 +0100 Subject: [PATCH 19/28] Refactor Content component to use optional chaining for safer data access --- xp-archive/client/content/Content.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index c887db7..bdc600f 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -55,8 +55,8 @@ export const Content = () => { } }, [data, selectedContentId, selectedLocale, selectedVersion]); - const isWebpage = !!data?.html && !data.json.attachment; - const hasAttachment = !!data?.json.attachment; + const isWebpage = !!data?.html && !data?.json?.attachment; + const hasAttachment = !!data?.json?.attachment; const [selectedView, setSelectedView] = useState( getDefaultView(isWebpage, hasAttachment) ); @@ -131,11 +131,11 @@ export const Content = () => { // Add helper functions to get title and URL with fallbacks const getDisplayName = () => { - return data?.json.displayName || cachedDisplayData.displayName || 'Laster...'; + return data?.json?.displayName || cachedDisplayData.displayName || 'Laster...'; }; const getPath = () => { - return data?.json._path || cachedDisplayData.path || ''; + return data?.json?._path || cachedDisplayData.path || ''; }; if (!selectedContentId) { From 1083c4dd2a22b3bd88becd484f0ae5db348c7fda Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:53:11 +0100 Subject: [PATCH 20/28] =?UTF-8?q?fors=C3=B8k=20cache=20visning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xp-archive/client/content/Content.tsx | 37 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index bdc600f..b798e8b 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -70,13 +70,14 @@ export const Content = () => { }; }); - // Add this new state to cache display values + // Add view type to cached display data const [cachedDisplayData, setCachedDisplayData] = useState({ displayName: '', path: '', + view: undefined as ViewVariant | undefined, }); - // Update this useEffect to also cache display data when data loads + // Update this useEffect to also cache display data and view when data loads useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -91,20 +92,40 @@ export const Content = () => { // Cache display data when it's available if (data.json?.displayName || data.json?._path) { - setCachedDisplayData({ - displayName: data.json.displayName || '', - path: data.json._path || '', - }); + setCachedDisplayData((prev) => ({ + displayName: data.json?.displayName || '', + path: data.json?._path || '', + view: prev.view, // Keep existing view + })); } } prevContentIdRef.current = selectedContentId; }, [selectedContentId, data?.versions, data?.json]); + // Update view selector effect to store the selected view in cache useEffect(() => { - setSelectedView(getDefaultView(isWebpage, hasAttachment)); + const newView = getDefaultView(isWebpage, hasAttachment); + setSelectedView(newView); + + // Cache the view + setCachedDisplayData((prev) => ({ + ...prev, + view: newView, + })); }, [isWebpage, hasAttachment, selectedContentId]); + // Add handler to update cached view + const handleViewChange = (view: ViewVariant) => { + setSelectedView(view); + + // Update cached view + setCachedDisplayData((prev) => ({ + ...prev, + view, + })); + }; + const htmlPath = `${xpArchiveConfig.basePath}/html/${selectedContentId}/${selectedLocale}/${ data?.json._versionKey }`; @@ -197,7 +218,7 @@ export const Content = () => {
From b761ac1504861ff492aaa94703c040b6135b8149 Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 11:59:51 +0100 Subject: [PATCH 21/28] =?UTF-8?q?Revert=20"fors=C3=B8k=20cache=20visning"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1083c4dd2a22b3bd88becd484f0ae5db348c7fda. --- xp-archive/client/content/Content.tsx | 37 ++++++--------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index b798e8b..bdc600f 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -70,14 +70,13 @@ export const Content = () => { }; }); - // Add view type to cached display data + // Add this new state to cache display values const [cachedDisplayData, setCachedDisplayData] = useState({ displayName: '', path: '', - view: undefined as ViewVariant | undefined, }); - // Update this useEffect to also cache display data and view when data loads + // Update this useEffect to also cache display data when data loads useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -92,40 +91,20 @@ export const Content = () => { // Cache display data when it's available if (data.json?.displayName || data.json?._path) { - setCachedDisplayData((prev) => ({ - displayName: data.json?.displayName || '', - path: data.json?._path || '', - view: prev.view, // Keep existing view - })); + setCachedDisplayData({ + displayName: data.json.displayName || '', + path: data.json._path || '', + }); } } prevContentIdRef.current = selectedContentId; }, [selectedContentId, data?.versions, data?.json]); - // Update view selector effect to store the selected view in cache useEffect(() => { - const newView = getDefaultView(isWebpage, hasAttachment); - setSelectedView(newView); - - // Cache the view - setCachedDisplayData((prev) => ({ - ...prev, - view: newView, - })); + setSelectedView(getDefaultView(isWebpage, hasAttachment)); }, [isWebpage, hasAttachment, selectedContentId]); - // Add handler to update cached view - const handleViewChange = (view: ViewVariant) => { - setSelectedView(view); - - // Update cached view - setCachedDisplayData((prev) => ({ - ...prev, - view, - })); - }; - const htmlPath = `${xpArchiveConfig.basePath}/html/${selectedContentId}/${selectedLocale}/${ data?.json._versionKey }`; @@ -218,7 +197,7 @@ export const Content = () => {
From fae83373d0061c9340ea49db3cb543d7a6149eef Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 12:00:42 +0100 Subject: [PATCH 22/28] fjern kommentarer --- xp-archive/client/content/Content.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index bdc600f..c52460e 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -70,13 +70,11 @@ export const Content = () => { }; }); - // Add this new state to cache display values const [cachedDisplayData, setCachedDisplayData] = useState({ displayName: '', path: '', }); - // Update this useEffect to also cache display data when data loads useEffect(() => { if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) { clearCachedVersionSelector(prevContentIdRef.current); @@ -89,7 +87,6 @@ export const Content = () => { isOpen: prev.isOpen, })); - // Cache display data when it's available if (data.json?.displayName || data.json?._path) { setCachedDisplayData({ displayName: data.json.displayName || '', @@ -110,7 +107,6 @@ export const Content = () => { }`; const getVersionDisplay = () => { - // First check if we have the version in our cache if (selectedVersion && versionSelectorCache.versions.length > 0) { const cachedVersion = versionSelectorCache.versions.find( (v) => v.versionId === selectedVersion @@ -120,7 +116,6 @@ export const Content = () => { } } - // Fall back to data if cache doesn't have it if (selectedVersion && data?.versions) { return formatTimestamp( data.versions.find((v) => v.versionId === selectedVersion)?.timestamp ?? '' @@ -129,7 +124,6 @@ export const Content = () => { return 'Laster...'; }; - // Add helper functions to get title and URL with fallbacks const getDisplayName = () => { return data?.json?.displayName || cachedDisplayData.displayName || 'Laster...'; }; From 073c1db7cc17d79faf891e546a9a757289d62a1c Mon Sep 17 00:00:00 2001 From: bdahle Date: Thu, 20 Mar 2025 12:05:56 +0100 Subject: [PATCH 23/28] =?UTF-8?q?legg=20til=20knapp=20for=20=C3=A5=20lukke?= =?UTF-8?q?=20versjonsvelgeren?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../versionSelector/SlidePanel/SlidePanel.module.css | 2 ++ .../client/versionSelector/VersionSelector.module.css | 11 +++++++++++ xp-archive/client/versionSelector/VersionSelector.tsx | 10 +++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css b/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css index 6d4f982..00005a7 100644 --- a/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css +++ b/xp-archive/client/versionSelector/SlidePanel/SlidePanel.module.css @@ -17,6 +17,8 @@ } .panel { + display: flex; + flex-direction: column; position: relative; z-index: 1; width: 460px; diff --git a/xp-archive/client/versionSelector/VersionSelector.module.css b/xp-archive/client/versionSelector/VersionSelector.module.css index 04a8387..13d858b 100644 --- a/xp-archive/client/versionSelector/VersionSelector.module.css +++ b/xp-archive/client/versionSelector/VersionSelector.module.css @@ -40,3 +40,14 @@ font-weight: var(--a-font-weight-bold); } } + +.closeButton { + position: sticky; + bottom: 1rem; + margin-top: 1.75rem; + + width: fit-content; + border-radius: 99px; + background-color: var(--a-surface-inverted); + align-self: center; +} diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index 07dd689..4c213c5 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { CheckmarkIcon, XMarkIcon } from '@navikt/aksel-icons'; import { Heading, Button, Search } from '@navikt/ds-react'; import { VersionReference } from 'shared/types'; import { formatTimestamp } from '@common/shared/timestamp'; @@ -6,7 +7,6 @@ import { useAppState } from 'client/context/appState/useAppState'; import { SlidePanel } from './SlidePanel/SlidePanel'; import { classNames } from '@common/client/utils/classNames'; import style from './VersionSelector.module.css'; -import { CheckmarkIcon } from '@navikt/aksel-icons'; type Props = { versions: VersionReference[]; @@ -87,6 +87,14 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = ))}
+ ); From c63494b287d5690672a9abe56e4b21cdc2311e20 Mon Sep 17 00:00:00 2001 From: bdahle Date: Fri, 21 Mar 2025 09:49:11 +0100 Subject: [PATCH 24/28] bytt tilbake til pushState --- xp-archive/client/content/Content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index c52460e..880b80e 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -51,7 +51,7 @@ export const Content = () => { setSelectedVersion(versionId); } const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${versionId}`; - window.history.replaceState({}, '', newUrl); + window.history.pushState({}, '', newUrl); } }, [data, selectedContentId, selectedLocale, selectedVersion]); From 3f464128a13b28adc149964d083095bae11a4a97 Mon Sep 17 00:00:00 2001 From: bdahle Date: Fri, 21 Mar 2025 10:14:27 +0100 Subject: [PATCH 25/28] Refactor version selector logic for improved readability and maintainability --- xp-archive/client/content/Content.tsx | 61 +++++++++++++++------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 880b80e..4df7aac 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -157,34 +157,39 @@ export const Content = () => { {getVersionDisplay()} - {versionSelectorCache.component ? ( - versionSelectorCache.component - ) : ( - 0 - ? versionSelectorCache.versions - : data?.versions || [] - } - isOpen={versionSelectorCache.isOpen} - onClose={() => { - setVersionSelectorCache((prev) => ({ - ...prev, - isOpen: false, - })); - }} - onMount={(component) => { - setCachedVersionSelector( - selectedContentId ?? '', - component, - versionSelectorCache.versions.length > 0 - ? versionSelectorCache.versions - : data?.versions || [], - versionSelectorCache.isOpen - ); - }} - /> - )} + {versionSelectorCache.component + ? versionSelectorCache.component + : (() => { + const versionSelectorVersions = + versionSelectorCache.versions.length > 0 + ? versionSelectorCache.versions + : data?.versions || []; + + const handleClose = () => { + setVersionSelectorCache((prev) => ({ + ...prev, + isOpen: false, + })); + }; + + const handleMount = (component: React.ReactNode) => { + setCachedVersionSelector( + selectedContentId ?? '', + component, + versionSelectorVersions, + versionSelectorCache.isOpen + ); + }; + + return ( + + ); + })()}
From 4db9bfaaecf19588330e23ee9af1097f277fa542 Mon Sep 17 00:00:00 2001 From: bdahle Date: Fri, 21 Mar 2025 10:18:43 +0100 Subject: [PATCH 26/28] =?UTF-8?q?revert=20til=20=C3=A5=20resette=20s=C3=B8?= =?UTF-8?q?k=20n=C3=A5r=20panelet=20lukkes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xp-archive/client/versionSelector/VersionSelector.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/xp-archive/client/versionSelector/VersionSelector.tsx b/xp-archive/client/versionSelector/VersionSelector.tsx index 4c213c5..e6d9d00 100644 --- a/xp-archive/client/versionSelector/VersionSelector.tsx +++ b/xp-archive/client/versionSelector/VersionSelector.tsx @@ -38,6 +38,7 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = const { setSelectedContentId, selectedVersion, setSelectedVersion } = useAppState(); const handleClose = () => { + setSearchQuery(''); onClose(); }; @@ -51,16 +52,6 @@ export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) = formatTimestamp(version.timestamp).toLowerCase().includes(searchQuery.toLowerCase()) ); - useEffect(() => { - if ( - versions.length > 0 && - filteredVersions.length > 0 && - versions[0].nodeId !== filteredVersions[0].nodeId - ) { - setSearchQuery(''); - } - }, [versions]); - const component = ( From 23d8668a14015f4e48a5c5608c1141e5a46c8f2a Mon Sep 17 00:00:00 2001 From: bdahle Date: Fri, 21 Mar 2025 10:21:23 +0100 Subject: [PATCH 27/28] inline display name og path --- xp-archive/client/content/Content.tsx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/xp-archive/client/content/Content.tsx b/xp-archive/client/content/Content.tsx index 4df7aac..390c67f 100644 --- a/xp-archive/client/content/Content.tsx +++ b/xp-archive/client/content/Content.tsx @@ -124,14 +124,6 @@ export const Content = () => { return 'Laster...'; }; - const getDisplayName = () => { - return data?.json?.displayName || cachedDisplayData.displayName || 'Laster...'; - }; - - const getPath = () => { - return data?.json?._path || cachedDisplayData.path || ''; - }; - if (!selectedContentId) { return ; } @@ -218,10 +210,10 @@ export const Content = () => {
- {getDisplayName()} + {data?.json?.displayName || cachedDisplayData.displayName || 'Laster...'}
- {getPath()} + {data?.json?._path || cachedDisplayData.path || ''}
From ba4401ea1662291302b2d288fd624083aaedf9eb Mon Sep 17 00:00:00 2001 From: bdahle Date: Fri, 21 Mar 2025 10:28:28 +0100 Subject: [PATCH 28/28] Refactor VersionSelectorCache to use a default cache item and improve type definitions --- .../versionSelector/VersionSelectorCache.tsx | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/xp-archive/client/versionSelector/VersionSelectorCache.tsx b/xp-archive/client/versionSelector/VersionSelectorCache.tsx index cdf912a..4b083cd 100644 --- a/xp-archive/client/versionSelector/VersionSelectorCache.tsx +++ b/xp-archive/client/versionSelector/VersionSelectorCache.tsx @@ -1,14 +1,19 @@ import React from 'react'; import { VersionReference } from 'shared/types'; -const contentCache: Record< - string, - { - component: React.ReactNode | null; - versions: VersionReference[]; - isOpen: boolean; - } -> = {}; +type VersionSelectorCacheItem = { + component: React.ReactNode | null; + versions: VersionReference[]; + isOpen: boolean; +}; + +const DEFAULT_CACHE: VersionSelectorCacheItem = { + component: null, + versions: [], + isOpen: false, +}; + +const contentCache: Record = {}; export const setCachedVersionSelector = ( contentId: string, @@ -29,17 +34,11 @@ export const setCachedVersionSelector = ( }; }; -export const getCachedVersionSelector = (contentId: string) => { - return ( - contentCache[contentId] || { - component: null, - versions: [], - isOpen: false, - } - ); +export const getCachedVersionSelector = (contentId: string): VersionSelectorCacheItem => { + return contentCache[contentId] || DEFAULT_CACHE; }; -export const clearCachedVersionSelector = (contentId: string) => { +export const clearCachedVersionSelector = (contentId: string): void => { if (contentId in contentCache) { delete contentCache[contentId]; }