Skip to content

Commit

Permalink
Merge pull request #602 from nfdi4plants/Feature_Swate_RefactoreLocal…
Browse files Browse the repository at this point in the history
…StorageUsage

Feature swate refactore local storage usage
  • Loading branch information
Freymaurer authored Jan 28, 2025
2 parents 9d06057 + 4e60af4 commit 9f3e2f1
Show file tree
Hide file tree
Showing 12 changed files with 586 additions and 78 deletions.
19 changes: 15 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"cytoscape": "^3.27.0",
"isomorphic-fetch": "^3.0.0",
"jsonschema": "^1.4.1",
"pako": "^2.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"use-sync-external-store": "^1.2.0"
Expand Down
3 changes: 2 additions & 1 deletion src/Client/Client.fsproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -25,6 +25,7 @@
<Compile Include="OfficeInterop\ExcelHelper.fs" />
<Compile Include="OfficeInterop\ArcTableHelper.fs" />
<Compile Include="OfficeInterop\OfficeInterop.fs" />
<Compile Include="States\IndexedDB.fs" />
<Compile Include="States\DataAnnotator.fs" />
<Compile Include="States\ARCitect.fs" />
<Compile Include="States\SpreadsheetInterface.fs" />
Expand Down
1 change: 1 addition & 0 deletions src/Client/MainComponents/Cells.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ open Shared
open ARCtrl
open Components
open Model

module private CellAux =

let headerTSRSetter (columnIndex: int, s: string, header: CompositeHeader, dispatch) =
Expand Down
2 changes: 1 addition & 1 deletion src/Client/MainComponents/Navbar.fs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ let Main(model: Model, dispatch, widgets, setWidgets) =
]
Daisy.navbarCenter [
prop.children [
// QuickAccessButtonListStart model.History dispatch
QuickAccessButtonListStart model.History dispatch
WidgetNavbarList(model, dispatch, addWidget)
]
]
Expand Down
37 changes: 20 additions & 17 deletions src/Client/Messages.fs
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,29 @@ type TopLevelMsg =
| CloseSuggestions

type Msg =
| UpdateModel of Model
| DevMsg of DevMsg
| OntologyMsg of Ontologies.Msg
| TermSearchMsg of TermSearch.Msg
| AdvancedSearchMsg of AdvancedSearch.Msg
| OfficeInteropMsg of OfficeInterop.Msg
| PersistentStorageMsg of PersistentStorage.Msg
| FilePickerMsg of FilePicker.Msg
| BuildingBlockMsg of BuildingBlock.Msg
| ProtocolMsg of Protocol.Msg
| UpdateModel of Model
| DevMsg of DevMsg
| OntologyMsg of Ontologies.Msg
| TermSearchMsg of TermSearch.Msg
| AdvancedSearchMsg of AdvancedSearch.Msg
| OfficeInteropMsg of OfficeInterop.Msg
| PersistentStorageMsg of PersistentStorage.Msg
| FilePickerMsg of FilePicker.Msg
| BuildingBlockMsg of BuildingBlock.Msg
| ProtocolMsg of Protocol.Msg
// | CytoscapeMsg of Cytoscape.Msg
| DataAnnotatorMsg of DataAnnotator.Msg
| SpreadsheetMsg of Spreadsheet.Msg
| DataAnnotatorMsg of DataAnnotator.Msg
| SpreadsheetMsg of Spreadsheet.Msg
/// This is used to forward Msg to SpreadsheetMsg/OfficeInterop
| InterfaceMsg of SpreadsheetInterface.Msg
| Batch of seq<Messages.Msg>
| Run of (unit -> unit)
| UpdateHistory of LocalHistory.Model
| InterfaceMsg of SpreadsheetInterface.Msg
| Batch of seq<Messages.Msg>
| Run of (unit -> unit)
| UpdateHistory of LocalHistory.Model
| UpdateHistoryAnd of LocalHistory.Model * Cmd<Msg>
| UpdateSpreadSheetModel of Spreadsheet.Model
| UpdateHistoryPosition of int
/// Top level msg to test specific api interactions, only for dev.
| TestMyAPI
| TestMyPostAPI
| UpdateModal of Model.ModalState.ModalTypes option
| UpdateModal of Model.ModalState.ModalTypes option
| DoNothing
219 changes: 219 additions & 0 deletions src/Client/States/IndexedDB.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
module IndexedDB

open Fable.Core
open JsInterop

open System

/// <summary>
/// Create or update an indexed database
/// </summary>
/// <param name="dbName"></param>
/// <param name="version"></param>
let createDatabase (dbName: string) version tableKey =
promise {
let indexedDB = emitJsExpr<obj>("globalThis.indexedDB") "globalThis.indexedDB"
let request: obj = indexedDB?``open``(dbName, version)
let! db =
Async.FromContinuations(fun (resolve, reject, _) ->
request?onsuccess <- fun _ -> resolve(request?result)
request?onerror <- fun _ -> reject(new Exception(request?error?message))
request?onupgradeneeded <- fun e ->
let resultDb = e?target?result
if resultDb?objectStoreNames?contains(tableKey) |> not then
let _ = resultDb?createObjectStore(tableKey)
resolve(request?result)
else
resolve(request?result)
)
|> Async.StartAsPromise
return db
}

/// <summary>
/// Create or update an indexed database
/// </summary>
/// <param name="dbName"></param>
/// <param name="version"></param>
let rec openDatabase (dbName: string) (tableKey: string) =
promise {
let indexedDB = emitJsExpr<obj>("globalThis.indexedDB") "globalThis.indexedDB"
let request: obj = indexedDB?``open``(dbName)
let! db =
Async.FromContinuations(fun (resolve, reject, _) ->
request?onsuccess <- fun e ->
let resultDb = e?target?result
let version = resultDb?version
if resultDb?objectStoreNames?contains(tableKey) |> not then
resultDb?close() // Close the current db instance to avoid transaction problems
let _ =
createDatabase dbName (version + 1) tableKey
|> Promise.start
resolve(None)
else
resolve(Some request?result)
request?onerror <- fun _ -> reject(new Exception(request?error?message))
)
|> Async.StartAsPromise
match db with
| Some db -> return db
| None -> return! openDatabase dbName tableKey
}

/// <summary>
/// Closes the given db and associated transactions
/// </summary>
/// <param name="db"></param>
let closeDatabase db =
db?close()

/// <summary>
/// Initializes the indexedDB and its associated tables
/// </summary>
/// <param name="dbName"></param>
/// <param name="tableKeys"></param>
let initInidexedDB (dbName: string) (tableKeys: string []) =
promise {
for tableKey in tableKeys do
let! db = openDatabase dbName tableKey
closeDatabase db
}

let clearTable db (tableKey: string) =
promise {
if db?objectStoreNames?contains(tableKey) then
let transaction = db?transaction(tableKey, "readwrite")
let store = transaction?objectStore(tableKey)
let storeRequest = store?clear()
do! Async.FromContinuations(fun (resolve, reject, _) ->
storeRequest?onsuccess <- fun _ -> resolve(storeRequest?result)
storeRequest?onerror <- fun _ -> reject(new Exception(storeRequest?error?message))
)
|> Async.StartAsPromise
}

let clearInidexedDB (dbName: string) (tableKeys: string []) =
promise {
for tableKey in tableKeys do
let! db = openDatabase dbName tableKey
do! clearTable db tableKey
closeDatabase db
}

/// <summary>
/// Add item to indexedDB
/// </summary>
/// <param name="db"></param>
/// <param name="tableKey"></param>
/// <param name="item"></param>
/// <param name="key"></param>
let addItem db (tableKey: string) (item: obj) (key: string) =
promise {
if db?objectStoreNames?contains(tableKey) then
let transaction = db?transaction(tableKey, "readwrite")
let store = transaction?objectStore(tableKey)
let storeRequest = store?add(item, key)
do! Async.FromContinuations(fun (resolve, reject, _) ->
storeRequest?onsuccess <- fun _ -> resolve(storeRequest?result)
storeRequest?onerror <- fun _ -> reject(new Exception(storeRequest?error?message))
)
|> Async.StartAsPromise
}

/// <summary>
/// Delete item from indexedDB
/// </summary>
/// <param name="db"></param>
/// <param name="tableKey"></param>
/// <param name="key"></param>
let deleteItem db (tableKey: string) (key: string) =
promise {
if db?objectStoreNames?contains(tableKey) then
let transaction = db?transaction(tableKey, "readwrite")
let store = transaction?objectStore(tableKey)
let storeRequest = store?delete(key)
do! Async.FromContinuations(fun (resolve, reject, _) ->
storeRequest?onsuccess <- fun _ -> resolve(storeRequest?result)
storeRequest?onerror <- fun _ -> reject(new Exception(storeRequest?error?message))
)
|> Async.StartAsPromise
}

/// <summary>
/// Update an existing item in the IndexedDB object store
/// </summary>
/// <param name="db"></param>
/// <param name="storeName"></param>
/// <param name="data"></param>
let updateItem db (tableKey: string) (item: obj) (key: string) =
promise {
if db?objectStoreNames?contains(tableKey) then
let transaction = db?transaction(tableKey, "readwrite")
let store = transaction?objectStore(tableKey)
let storeRequest = store?put(item, key)
do! Async.FromContinuations(fun (resolve, reject, _) ->
storeRequest?onsuccess <- fun _ -> resolve(storeRequest?result)
storeRequest?onerror <- fun _ -> reject(new Exception(storeRequest?error?message))
)
|> Async.StartAsPromise
}

/// <summary>
/// Retrive a specific item from the database
/// </summary>
/// <param name="db"></param>
/// <param name="localStorage"></param>
/// <param name="key"></param>
let tryGetItem (db: obj) (tableKey: string) (key: string) =
promise {
if db?objectStoreNames?contains(tableKey) then
let transaction = db?transaction(tableKey, "readonly")
let store = transaction?objectStore(tableKey)
let storeRequest = store?get(key)
let! item =
Async.FromContinuations(fun (resolve, reject, _) ->
storeRequest?onsuccess <- fun _ -> resolve(storeRequest?result)
storeRequest?onerror <- fun _ -> reject(new Exception(storeRequest?error?message))
)
|> Async.StartAsPromise

if isNullOrUndefined item then
return None
else
let result = item.ToString()
if String.IsNullOrEmpty result then
return None
else return Some result
else
return None
}

/// <summary>
/// Retrive all items from the database
/// </summary>
/// <param name="db"></param>
/// <param name="localStorage"></param>
let getAllItems (db: obj) (tableKey: string) =
promise {
if db?objectStoreNames?contains(tableKey) then
let transaction = db?transaction(tableKey, "readonly")
let store = transaction?objectStore(tableKey)
let storeRequest = store?getAll()

let! item =
Async.FromContinuations(fun (resolve, reject, _) ->
storeRequest?onsuccess <- fun _ -> resolve(storeRequest?result)
storeRequest?onerror <- fun _ -> reject(new Exception(storeRequest?error?message "Failed to open database"))
)
|> Async.StartAsPromise

if isNullOrUndefined item then
return None
else
let result = item.ToString()
if String.IsNullOrEmpty result then
return None
else return Some result
else
return None
}
Loading

0 comments on commit 9f3e2f1

Please sign in to comment.