diff --git a/README.DOCKER.md b/README.DOCKER.md index 4dfbef045..c3b38224d 100644 --- a/README.DOCKER.md +++ b/README.DOCKER.md @@ -49,7 +49,7 @@ Make an changes you need to `config/docker.json` then build the image. If it doe "web_port" : 8000, "enable_v3" : true, "mongodb_uri": "mongodb://172.17.0.2/homebrewery", -"enable_themes" : true, +"enable_themes" : true } ``` @@ -90,6 +90,13 @@ docker run --name homebrewery-mongodb -d --restart unless-stopped -v mongodata:/ docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest ``` +**NOTE:** If you are running from the Windows command line, this will not work as `$(pwd)` is not valid syntax. Use this command instead: +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v %cd%/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + + ## Updating the Image When Homebrewery code updates, your docker container will not automatically follow the changes. To do so you will need to rebuild your homebrewery image. @@ -117,3 +124,9 @@ docker-compose build homebrewery docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v $(pwd)/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest ``` +**NOTE:** If you are running from the Windows command line, this will not work as `$(pwd)` is not valid syntax. Use this command instead: +```shell +# Make sure you run this in the homebrewery directory +docker run --name homebrewery-app -d --restart unless-stopped -e NODE_ENV=docker -v %cd%/config/docker.json:/usr/src/app/config/docker.json -p 8000:8000 docker.io/library/homebrewery:latest +``` + diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index 29973d221..787c2a3eb 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -7,15 +7,17 @@ import LockTools from './lockTools/lockTools.jsx'; const tabGroups = ['brew', 'notifications', 'authors', 'locks']; +const ADMIN_TAB = 'HB_adminPage_currentTab'; + const Admin = ()=>{ const [currentTab, setCurrentTab] = useState(''); useEffect(()=>{ - setCurrentTab(localStorage.getItem('hbAdminTab') || 'brew'); + setCurrentTab(localStorage.getItem(ADMIN_TAB) || 'brew'); }, []); useEffect(()=>{ - localStorage.setItem('hbAdminTab', currentTab); + localStorage.setItem(ADMIN_TAB, currentTab); }, [currentTab]); return ( diff --git a/client/components/splitPane/splitPane.jsx b/client/components/splitPane/splitPane.jsx index 4c77d81a5..78ba59ed3 100644 --- a/client/components/splitPane/splitPane.jsx +++ b/client/components/splitPane/splitPane.jsx @@ -2,7 +2,8 @@ require('./splitPane.less'); const React = require('react'); const { useState, useEffect } = React; -const storageKey = 'naturalcrit-pane-split'; +const PANE_WIDTH_KEY = 'HB_editor_splitWidth'; +const LIVE_SCROLL_KEY = 'HB_editor_liveScroll'; const SplitPane = (props)=>{ const { @@ -18,9 +19,9 @@ const SplitPane = (props)=>{ const [liveScroll, setLiveScroll] = useState(false); useEffect(()=>{ - const savedPos = window.localStorage.getItem(storageKey); + const savedPos = window.localStorage.getItem(PANE_WIDTH_KEY); setDividerPos(savedPos ? limitPosition(savedPos, 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13)) : window.innerWidth / 2); - setLiveScroll(window.localStorage.getItem('liveScroll') === 'true'); + setLiveScroll(window.localStorage.getItem(LIVE_SCROLL_KEY) === 'true'); window.addEventListener('resize', handleResize); return ()=>window.removeEventListener('resize', handleResize); @@ -29,13 +30,13 @@ const SplitPane = (props)=>{ const limitPosition = (x, min = 1, max = window.innerWidth - 13)=>Math.round(Math.min(max, Math.max(min, x))); //when resizing, the divider should grow smaller if less space is given, then grow back if the space is restored, to the original position - const handleResize = ()=>setDividerPos(limitPosition(window.localStorage.getItem(storageKey), 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13))); + const handleResize = ()=>setDividerPos(limitPosition(window.localStorage.getItem(PANE_WIDTH_KEY), 0.1 * (window.innerWidth - 13), 0.9 * (window.innerWidth - 13))); const handleUp =(e)=>{ e.preventDefault(); if(isDragging) { onDragFinish(dividerPos); - window.localStorage.setItem(storageKey, dividerPos); + window.localStorage.setItem(PANE_WIDTH_KEY, dividerPos); } setIsDragging(false); }; @@ -52,7 +53,7 @@ const SplitPane = (props)=>{ }; const liveScrollToggle = ()=>{ - window.localStorage.setItem('liveScroll', String(!liveScroll)); + window.localStorage.setItem(LIVE_SCROLL_KEY, String(!liveScroll)); setLiveScroll(!liveScroll); }; diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 7a101e9f9..bda7143fc 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -24,6 +24,8 @@ const PAGEBREAK_REGEX_LEGACY = /\\page(?:break)?/m; const COLUMNBREAK_REGEX_LEGACY = /\\column(:?break)?/m; const PAGE_HEIGHT = 1056; +const TOOLBAR_STATE_KEY = 'HB_renderer_toolbarState'; + const INITIAL_CONTENT = dedent` @@ -122,7 +124,7 @@ const BrewRenderer = (props)=>{ //useEffect to store or gather toolbar state from storage useEffect(()=>{ - const toolbarState = JSON.parse(window.localStorage.getItem('hb_toolbarState')); + const toolbarState = JSON.parse(window.localStorage.getItem(TOOLBAR_STATE_KEY)); toolbarState && setDisplayOptions(toolbarState); }, []); @@ -284,7 +286,7 @@ const BrewRenderer = (props)=>{ const handleDisplayOptionsChange = (newDisplayOptions)=>{ setDisplayOptions(newDisplayOptions); - localStorage.setItem('hb_toolbarState', JSON.stringify(newDisplayOptions)); + localStorage.setItem(TOOLBAR_STATE_KEY, JSON.stringify(newDisplayOptions)); }; const pagesStyle = { diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index 6938eacb7..4aee3b6bd 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.jsx +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -9,6 +9,8 @@ import { Anchored, AnchoredBox, AnchoredTrigger } from '../../../components/Anch const MAX_ZOOM = 300; const MIN_ZOOM = 10; +const TOOLBAR_VISIBILITY = 'HB_renderer_toolbarVisibility'; + const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPages, headerState, setHeaderState })=>{ const [pageNum, setPageNum] = useState(1); @@ -21,8 +23,8 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa }, [visiblePages]); useEffect(()=>{ - const Visibility = localStorage.getItem('hb_toolbarVisibility'); - if (Visibility) setToolsVisible(Visibility === 'true'); + const Visibility = localStorage.getItem(TOOLBAR_VISIBILITY); + if(Visibility) setToolsVisible(Visibility === 'true'); }, []); @@ -100,7 +102,7 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9f9e23625..a067ac4af 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -10,7 +10,7 @@ const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); const SnippetBar = require('./snippetbar/snippetbar.jsx'); const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); -const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME'; +const EDITOR_THEME_KEY = 'HB_editor_theme'; const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/; @@ -140,7 +140,7 @@ const Editor = createClass({ handleViewChange : function(newView){ this.props.setMoveArrows(newView === 'text'); - + this.setState({ view : newView }, ()=>{ diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index a6b4b9175..1aff5067d 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -4,6 +4,8 @@ import './homebrew.less'; import React from 'react'; import { StaticRouter as Router, Route, Routes, useParams, useSearchParams } from 'react-router'; +import { updateLocalStorage } from './utils/updateLocalStorage/updateLocalStorageKeys.js'; + import HomePage from './pages/homePage/homePage.jsx'; import EditPage from './pages/editPage/editPage.jsx'; import UserPage from './pages/userPage/userPage.jsx'; @@ -48,6 +50,8 @@ const Homebrew = (props)=>{ global.enable_themes = enable_themes; global.config = config; + updateLocalStorage(); + return (
diff --git a/client/homebrew/navbar/recent.navitem.jsx b/client/homebrew/navbar/recent.navitem.jsx index a6cbbf406..4c4722515 100644 --- a/client/homebrew/navbar/recent.navitem.jsx +++ b/client/homebrew/navbar/recent.navitem.jsx @@ -5,8 +5,8 @@ const Moment = require('moment'); const Nav = require('naturalcrit/nav/nav.jsx'); -const EDIT_KEY = 'homebrewery-recently-edited'; -const VIEW_KEY = 'homebrewery-recently-viewed'; +const EDIT_KEY = 'HB_nav_recentlyEdited'; +const VIEW_KEY = 'HB_nav_recentlyViewed'; const RecentItems = createClass({ diff --git a/client/homebrew/pages/accountPage/accountPage.jsx b/client/homebrew/pages/accountPage/accountPage.jsx index 598683504..b69eb6e3e 100644 --- a/client/homebrew/pages/accountPage/accountPage.jsx +++ b/client/homebrew/pages/accountPage/accountPage.jsx @@ -13,7 +13,7 @@ const AccountPage = (props)=>{ // initialize save location from local storage based on user id React.useEffect(()=>{ if(!saveLocation && accountDetails.username) { - SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${accountDetails.username}`; + SAVEKEY = `HB_editor_defaultSave_${accountDetails.username}`; // if no SAVEKEY in local storage, default save location to Google Drive if user has Google account. let saveLocation = window.localStorage.getItem(SAVEKEY); saveLocation = saveLocation ?? (accountDetails.googleId ? 'GOOGLE-DRIVE' : 'HOMEBREWERY'); diff --git a/client/homebrew/pages/basePages/listPage/listPage.jsx b/client/homebrew/pages/basePages/listPage/listPage.jsx index ec557ffb1..4afc14364 100644 --- a/client/homebrew/pages/basePages/listPage/listPage.jsx +++ b/client/homebrew/pages/basePages/listPage/listPage.jsx @@ -7,7 +7,9 @@ const moment = require('moment'); const BrewItem = require('./brewItem/brewItem.jsx'); -const USERPAGE_KEY_PREFIX = 'HOMEBREWERY-LISTPAGE'; +const USERPAGE_SORT_DIR = 'HB_listPage_sortDir'; +const USERPAGE_SORT_TYPE = 'HB_listPage_sortType'; +const USERPAGE_GROUP_VISIBILITY_PREFIX = 'HB_listPage_visibility_group'; const DEFAULT_SORT_TYPE = 'alpha'; const DEFAULT_SORT_DIR = 'asc'; @@ -50,12 +52,12 @@ const ListPage = createClass({ // LOAD FROM LOCAL STORAGE if(typeof window !== 'undefined') { - const newSortType = (this.state.sortType ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`) || DEFAULT_SORT_TYPE)); - const newSortDir = (this.state.sortDir ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`) || DEFAULT_SORT_DIR)); + const newSortType = (this.state.sortType ?? (localStorage.getItem(USERPAGE_SORT_TYPE) || DEFAULT_SORT_TYPE)); + const newSortDir = (this.state.sortDir ?? (localStorage.getItem(USERPAGE_SORT_DIR) || DEFAULT_SORT_DIR)); this.updateUrl(this.state.filterString, newSortType, newSortDir); const brewCollection = this.props.brewCollection.map((brewGroup)=>{ - brewGroup.visible = (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`) ?? 'true')=='true'; + brewGroup.visible = (localStorage.getItem(`${USERPAGE_GROUP_VISIBILITY_PREFIX}_${brewGroup.class}`) ?? 'true')=='true'; return brewGroup; }); @@ -73,10 +75,10 @@ const ListPage = createClass({ saveToLocalStorage : function() { this.state.brewCollection.map((brewGroup)=>{ - localStorage.setItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`, `${brewGroup.visible}`); + localStorage.setItem(`${USERPAGE_GROUP_VISIBILITY_PREFIX}_${brewGroup.class}`, `${brewGroup.visible}`); }); - localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`, this.state.sortType); - localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`, this.state.sortDir); + localStorage.setItem(USERPAGE_SORT_TYPE, this.state.sortType); + localStorage.setItem(USERPAGE_SORT_DIR, this.state.sortDir); }, renderBrews : function(brews){ diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 3bc118f4c..e3d449a55 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -39,10 +39,13 @@ const SAVE_TIMEOUT = 10000; const UNSAVED_WARNING_TIMEOUT = 900000; //Warn user afer 15 minutes of unsaved changes const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds -const BREWKEY = 'homebrewery-new'; -const STYLEKEY = 'homebrewery-new-style'; -const SNIPKEY = 'homebrewery-new-snippets'; -const METAKEY = 'homebrewery-new-meta'; + +const AUTOSAVE_KEY = 'HB_editor_autoSaveOn'; +const BREWKEY = 'HB_newPage_content'; +const STYLEKEY = 'HB_newPage_style'; +const SNIPKEY = 'HB_newPage_snippets'; +const METAKEY = 'HB_newPage_meta'; + const useLocalStorage = false; @@ -77,7 +80,7 @@ const EditPage = (props)=>{ const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges useEffect(()=>{ - const autoSavePref = JSON.parse(localStorage.getItem('AUTOSAVE_ON') ?? true); + const autoSavePref = JSON.parse(localStorage.getItem(AUTOSAVE_KEY) ?? true); setAutoSaveEnabled(autoSavePref); setWarnUnsavedChanges(!autoSavePref); setHTMLErrors(Markdown.validate(currentBrew.text)); @@ -319,7 +322,7 @@ const EditPage = (props)=>{ const toggleAutoSave = ()=>{ clearTimeout(warnUnsavedTimeout.current); clearTimeout(saveTimeout.current); - localStorage.setItem('AUTOSAVE_ON', JSON.stringify(!autoSaveEnabled)); + localStorage.setItem(AUTOSAVE_KEY, JSON.stringify(!autoSaveEnabled)); setAutoSaveEnabled(!autoSaveEnabled); setWarnUnsavedChanges(autoSaveEnabled); }; diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index dc5cc155a..d1d1fa75c 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -26,11 +26,13 @@ import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx'; // Page specific imports import { Meta } from 'vitreum/headtags'; -const BREWKEY = 'homebrewery-new'; -const STYLEKEY = 'homebrewery-new-style'; -const SNIPKEY = 'homebrewery-new-snippets'; -const METAKEY = 'homebrewery-new-meta'; -const SAVEKEYPREFIX = 'HOMEBREWERY-DEFAULT-SAVE-LOCATION-'; + +const BREWKEY = 'HB_newPage_content'; +const STYLEKEY = 'HB_newPage_style'; +const METAKEY = 'HB_newPage_metadata'; +const SNIPKEY = 'HB_newPage_snippets'; +const SAVEKEYPREFIX = 'HB_editor_defaultSave_'; + const useLocalStorage = true; diff --git a/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js new file mode 100644 index 000000000..b4a05974f --- /dev/null +++ b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js @@ -0,0 +1,35 @@ + +const getLocalStorageMap = function(){ + const localStorageMap = { + 'AUTOSAVE_ON' : 'HB_editor_autoSaveOn', + 'HOMEBREWERY-EDITOR-THEME' : 'HB_editor_theme', + 'liveScroll' : 'HB_editor_liveScroll', + 'naturalcrit-pane-split' : 'HB_editor_splitWidth', + + 'HOMEBREWERY-LISTPAGE-SORTDIR' : 'HB_listPage_sortDir', + 'HOMEBREWERY-LISTPAGE-SORTTYPE' : 'HB_listPage_sortType', + 'HOMEBREWERY-LISTPAGE-VISIBILITY-published' : 'HB_listPage_visibility_group_published', + 'HOMEBREWERY-LISTPAGE-VISIBILITY-unpublished' : 'HB_listPage_visibility_group_unpublished', + + 'hbAdminTab' : 'HB_adminPage_currentTab', + + 'homebrewery-new' : 'HB_newPage_content', + 'homebrewery-new-meta' : 'HB_newPage_metadata', + 'homebrewery-new-style' : 'HB_newPage_style', + + 'homebrewery-recently-edited' : 'HB_nav_recentlyEdited', + 'homebrewery-recently-viewed' : 'HB_nav_recentlyViewed', + + 'hb_toolbarState' : 'HB_renderer_toolbarState', + 'hb_toolbarVisibility' : 'HB_renderer_toolbarVisibility' + }; + + if(global?.account?.username){ + const username = global.account.username; + localStorageMap[`HOMEBREWERY-DEFAULT-SAVE-LOCATION-${username}`] = `HB_editor_defaultSave_${username}`; + } + + return localStorageMap; +}; + +export default getLocalStorageMap; \ No newline at end of file diff --git a/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js new file mode 100644 index 000000000..ac61d4add --- /dev/null +++ b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js @@ -0,0 +1,30 @@ +import getLocalStorageMap from './localStorageKeyMap.js'; + +describe('getLocalStorageMap', ()=>{ + it('no username', ()=>{ + const account = global.account; + + delete global.account; + + const map = getLocalStorageMap(); + + global.account = account; + + expect(map).toBeInstanceOf(Object); + expect(Object.entries(map)).toHaveLength(16); + }); + + it('no username', ()=>{ + const account = global.account; + + global.account = { username: 'test' }; + + const map = getLocalStorageMap(); + + global.account = account; + + expect(map).toBeInstanceOf(Object); + expect(Object.entries(map)).toHaveLength(17); + expect(map).toHaveProperty('HOMEBREWERY-DEFAULT-SAVE-LOCATION-test', 'HB_editor_defaultSave_test'); + }); +}); \ No newline at end of file diff --git a/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js b/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js new file mode 100644 index 000000000..1a8231f73 --- /dev/null +++ b/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js @@ -0,0 +1,25 @@ +import getLocalStorageMap from './localStorageKeyMap.js'; + +const updateLocalStorage = function(){ + // Return if no window and thus no local storage + if(typeof window === 'undefined') return; + + // Return if the local storage key map has no content + const localStorageKeyMap = getLocalStorageMap(); + if(Object.keys(localStorageKeyMap).length == 0) return; + + const storage = window.localStorage; + + Object.keys(localStorageKeyMap).forEach((key)=>{ + if(storage[key]){ + if(!storage[localStorageKeyMap[key]]){ + const data = storage.getItem(key); + storage.setItem(localStorageKeyMap[key], data); + }; + storage.removeItem(key); + } + }); + +}; + +export { updateLocalStorage }; \ No newline at end of file