From 77f162f7a4e556b183b5c276f5808617ce1639f8 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Tue, 1 Oct 2024 23:53:35 +1300 Subject: [PATCH] Initial IDB functionality pass --- .../homebrew/editor/snippetbar/snippetbar.jsx | 4 +- client/homebrew/utils/useIDB.js | 80 ++++++++++++++++ client/homebrew/utils/versionHistory.js | 94 +++++++++++++------ package-lock.json | 6 ++ package.json | 3 +- 5 files changed, 155 insertions(+), 32 deletions(-) create mode 100644 client/homebrew/utils/useIDB.js diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index f183e0876..12658cd41 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -70,10 +70,10 @@ const Snippetbar = createClass({ if(historyExists(this.props.brew) != this.state.historyExists){ this.setState({ - historyExists : !this.state.historyExists + historyExists : !this.state.historyExists }); }; - + }, mergeCustomizer : function(oldValue, newValue, key) { diff --git a/client/homebrew/utils/useIDB.js b/client/homebrew/utils/useIDB.js new file mode 100644 index 000000000..03404160a --- /dev/null +++ b/client/homebrew/utils/useIDB.js @@ -0,0 +1,80 @@ +import { + get as iGet, + getMany as iGetMany, + set as iSet, + setMany as iSetMany, + update as iUpdate, + del as iDel, + keys, + createStore, + Store +} from 'idb-keyval/dist/index.js'; // EcmaScript Module + +const HOMEBREWERY_DB = 'HOMEBREWERY-DB'; +const HOMEBREWERY_STORE = 'HOMEBREWERY-STORE'; + +let hbStore; + +function init(){ + if(hbStore) return true; + if(!hbStore && typeof window != 'undefined' && typeof window.indexedDB != 'undefined'){ + hbStore = createStore(HOMEBREWERY_DB, HOMEBREWERY_STORE); + return true; + } + return false; +} + +function checkFn(fn){ + return init() && fn(); +}; + +const get = checkFn(async (key)=>{ + console.log('get:', key); + return iGet(key, hbStore); +}); + +const getMany = checkFn(async (keys)=>{ + checkFn(async ()=>{ + console.log('getMany:', keys); + return await iGetMany(keys, hbStore); + }); +}); + +const set = checkFn(async (key, val)=>{ + console.log('set:', key, val); + init(); + return iSet(key, val, hbStore); +}); + +const setMany = checkFn(async (keyValArray)=>{ + console.log('set:', keyValArray); + init(); + return iSetMany(keyValArray, hbStore); +}); + + +const update = checkFn(async (key, updateFn)=>{ + init(); + return iUpdate(key, updateFn, hbStore); +}); + +const remove = checkFn(async (key)=>{ + console.log('remove:', key); + init(); + return iDel(key, hbStore); +}); + +const list = checkFn(async ()=>{ + init(); + return await keys(hbStore); +}); + +module.exports = { + get, + getMany, + set, + setMany, + update, + remove, + list +}; \ No newline at end of file diff --git a/client/homebrew/utils/versionHistory.js b/client/homebrew/utils/versionHistory.js index ad7c6102e..b86dc66e0 100644 --- a/client/homebrew/utils/versionHistory.js +++ b/client/homebrew/utils/versionHistory.js @@ -1,3 +1,5 @@ +import * as IDB from 'idb-keyval/dist/index.js'; + export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY'; export const HISTORY_SLOTS = 5; @@ -27,12 +29,12 @@ function getVersionBySlot(brew, slot){ // - If it exists, parse data to object // - If it doesn't exist, pass default object const key = getKeyBySlot(brew, slot); - const storedVersion = localStorage.getItem(key); - const output = storedVersion ? JSON.parse(storedVersion) : { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true }; + const storedVersion = IDB.get(key); + const output = storedVersion ? storedVersion : { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true }; return output; }; -function updateStoredBrew(brew, slot = 0) { +function parseBrewForStorage(brew, slot = 0) { const archiveBrew = { title : brew.title, text : brew.text, @@ -46,44 +48,77 @@ function updateStoredBrew(brew, slot = 0) { archiveBrew.expireAt.setMinutes(archiveBrew.expireAt.getMinutes() + HISTORY_SAVE_DELAYS[slot]); const key = getKeyBySlot(brew, slot); - localStorage.setItem(key, JSON.stringify(archiveBrew)); + + return [key, archiveBrew]; } -export function historyExists(brew){ - return Object.keys(localStorage) - .some((key)=>{ - return key.startsWith(`${HISTORY_PREFIX}-${brew.shareId}`); - }); +export async function historyExists(brew){ + console.log('HISTORY CHECK'); + const historyExists = await IDB.keys() + .then((keys)=>{ + return [...keys].some((key)=>{ + return key.startsWith(`${HISTORY_PREFIX}-${brew.shareId}`); + }); + }) + .catch(()=>{return false;}); + console.log('HISTORY STATE:', historyExists); } -export function loadHistory(brew){ - const history = {}; +export async function loadHistory(brew){ + const DEFAULT_HISTORY_ITEM = { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true }; + + const historyKeys = []; // Load data from local storage to History object for (let i = 1; i <= HISTORY_SLOTS; i++){ - history[i] = getVersionBySlot(brew, i); + historyKeys.push(getKeyBySlot(brew, i)); }; + const history = []; + await IDB.getMany(historyKeys) + .then((dataArray)=>{ + return dataArray.forEach((data)=>{ + history.push(data ?? DEFAULT_HISTORY_ITEM); + }); + }) + .catch(()=>{ + historyKeys.forEach(()=>{ + history.push(DEFAULT_HISTORY_ITEM); + }); + }); + return history; } -export function updateHistory(brew) { - const history = loadHistory(brew); +export async function updateHistory(brew) { + const history = await loadHistory(brew); + + console.log('DATA:', history); // Walk each version position - for (let slot = HISTORY_SLOTS; slot > 0; slot--){ + for (let slot = HISTORY_SLOTS - 1; slot >= 0; slot--){ + console.log('SLOT #:', slot, history[slot]); const storedVersion = history[slot]; // If slot has expired, update all lower slots and break if(new Date() >= new Date(storedVersion.expireAt)){ - for (let updateSlot = slot - 1; updateSlot>0; updateSlot--){ + const historyUpdate = []; + + for (let updateSlot = slot - 1; updateSlot > 0; updateSlot--){ + console.log('CHECK DATA IN SLOT #:', updateSlot); // Move data from updateSlot to updateSlot + 1 - !history[updateSlot]?.noData && updateStoredBrew(history[updateSlot], updateSlot + 1); + if(!history[updateSlot - 1]?.noData) { + console.log('UPDATE SLOT #:', updateSlot - 1, '>', updateSlot); + historyUpdate.push(parseBrewForStorage(history[updateSlot - 1], updateSlot + 1)); + } }; // Update the most recent brew - updateStoredBrew(brew, 1); + historyUpdate.push(parseBrewForStorage(brew, 1)); + + console.log('HISTORY UPDATE OBJECT:', historyUpdate); + IDB.setMany(historyUpdate); // Break out of data checks because we found an expired value break; @@ -102,15 +137,16 @@ export function getHistoryItems(brew){ }; export function versionHistoryGarbageCollection(){ - Object.keys(localStorage) - .filter((key)=>{ - return key.startsWith(HISTORY_PREFIX); - }) - .forEach((key)=>{ - const collectAt = new Date(JSON.parse(localStorage.getItem(key)).savedAt); - collectAt.setMinutes(collectAt.getMinutes() + GARBAGE_COLLECT_DELAY); - if(new Date() > collectAt){ - localStorage.removeItem(key); - } - }); + console.log('Version History Garbage Collection'); + // Object.keys(IDB) + // .filter((key)=>{ + // return key.startsWith(HISTORY_PREFIX); + // }) + // .forEach((key)=>{ + // const collectAt = new Date(JSON.parse(IDB.get(key)).savedAt); + // collectAt.setMinutes(collectAt.getMinutes() + GARBAGE_COLLECT_DELAY); + // if(new Date() > collectAt){ + // IDB.removeItem(key); + // } + // }); }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index cb0299d4e..9645f64e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "express-async-handler": "^1.2.0", "express-static-gzip": "2.1.8", "fs-extra": "11.2.0", + "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", "jwt-simple": "^0.5.6", "less": "^3.13.1", @@ -7451,6 +7452,11 @@ "node": ">=0.10.0" } }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", diff --git a/package.json b/package.json index c78a08f25..917a09a96 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "express-async-handler": "^1.2.0", "express-static-gzip": "2.1.8", "fs-extra": "11.2.0", + "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", "jwt-simple": "^0.5.6", "less": "^3.13.1", @@ -138,4 +139,4 @@ "stylelint-config-recommended": "^14.0.1", "supertest": "^7.0.0" } -} \ No newline at end of file +}