diff --git a/package-lock.json b/package-lock.json
index a7dec072..b21e6339 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,6 +4,7 @@
"requires": true,
"packages": {
"": {
+ "name": "Swate",
"dependencies": {
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
@@ -2613,9 +2614,10 @@
"license": "MIT"
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
+ "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==",
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
diff --git a/src/Client/Client.fsproj b/src/Client/Client.fsproj
index 3fd60958..07c67a35 100644
--- a/src/Client/Client.fsproj
+++ b/src/Client/Client.fsproj
@@ -126,7 +126,7 @@
-
+
diff --git a/src/Client/Init.fs b/src/Client/Init.fs
index f27e7a91..577b6d7a 100644
--- a/src/Client/Init.fs
+++ b/src/Client/Init.fs
@@ -7,9 +7,7 @@ open Model
open Messages
open Update
-let initializeModel () =
- let dt = LocalStorage.Darkmode.DataTheme.GET()
- LocalStorage.Darkmode.DataTheme.SET dt
+let initialModel =
{
PageState = PageState .init()
PersistentStorageState = PersistentStorageState .init()
@@ -21,14 +19,12 @@ let initializeModel () =
ProtocolState = Protocol.Model .init()
CytoscapeModel = Cytoscape.Model .init()
DataAnnotatorModel = DataAnnotator.Model .init()
- SpreadsheetModel = Spreadsheet.Model .fromLocalStorage()
- History = LocalHistory.Model .init().UpdateFromSessionStorage()
+ SpreadsheetModel = Spreadsheet.Model .init()
+ History = LocalHistory.Model .init()
}
// defines the initial state and initial command (= side-effect) of the application
let init (pageOpt: Routing.Route option) : Model * Cmd =
- let initialModel, pageCmd = initializeModel () |> urlUpdate pageOpt
- let cmd = Cmd.ofMsg <| InterfaceMsg (SpreadsheetInterface.Initialize initialModel.PersistentStorageState.Host.Value)
- let batch = Cmd.batch [|pageCmd; cmd|]
- initialModel, batch
\ No newline at end of file
+ let model, cmd = urlUpdate pageOpt initialModel
+ model, cmd
\ No newline at end of file
diff --git a/src/Client/MainComponents/Navbar.fs b/src/Client/MainComponents/Navbar.fs
index 095c07c8..1111e5ec 100644
--- a/src/Client/MainComponents/Navbar.fs
+++ b/src/Client/MainComponents/Navbar.fs
@@ -163,7 +163,7 @@ let Main(model: Model, dispatch, widgets, setWidgets) =
]
Daisy.navbarCenter [
prop.children [
- QuickAccessButtonListStart model.History dispatch
+ // QuickAccessButtonListStart model.History dispatch
WidgetNavbarList(model, dispatch, addWidget)
]
]
diff --git a/src/Client/MainComponents/Widgets.fs b/src/Client/MainComponents/Widgets.fs
index 218ebce0..b31dd277 100644
--- a/src/Client/MainComponents/Widgets.fs
+++ b/src/Client/MainComponents/Widgets.fs
@@ -245,18 +245,21 @@ type Widget =
static member FilePicker (model, dispatch, rmv) =
let content = Html.div [
- FilePicker.uploadButton model dispatch
- if model.FilePickerState.FileNames <> [] then
- FilePicker.fileSortElements model dispatch
+ prop.className "@container/filePickerWidget min-w-32"
+ prop.children [
+ FilePicker.uploadButton model dispatch "@md/filePickerWidget:flex-row"
+ if model.FilePickerState.FileNames <> [] then
+ FilePicker.fileSortElements model dispatch
- Html.div [
- prop.style [style.maxHeight (length.px 350); style.overflow.auto]
- prop.children [
- FilePicker.FileNameTable.table model dispatch
+ Html.div [
+ prop.style [style.maxHeight (length.px 350); style.overflow.auto]
+ prop.children [
+ FilePicker.FileNameTable.table model dispatch
+ ]
]
- ]
- //fileNameElements model dispatch
- FilePicker.insertButton model dispatch
+ //fileNameElements model dispatch
+ FilePicker.insertButton model dispatch
+ ]
]
let prefix = WidgetLiterals.FilePicker
Widget.Base(content, prefix, rmv)
diff --git a/src/Client/Modals/SelectiveImportModal.fs b/src/Client/Modals/SelectiveImportModal.fs
index dddda498..8ee955e8 100644
--- a/src/Client/Modals/SelectiveImportModal.fs
+++ b/src/Client/Modals/SelectiveImportModal.fs
@@ -12,166 +12,139 @@ open Components
type SelectiveImportModal =
- static member private ImportTypeRadio(importType: TableJoinOptions, setImportType: TableJoinOptions -> unit) =
- let myradio(target: TableJoinOptions, txt: string) =
- let isChecked = importType = target
- Daisy.formControl [
- Daisy.label [
- prop.children [
- Daisy.radio [
- prop.name "importType"
- prop.isChecked isChecked
- prop.onChange (fun (b:bool) -> if b then setImportType target)
- ]
- Daisy.labelText txt
+ static member private Radio(radioGroup: string, txt:string, isChecked, onChange: bool -> unit, ?isDisabled: bool) =
+ let isDisabled = defaultArg isDisabled false
+ Daisy.formControl [
+ Daisy.label [
+ prop.className "cursor-pointer hover:bg-base-200 transition-colors"
+ prop.children [
+ Daisy.radio [
+ prop.disabled isDisabled
+ radio.xs
+ prop.name radioGroup
+ prop.isChecked isChecked
+ prop.onChange onChange
]
+ Daisy.labelText txt
]
]
- Daisy.card [
- Daisy.cardBody [
- Daisy.label [
- Daisy.labelText [
- Html.i [prop.className "fa-solid fa-cog"]
- Html.text (" Import Type")
- ]
- ]
- Html.div [
- prop.className "is-flex is-justify-content-space-between"
+ ]
+ static member private Box (title: string, icon: string, content: ReactElement, ?className: string list) =
+ Html.div [
+ prop.className [
+ "rounded shadow p-2 flex flex-col gap-2"
+ if className.IsSome then
+ className.Value |> String.concat " "
+ ]
+ prop.children [
+ Html.h3 [
+ prop.className "font-semibold gap-2 flex flex-row items-center"
prop.children [
- myradio(ARCtrl.TableJoinOptions.Headers, " Column Headers")
- myradio(ARCtrl.TableJoinOptions.WithUnit, " ..With Units")
- myradio(ARCtrl.TableJoinOptions.WithValues, " ..With Values")
+ Html.i [prop.className icon]
+ Html.span title
]
]
+ content
]
]
+ static member private ImportTypeRadio(importType: TableJoinOptions, setImportType: TableJoinOptions -> unit) =
+ let myradio(target: TableJoinOptions, txt: string) =
+ let isChecked = importType = target
+ SelectiveImportModal.Radio("importType", txt, isChecked, fun (b:bool) -> if b then setImportType target)
+ SelectiveImportModal.Box ("Import Type", "fa-solid fa-cog", React.fragment [
+ Html.div [
+ myradio(ARCtrl.TableJoinOptions.Headers, " Column Headers")
+ myradio(ARCtrl.TableJoinOptions.WithUnit, " ..With Units")
+ myradio(ARCtrl.TableJoinOptions.WithValues, " ..With Values")
+ ]
+ ])
+
static member private MetadataImport(isActive: bool, setActive: bool -> unit, disArcFile: ArcFilesDiscriminate) =
let name = string disArcFile
- Daisy.card [
- if isActive then prop.className "bg-info"
- prop.children [
- Html.div [
- Daisy.label [
- Daisy.labelText [
- Html.i [prop.className "fa-solid fa-lightbulb"]
- Html.textf " %s Metadata" name
- ]
- ]
- Daisy.formControl [
- Daisy.label [
- Daisy.checkbox [
- prop.type'.checkbox
- prop.onChange (fun (b:bool) -> setActive b)
- ]
- Daisy.labelText " Import"
+ SelectiveImportModal.Box (sprintf "%s Metadata" name, "fa-solid fa-lightbulb", React.fragment [
+ Daisy.formControl [
+ Daisy.label [
+ prop.className "cursor-pointer"
+ prop.children [
+ Daisy.checkbox [
+ prop.type'.checkbox
+ prop.onChange (fun (b:bool) -> setActive b)
]
- ]
- Html.span [
- prop.className "text-warning"
- prop.text "Importing metadata will overwrite the current file."
+ Daisy.labelText "Import"
]
]
]
- ]
+ Html.span [
+ prop.className "text-warning bg-warning-content flex flex-row gap-2 justify-center items-center"
+ prop.children [
+ Html.i [prop.className "fa-solid fa-exclamation-triangle"]
+ Html.text " Importing metadata will overwrite the current file."
+ ]
+ ]
+ ],
+ className = [if isActive then "bg-info text-info-content"]
+ )
[]
- static member private TableImport(index: int, table: ArcTable, state: SelectiveImportModalState, addTableImport: int -> bool -> unit, rmvTableImport: int -> unit) =
+ static member private TableImport(index: int, table0: ArcTable, state: SelectiveImportModalState, addTableImport: int -> bool -> unit, rmvTableImport: int -> unit) =
let showData, setShowData = React.useState(false)
- let name = table.Name
+ let name = table0.Name
let radioGroup = "radioGroup_" + name
let import = state.ImportTables |> List.tryFind (fun it -> it.Index = index)
let isActive = import.IsSome
- let disableAppend = state.ImportMetadata
- Daisy.card [
- if isActive then prop.className "bg-success"
- prop.children [
- Html.div [
- Daisy.label [
- Daisy.labelText [
- Html.i [prop.className "fa-solid fa-table"]
- Html.span (" " + name)
- Daisy.button.label [
- if showData then button.active
- button.sm
- prop.onClick (fun _ -> setShowData (not showData))
- prop.style [style.float'.right; style.cursor.pointer]
- prop.children [
- Html.i [
- prop.style [style.transitionProperty "transform"; style.transitionDuration (System.TimeSpan.FromSeconds 0.35)]
- prop.className ["fa-solid"; "fa-angle-down"; if showData then "fa-rotate-180"]
+ let isDisabled = state.ImportMetadata
+ SelectiveImportModal.Box (name, "fa-solid fa-table", React.fragment [
+ Html.div [
+ SelectiveImportModal.Radio (radioGroup, "Import",
+ isActive && import.Value.FullImport,
+ (fun (b:bool) -> addTableImport index true),
+ isDisabled
+ )
+ SelectiveImportModal.Radio (radioGroup, "Append to active table",
+ isActive && not import.Value.FullImport,
+ (fun (b:bool) -> addTableImport index false),
+ isDisabled
+ )
+ SelectiveImportModal.Radio (radioGroup, "No Import",
+ not isActive,
+ (fun (b:bool) -> rmvTableImport index),
+ isDisabled
+ )
+ ]
+ Daisy.collapse [
+ Html.input [prop.type'.checkbox]
+ Daisy.collapseTitle [
+ prop.className "p-1 min-h-0"
+ prop.text "Preview Table"
+ ]
+ Daisy.collapseContent [
+ prop.className "overflow-x-auto"
+ prop.children [
+ Daisy.table [
+ table.xs
+ prop.children [
+ Html.thead [
+ Html.tr [
+ for c in table0.Headers do
+ Html.th (c.ToString())
]
]
- ]
- ]
- ]
- Html.div [
- Daisy.formControl [
- let isInnerActive = isActive && import.Value.FullImport
- Daisy.label [
- Daisy.radio [
- prop.type'.radio
- prop.name radioGroup
- prop.isChecked isInnerActive
- prop.onChange (fun (b:bool) -> addTableImport index true)
- ]
- Daisy.labelText " Import"
- ]
- ]
- Daisy.formControl [
- let isInnerActive = isActive && not import.Value.FullImport
- Daisy.label [
- Daisy.radio [
- prop.type'.radio
- prop.name radioGroup
- if disableAppend then prop.disabled true
- prop.isChecked isInnerActive
- prop.onChange (fun (b:bool) -> addTableImport index true)
- ]
- Daisy.labelText " Append to active table"
- ]
- ]
- Daisy.formControl [
- let isInnerActive = not isActive
- Daisy.label [
- Daisy.radio [
- prop.type'.radio
- prop.name radioGroup
- if disableAppend then prop.disabled true
- prop.isChecked isInnerActive
- prop.onChange (fun (b:bool) -> addTableImport index true)
- ]
- Daisy.labelText " No Import"
- ]
- ]
- ]
- ]
- if showData then
- Html.div [
- prop.className "overflow-x-auto"
- prop.children [
- Daisy.table [
- prop.children [
- Html.thead [
+ Html.tbody [
+ for ri in 0 .. (table0.RowCount-1) do
+ let row = table0.GetRow(ri, true)
Html.tr [
- for c in table.Headers do
- Html.th (c.ToString())
+ for c in row do
+ Html.td (c.ToString())
]
- ]
- Html.tbody [
- for ri in 0 .. (table.RowCount-1) do
- let row = table.GetRow(ri, true)
- Html.tr [
- for c in row do
- Html.td (c.ToString())
- ]
- ]
]
]
]
]
- ]
- ]
+ ]
+ ]],
+ className = [if isActive then "bg-primary text-primary-content"]
+ )
[]
static member Main (import: ArcFiles) (model: Spreadsheet.Model) dispatch (rmv: _ -> unit) =
@@ -194,32 +167,30 @@ type SelectiveImportModal =
modal.active
prop.children [
Daisy.modalBackdrop [ prop.onClick rmv ]
- Daisy.card [
- prop.style [style.maxHeight(length.percent 70); style.overflowY.hidden]
+ Daisy.modalBox.div [
+ prop.className "w-4/5 overflow-y-auto flex flex-col @container/importModal gap-2"
prop.children [
- Daisy.cardBody [
- Daisy.cardActions [
- prop.className "justify-end"
- prop.children [
- Components.DeleteButton(props=[prop.onClick rmv])
- ]
+ Daisy.cardTitle [
+ prop.className "justify-between"
+ prop.children [
+ Html.p "Import"
+ Components.DeleteButton(props=[prop.onClick rmv])
]
- Daisy.cardTitle "Import"
- SelectiveImportModal.ImportTypeRadio(state.ImportType, fun it -> {state with ImportType = it} |> setState)
- SelectiveImportModal.MetadataImport(state.ImportMetadata, setMetadataImport, disArcfile)
- for ti in 0 .. (tables.Count-1) do
- let t = tables.[ti]
- SelectiveImportModal.TableImport(ti, t, state, addTableImport, rmvTableImport)
- Daisy.cardActions [
- Daisy.button.button [
- button.info
- prop.style [style.marginLeft length.auto]
- prop.text "Submit"
- prop.onClick(fun e ->
- {| importState = state; importedFile = import|} |> SpreadsheetInterface.ImportJson |> InterfaceMsg |> dispatch
- rmv e
- )
- ]
+ ]
+ SelectiveImportModal.ImportTypeRadio(state.ImportType, fun it -> {state with ImportType = it} |> setState)
+ SelectiveImportModal.MetadataImport(state.ImportMetadata, setMetadataImport, disArcfile)
+ for ti in 0 .. (tables.Count-1) do
+ let t = tables.[ti]
+ SelectiveImportModal.TableImport(ti, t, state, addTableImport, rmvTableImport)
+ Daisy.cardActions [
+ Daisy.button.button [
+ button.info
+ prop.style [style.marginLeft length.auto]
+ prop.text "Submit"
+ prop.onClick(fun e ->
+ {| importState = state; importedFile = import|} |> SpreadsheetInterface.ImportJson |> InterfaceMsg |> dispatch
+ rmv e
+ )
]
]
]
diff --git a/src/Client/Modals/UpdateColumn.fs b/src/Client/Modals/UpdateColumn.fs
index 427530d9..890a24d0 100644
--- a/src/Client/Modals/UpdateColumn.fs
+++ b/src/Client/Modals/UpdateColumn.fs
@@ -54,10 +54,8 @@ module private Components =
prop.className "grow"
tabs.bordered
prop.children [
- Html.ul [
- Tab(FunctionPage.Create, currentPage, setPage)
- Tab(FunctionPage.Update, currentPage, setPage)
- ]
+ Tab(FunctionPage.Create, currentPage, setPage)
+ Tab(FunctionPage.Update, currentPage, setPage)
]
]
@@ -67,8 +65,8 @@ module private Components =
Html.td [
let s0,marked,s2 = split (fst markedIndices) (snd markedIndices) cell0
Html.span s0
- Html.span [
- prop.className "has-background-info"
+ Html.mark [
+ prop.className "bg-info text-info-content"
prop.text marked
]
Html.span s2
@@ -117,30 +115,33 @@ type UpdateColumn =
)
|> setPreview
React.fragment [
- Daisy.label [
- Daisy.labelText "BAse"
- ]
- Daisy.input [
- prop.autoFocus true
- prop.valueOrDefault baseStr
- prop.onChange(fun s ->
- setBaseStr s
- updateCells s suffix
- )
+ Daisy.formControl [
+ Daisy.label [
+ Daisy.labelText "Base"
+ ]
+ Daisy.input [
+ input.bordered
+ prop.autoFocus true
+ prop.valueOrDefault baseStr
+ prop.onChange(fun s ->
+ setBaseStr s
+ updateCells s suffix
+ )
+ ]
]
- Html.label [
- prop.className "is-flex is-align-items-center checkbox"
- prop.style [style.gap (length.rem 0.5)]
- prop.children [
- Html.input [
- prop.type' "checkbox"
- prop.isChecked suffix
- prop.onChange(fun e ->
- setSuffix e
- updateCells baseStr e
- )
+ Daisy.formControl [
+ Daisy.label [
+ prop.className "cursor-pointer"
+ prop.children [
+ Daisy.labelText "Add number suffix"
+ Daisy.checkbox [
+ prop.isChecked suffix
+ prop.onChange(fun e ->
+ setSuffix e
+ updateCells baseStr e
+ )
+ ]
]
- Html.p [prop.text "Add number suffix"; prop.className "text-sm"]
]
]
]
@@ -168,29 +169,34 @@ type UpdateColumn =
else
()
Html.div [
- prop.className "is-flex is-flex-direction-row"
- prop.style [style.gap (length.rem 1)]
+ prop.className "flex gap-2"
prop.children [
- Daisy.label [
- Daisy.labelText "Regex"
- ]
- Daisy.input [
- prop.autoFocus true
- prop.valueOrDefault regex
- prop.onChange (fun s ->
- setRegex s;
- updateCells replacement s
- )
- ]
- Daisy.label [
- Daisy.labelText "Replacement"
+ Daisy.formControl [
+ Daisy.label [
+ Daisy.labelText "Regex"
+ ]
+ Daisy.input [
+ prop.autoFocus true
+ input.bordered
+ prop.valueOrDefault regex
+ prop.onChange (fun s ->
+ setRegex s;
+ updateCells replacement s
+ )
+ ]
]
- Daisy.input [
- prop.valueOrDefault replacement
- prop.onChange (fun s ->
- setReplacement s;
- updateCells s regex
- )
+ Daisy.formControl [
+ Daisy.label [
+ Daisy.labelText "Replacement"
+ ]
+ Daisy.input [
+ input.bordered
+ prop.valueOrDefault replacement
+ prop.onChange (fun s ->
+ setReplacement s;
+ updateCells s regex
+ )
+ ]
]
]
]
@@ -218,31 +224,35 @@ type UpdateColumn =
modal.active
prop.children [
Daisy.modalBackdrop [ prop.onClick rmv ]
- Daisy.card [
- prop.style [style.maxHeight(length.percent 70); style.overflowY.hidden]
+ Daisy.modalBox.div [
+ prop.style [style.maxHeight(length.percent 70); style.maxWidth(length.px 900); style.overflowY.hidden]
prop.children [
- Daisy.cardBody [
- Daisy.cardActions [
- prop.className "justify-end"
- prop.children [
- Components.DeleteButton(props=[prop.onClick rmv])
- ]
- ]
- Daisy.cardTitle "Update Column"
- Components.TabNavigation(currentPage, setPage)
- match currentPage with
- | FunctionPage.Create -> UpdateColumn.CreateForm(getCellStrings(), setPreview)
- | FunctionPage.Update -> UpdateColumn.UpdateForm(getCellStrings(), setPreview, regex, setRegex)
- Components.PreviewTable(column, preview, regex)
- Daisy.cardActions [
- Daisy.button.button [
- button.info
- prop.style [style.marginLeft length.auto]
- prop.text "Submit"
- prop.onClick(fun e ->
- submit()
- rmv e
- )
+ Daisy.card [
+ prop.children [
+ Daisy.cardBody [
+ Daisy.cardTitle [
+ prop.className "flex flex-row justify-between"
+ prop.children [
+ Html.p "Update Column"
+ Components.DeleteButton(props=[prop.onClick rmv])
+ ]
+ ]
+ Components.TabNavigation(currentPage, setPage)
+ match currentPage with
+ | FunctionPage.Create -> UpdateColumn.CreateForm(getCellStrings(), setPreview)
+ | FunctionPage.Update -> UpdateColumn.UpdateForm(getCellStrings(), setPreview, regex, setRegex)
+ Components.PreviewTable(column, preview, regex)
+ Daisy.cardActions [
+ Daisy.button.button [
+ button.info
+ prop.style [style.marginLeft length.auto]
+ prop.text "Submit"
+ prop.onClick(fun e ->
+ submit()
+ rmv e
+ )
+ ]
+ ]
]
]
]
diff --git a/src/Client/Model.fs b/src/Client/Model.fs
index 4636e1d4..3d8f9066 100644
--- a/src/Client/Model.fs
+++ b/src/Client/Model.fs
@@ -121,7 +121,7 @@ type PersistentStorageState = {
} with
static member init () = {
SearchableOntologies = [||]
- Host = None
+ Host = Some Swatehost.Browser
AppVersion = ""
ShowSideBar = false
HasOntologiesLoaded = false
diff --git a/src/Client/Pages/FilePicker/FilePickerView.fs b/src/Client/Pages/FilePicker/FilePickerView.fs
index 3ba15e7e..4dbf8fe7 100644
--- a/src/Client/Pages/FilePicker/FilePickerView.fs
+++ b/src/Client/Pages/FilePicker/FilePickerView.fs
@@ -8,63 +8,66 @@ open Messages
open Feliz
open Feliz.DaisyUI
-let update (filePickerMsg:FilePicker.Msg) (currentState: FilePicker.Model) (model: Model.Model) : FilePicker.Model * Cmd =
+let update (filePickerMsg:FilePicker.Msg) (state: FilePicker.Model) (model: Model.Model) : FilePicker.Model * Cmd =
match filePickerMsg with
| LoadNewFiles fileNames ->
- let nextState : FilePicker.Model = {
- FileNames = fileNames |> List.mapi (fun i x -> i + 1, x)
+ let nextModel = {
+ model with
+ Model.FilePickerState.FileNames = fileNames |> List.mapi (fun i x -> i + 1, x)
+ Model.PageState.SidebarPage = Routing.SidebarPage.FilePicker
}
- let nextCmd = UpdateModel {model with Model.PageState.SidebarPage = Routing.SidebarPage.FilePicker} |> Cmd.ofMsg
- nextState, nextCmd
+ let nextCmd = UpdateModel nextModel|> Cmd.ofMsg
+ state, nextCmd
| UpdateFileNames newFileNames ->
let nextState : FilePicker.Model = {
FileNames = newFileNames
}
nextState, Cmd.none
-let uploadButton (model:Model) dispatch =
+/// "parentContainerResizeClass": uses tailwind container queries. Expects a string like "@md/parentId:flex-row"
+let uploadButton (model:Model) dispatch (parentContainerResizeClass: string) =
let inputId = "filePicker_OnFilePickerMainFunc"
Html.div [
- Html.input [
- prop.style [style.display.none]
- prop.id inputId
- prop.multiple true
- prop.type'.file
- prop.onChange (fun (ev: File list) ->
- let files = ev //ev.target?files
-
- let fileNames =
- files |> List.map (fun f -> f.name)
-
- fileNames |> LoadNewFiles |> FilePickerMsg |> dispatch
-
- //let picker = Browser.Dom.document.getElementById(inputId)
- //// https://stackoverflow.com/questions/3528359/html-input-type-file-file-selection-event/3528376
- //picker?value <- null
- )
+ prop.className [
+ "flex flex-col gap-2"
+ parentContainerResizeClass
]
- match model.PersistentStorageState.Host with
+ prop.children [
+ Html.input [
+ prop.style [style.display.none]
+ prop.id inputId
+ prop.multiple true
+ prop.type'.file
+ prop.onChange (fun (ev: File list) ->
+ let files = ev //ev.target?files
+
+ let fileNames =
+ files |> List.map (fun f -> f.name)
+
+ fileNames |> LoadNewFiles |> FilePickerMsg |> dispatch
+
+ //let picker = Browser.Dom.document.getElementById(inputId)
+ //// https://stackoverflow.com/questions/3528359/html-input-type-file-file-selection-event/3528376
+ //picker?value <- null
+ )
+ ]
+ match model.PersistentStorageState.Host with
| Some (Swatehost.ARCitect) ->
- Html.div [
- prop.className "flex flex-row gap-2"
- prop.children [
- Daisy.button.button [
- button.primary
- button.block
- prop.onClick(fun _ ->
- ARCitect.RequestPaths false |> ARCitect.ARCitect.send
- )
- prop.text "Pick Files"
- ]
- Daisy.button.button [
- button.primary
- button.block
- prop.onClick(fun _ ->
- ARCitect.RequestPaths true |> ARCitect.ARCitect.send
- )
- prop.text "Pick Directories"
- ]
- ]
+ Daisy.button.button [
+ button.primary
+ button.block
+ prop.onClick(fun _ ->
+ ARCitect.RequestPaths false |> ARCitect.ARCitect.send
+ )
+ prop.text "Pick Files"
+ ]
+ Daisy.button.button [
+ button.primary
+ button.block
+ prop.onClick(fun _ ->
+ ARCitect.RequestPaths true |> ARCitect.ARCitect.send
+ )
+ prop.text "Pick Directories"
]
| _ ->
Daisy.button.button [
@@ -76,6 +79,7 @@ let uploadButton (model:Model) dispatch =
)
prop.text "Pick file names"
]
+ ]
]
let insertButton (model:Model) dispatch =
@@ -214,7 +218,7 @@ module FileNameTable =
let fileContainer (model:Model) dispatch =
SidebarComponents.SidebarLayout.LogicContainer [
- uploadButton model dispatch
+ uploadButton model dispatch "@md/sidebar:flex-row"
if model.FilePickerState.FileNames <> [] then
fileSortElements model dispatch
diff --git a/src/Client/Pages/JsonExporter/JsonExporter.fs b/src/Client/Pages/JsonExporter/JsonExporter.fs
index 665ef029..f14cffe0 100644
--- a/src/Client/Pages/JsonExporter/JsonExporter.fs
+++ b/src/Client/Pages/JsonExporter/JsonExporter.fs
@@ -34,254 +34,6 @@ let download(filename, text) =
document.body.removeChild(element) |> ignore
()
-//open Messages
-//open Feliz
-//open Feliz.DaisyUI
-
-//let dropdownItem (exportType:JsonExportType) (model:Model) msg (isActive:bool) =
-// Bulma.dropdownItem.a [
-// prop.tabIndex 0
-// prop.onClick (fun e ->
-// e.stopPropagation()
-// exportType |> msg
-// )
-// prop.onKeyDown (fun k -> if (int k.which) = 13 then exportType |> msg)
-// prop.children [
-// Html.span [
-// prop.className "has-tooltip-right has-tooltip-multiline"
-// prop.custom ("data-tooltip", exportType.toExplanation)
-// prop.style [style.fontSize(length.rem 1.1); style.paddingRight 10; style.textAlign.center; style.color NFDIColors.Yellow.Darker20]
-// Html.i [prop.className "fa-solid fa-circle-info"] |> prop.children
-// ]
-
-// Html.span (exportType.ToString())
-// ]
-// ]
-
-//let parseTableToISAJsonEle (model:Model) (dispatch:Messages.Msg -> unit) =
-// mainFunctionContainer [
-// Bulma.field.div [
-// Bulma.field.hasAddons
-// prop.children [
-// Bulma.control.div [
-// Bulma.dropdown [
-// if model.JsonExporterModel.ShowTableExportTypeDropdown then Bulma.dropdown.isActive
-// prop.children [
-// Bulma.dropdownTrigger [
-// Daisy.button.a [
-// prop.onClick(fun e -> e.stopPropagation(); UpdateShowTableExportTypeDropdown (not model.JsonExporterModel.ShowTableExportTypeDropdown) |> JsonExporterMsg |> dispatch )
-// prop.children [
-// span [Style [MarginRight "5px"]] [str (model.JsonExporterModel.TableJsonExportType.ToString())]
-// Html.i [prop.className "fa-solid fa-angle-down"]
-// ]
-// ]
-// ]
-// Bulma.dropdownMenu [
-// Bulma.dropdownContent [
-// let msg = (UpdateTableJsonExportType >> JsonExporterMsg >> dispatch)
-// dropdownItem JsonExportType.Assay model msg (model.JsonExporterModel.TableJsonExportType = JsonExportType.Assay)
-// dropdownItem JsonExportType.ProcessSeq model msg (model.JsonExporterModel.TableJsonExportType = JsonExportType.ProcessSeq)
-// ]
-// ]
-// ]
-// ]
-// ]
-// Bulma.control.div [
-// Bulma.control.isExpanded
-// Daisy.button.a [
-// button.info
-// button.block
-// prop.onClick(fun _ ->
-// InterfaceMsg SpreadsheetInterface.ExportJsonTable |> dispatch
-// )
-// prop.text "Download as isa json"
-// ] |> prop.children
-// ]
-// ]
-// ]
-// ]
-
-//let parseTablesToISAJsonEle (model:Model) (dispatch:Messages.Msg -> unit) =
-// mainFunctionContainer [
-// Bulma.field.div [
-// Bulma.field.hasAddons
-// prop.children [
-// Bulma.control.div [
-// Bulma.dropdown [
-// if model.JsonExporterModel.ShowWorkbookExportTypeDropdown then Bulma.dropdown.isActive
-// prop.children [
-// Bulma.dropdownTrigger [
-// Daisy.button.a [
-// prop.onClick (fun e -> e.stopPropagation(); UpdateShowWorkbookExportTypeDropdown (not model.JsonExporterModel.ShowWorkbookExportTypeDropdown) |> JsonExporterMsg |> dispatch )
-// prop.children [
-// span [Style [MarginRight "5px"]] [str (model.JsonExporterModel.WorkbookJsonExportType.ToString())]
-// Html.i [prop.className "fa-solid fa-angle-down"]
-// ]
-// ]
-// ]
-// Bulma.dropdownMenu [
-// Bulma.dropdownContent [
-// let msg = (UpdateWorkbookJsonExportType >> JsonExporterMsg >> dispatch)
-// dropdownItem JsonExportType.Assay model msg (model.JsonExporterModel.WorkbookJsonExportType = JsonExportType.Assay)
-// dropdownItem JsonExportType.ProcessSeq model msg (model.JsonExporterModel.WorkbookJsonExportType = JsonExportType.ProcessSeq)
-// ]
-// ]
-// ]
-// ]
-// ]
-// Bulma.control.div [
-// Bulma.control.isExpanded
-// Daisy.button.a [
-// button.info
-// button.block
-// prop.onClick(fun _ ->
-// InterfaceMsg SpreadsheetInterface.ExportJsonTables |> dispatch
-// )
-// prop.text "Download as isa json"
-// ]
-// |> prop.children
-// ]
-// ]
-// ]
-// ]
-
-//// SND ELEMENT
-//open Browser.Types
-
-//let fileUploadButton (model:Model) dispatch (id: string) =
-// Bulma.label [
-// prop.className "mb-2 has-text-weight-normal"
-// prop.children [
-// Bulma.fileInput [
-// prop.id id
-// prop.type' "file";
-// prop.style [style.display.none]
-// prop.onChange (fun (ev: File list) ->
-// let files = ev//: Browser.Types.FileList = ev.target?files
-
-// let blobs =
-// files
-// |> List.map (fun f -> f.slice() )
-
-// let reader = Browser.Dom.FileReader.Create()
-
-// reader.onload <- fun evt ->
-// let byteArr =
-// let arraybuffer : Fable.Core.JS.ArrayBuffer = evt.target?result
-// let uintArr = Fable.Core.JS.Constructors.Uint8Array.Create arraybuffer
-// uintArr.ToString().Split([|","|], System.StringSplitOptions.RemoveEmptyEntries)
-// |> Array.map (fun byteStr -> byte byteStr)
-
-// StoreXLSXByteArray byteArr |> JsonExporterMsg |> dispatch
-
-// reader.onerror <- fun evt ->
-// curry GenericLog Cmd.none ("Error", evt.Value) |> DevMsg |> dispatch
-
-// reader.readAsArrayBuffer(blobs |> List.head)
-
-// let picker = Browser.Dom.document.getElementById(id)
-// // https://stackoverflow.com/questions/3528359/html-input-type-file-file-selection-event/3528376
-// picker?value <- null
-// )
-// ]
-// Daisy.button.a [
-// button.info;
-// button.block
-// prop.text "Upload Excel file"
-// ]
-// ]
-// ]
-
-
-//let xlsxUploadAndParsingMainElement (model:Model) (dispatch: Msg -> unit) =
-// let inputId = "xlsxConverter_uploadButton"
-// mainFunctionContainer [
-// // Upload xlsx file to byte []
-// fileUploadButton model dispatch inputId
-// // Request parsing
-// Bulma.field.div [
-// Bulma.field.hasAddons
-// prop.children [
-// Bulma.control.div [
-// Bulma.dropdown [
-// if model.JsonExporterModel.ShowXLSXExportTypeDropdown then Bulma.dropdown.isActive
-// prop.children [
-// Bulma.dropdownTrigger [
-// Daisy.button.a [
-// prop.onClick (fun e -> e.stopPropagation(); UpdateShowXLSXExportTypeDropdown (not model.JsonExporterModel.ShowXLSXExportTypeDropdown) |> JsonExporterMsg |> dispatch )
-// prop.children [
-// span [Style [MarginRight "5px"]] [str (model.JsonExporterModel.XLSXParsingExportType.ToString())]
-// Html.i [prop.className "fa-solid fa-angle-down"]
-// ]
-// ]
-// ]
-// Bulma.dropdownMenu [
-// Bulma.dropdownContent [
-// let msg = (UpdateXLSXParsingExportType >> JsonExporterMsg >> dispatch)
-// dropdownItem JsonExportType.Assay model msg (model.JsonExporterModel.XLSXParsingExportType = JsonExportType.Assay)
-// dropdownItem JsonExportType.ProcessSeq model msg (model.JsonExporterModel.XLSXParsingExportType = JsonExportType.ProcessSeq)
-// dropdownItem JsonExportType.ProtocolTemplate model msg (model.JsonExporterModel.XLSXParsingExportType = JsonExportType.ProtocolTemplate)
-// ]
-// ]
-// ]
-// ]
-// ]
-// Bulma.control.div [
-// Bulma.control.isExpanded
-// Daisy.button.a [
-// let hasContent = model.JsonExporterModel.XLSXByteArray <> Array.empty
-// button.info
-// if hasContent then
-// Daisy.button.isActive
-// else
-// button.error
-// prop.disabled true
-// button.block
-// prop.onClick(fun _ ->
-// if hasContent then
-// ParseXLSXToJsonRequest model.JsonExporterModel.XLSXByteArray |> JsonExporterMsg |> dispatch
-// )
-// prop.text "Download as isa json"
-// ]
-// |> prop.children
-// ]
-// ]
-// ]
-// ]
-
-//let jsonExporterMainElement (model:Model) (dispatch: Messages.Msg -> unit) =
-
- //Bulma.content [
-
- // prop.onSubmit (fun e -> e.preventDefault())
- // prop.onKeyDown (fun k -> if (int k.which) = 13 then k.preventDefault())
- // prop.onClick (fun e -> CloseAllDropdowns |> JsonExporterMsg |> dispatch)
- // prop.style [style.minHeight(length.vh 100)]
- // prop.children [
- // Bulma.label "Json Exporter"
-
- // Bulma.help [
- // str "Export swate annotation tables to "
- // a [Href @"https://en.wikipedia.org/wiki/JSON"] [str "JSON"]
- // str " format. Official ISA-JSON types can be found "
- // a [Href @"https://isa-specs.readthedocs.io/en/latest/isajson.html#"] [str "here"]
- // str "."
- // ]
-
- // Bulma.label "Export active table"
-
- // parseTableToISAJsonEle model dispatch
-
- // Bulma.label "Export workbook"
-
- // parseTablesToISAJsonEle model dispatch
-
- // Bulma.label "Export Swate conform xlsx file."
-
- // xlsxUploadAndParsingMainElement model dispatch
- // ]
- //]
-
type private JsonExportState = {
ExportFormat: JsonExportFormat
} with
@@ -293,7 +45,7 @@ type FileExporter =
static member private FileFormat(efm: JsonExportFormat, state: JsonExportState, setState) =
Html.option [
- prop.text (string efm)
+ prop.text (efm.AsStringRdbl)
]
[]
@@ -356,7 +108,7 @@ type FileExporter =
Html.text ": A simple ARCtrl specific format."
]
Html.li [
- Html.b "ARCtrlCompressed"
+ Html.b "ARCtrl Compressed"
Html.text ": A compressed ARCtrl specific format."
]
Html.li [
@@ -370,12 +122,12 @@ type FileExporter =
Html.text ")."
]
Html.li [
- Html.b "ROCrate"
- Html.text ": ROCrate format ("
+ Html.b "RO-Crate Metadata"
+ Html.text ": RO-Crate format ("
Html.a [
prop.target.blank
prop.href "https://www.researchobject.org/ro-crate/"
- prop.text "ROCrate"
+ prop.text "RO-Crate"
]
Html.text ", "
Html.a [
diff --git a/src/Client/SharedComponents/Metadata/Assay.fs b/src/Client/SharedComponents/Metadata/Assay.fs
index eca5b57c..ebee9927 100644
--- a/src/Client/SharedComponents/Metadata/Assay.fs
+++ b/src/Client/SharedComponents/Metadata/Assay.fs
@@ -8,7 +8,7 @@ open Components
open Components.Forms
[]
-let Main(assay: ArcAssay, setArcAssay: ArcAssay -> unit, setDatamap: ArcAssay -> DataMap option -> unit) =
+let Main(assay: ArcAssay, setArcAssay: ArcAssay -> unit, setDatamap: ArcAssay -> DataMap option -> unit, model: Model.Model) =
Generic.Section [
Generic.BoxedField(
"Assay Metadata",
@@ -20,9 +20,9 @@ let Main(assay: ArcAssay, setArcAssay: ArcAssay -> unit, setDatamap: ArcAssay ->
setArcAssay nextAssay
),
"Identifier",
- validator = {| fn = (fun s -> ARCtrl.Helper.Identifier.tryCheckValidCharacters s); msg = "Invalid Identifier" |}
+ validator = {| fn = (fun s -> ARCtrl.Helper.Identifier.tryCheckValidCharacters s); msg = "Invalid Identifier" |},
+ disabled = Generic.isDisabledInARCitect model.PersistentStorageState.Host
)
-
FormComponents.OntologyAnnotationInput(
assay.MeasurementType |> Option.defaultValue (OntologyAnnotation()),
(fun oa ->
diff --git a/src/Client/SharedComponents/Metadata/Forms.fs b/src/Client/SharedComponents/Metadata/Forms.fs
index 9c9c8310..6e29152e 100644
--- a/src/Client/SharedComponents/Metadata/Forms.fs
+++ b/src/Client/SharedComponents/Metadata/Forms.fs
@@ -404,7 +404,8 @@ type FormComponents =
]
[]
- static member TextInput(value: string, setValue: string -> unit, ?label: string, ?validator: {| fn: string -> bool; msg: string |}, ?placeholder: string, ?isarea: bool, ?isJoin) =
+ static member TextInput(value: string, setValue: string -> unit, ?label: string, ?validator: {| fn: string -> bool; msg: string |}, ?placeholder: string, ?isarea: bool, ?isJoin, ?disabled) =
+ let disabled = defaultArg disabled false
let isJoin = defaultArg isJoin false
let loading, setLoading = React.useState(false)
let isValid, setIsValid = React.useState(true)
@@ -452,6 +453,8 @@ type FormComponents =
match isarea with
| Some true ->
Daisy.textarea [
+ prop.disabled disabled
+ prop.readOnly disabled
prop.className "grow ghost"
if placeholder.IsSome then prop.placeholder placeholder.Value
prop.ref ref
@@ -459,6 +462,8 @@ type FormComponents =
]
| _ ->
Html.input [
+ prop.disabled disabled
+ prop.readOnly disabled
prop.className "trunacte w-full"
if placeholder.IsSome then prop.placeholder placeholder.Value
prop.ref ref
diff --git a/src/Client/SharedComponents/Metadata/Generic.fs b/src/Client/SharedComponents/Metadata/Generic.fs
index 81f559b7..5aeffef6 100644
--- a/src/Client/SharedComponents/Metadata/Generic.fs
+++ b/src/Client/SharedComponents/Metadata/Generic.fs
@@ -4,6 +4,10 @@ open Feliz.DaisyUI
open Feliz
type Generic =
+
+ static member isDisabledInARCitect (host: Swatehost option) =
+
+ host.IsSome && host.Value = Swatehost.ARCitect
static member FieldTitle (title:string) =
Html.h5 [
prop.className "text-primary font-semibold mt-6 mb-2"
diff --git a/src/Client/SharedComponents/Metadata/Investigation.fs b/src/Client/SharedComponents/Metadata/Investigation.fs
index 4e302ccd..d5a8cadd 100644
--- a/src/Client/SharedComponents/Metadata/Investigation.fs
+++ b/src/Client/SharedComponents/Metadata/Investigation.fs
@@ -7,7 +7,7 @@ open ARCtrl
open Components
open Components.Forms
-let Main(investigation: ArcInvestigation, setInvestigation: ArcInvestigation -> unit) =
+let Main(investigation: ArcInvestigation, setInvestigation: ArcInvestigation -> unit, model: Model.Model) =
Generic.Section [
Generic.BoxedField(
"Investigation Metadata",
@@ -17,7 +17,8 @@ let Main(investigation: ArcInvestigation, setInvestigation: ArcInvestigation ->
(fun s ->
let nextInvestigation = IdentifierSetters.setInvestigationIdentifier s investigation
setInvestigation nextInvestigation),
- "Identifier"
+ "Identifier",
+ disabled = Generic.isDisabledInARCitect model.PersistentStorageState.Host
)
FormComponents.TextInput (
Option.defaultValue "" investigation.Title,
diff --git a/src/Client/SharedComponents/Metadata/Study.fs b/src/Client/SharedComponents/Metadata/Study.fs
index eed69075..619ea3ff 100644
--- a/src/Client/SharedComponents/Metadata/Study.fs
+++ b/src/Client/SharedComponents/Metadata/Study.fs
@@ -6,7 +6,7 @@ open Components
open Components.Forms
open System
-let Main(study: ArcStudy, assignedAssays: ArcAssay list, setArcStudy: (ArcStudy * ArcAssay list) -> unit, setDatamap: ArcStudy -> DataMap option -> unit) =
+let Main(study: ArcStudy, assignedAssays: ArcAssay list, setArcStudy: (ArcStudy * ArcAssay list) -> unit, setDatamap: ArcStudy -> DataMap option -> unit, model: Model.Model) =
Generic.Section [
Generic.BoxedField(
"Study Metadata",
@@ -16,7 +16,16 @@ let Main(study: ArcStudy, assignedAssays: ArcAssay list, setArcStudy: (ArcStudy
(fun s ->
let nextStudy = IdentifierSetters.setStudyIdentifier s study
setArcStudy (nextStudy , assignedAssays)),
- "Identifier"
+ "Identifier",
+ validator = {| fn = (fun s -> ARCtrl.Helper.Identifier.tryCheckValidCharacters s); msg = "Invalid Identifier" |},
+ disabled = Generic.isDisabledInARCitect model.PersistentStorageState.Host
+ )
+ FormComponents.TextInput (
+ Option.defaultValue "" study.Title,
+ (fun s ->
+ study.Title <- s |> Option.whereNot String.IsNullOrWhiteSpace
+ setArcStudy (study , assignedAssays)),
+ "Title"
)
FormComponents.TextInput (
Option.defaultValue "" study.Description,
diff --git a/src/Client/SharedComponents/TermSearchInput.fs b/src/Client/SharedComponents/TermSearchInput.fs
index 27b4a8ce..0d573be8 100644
--- a/src/Client/SharedComponents/TermSearchInput.fs
+++ b/src/Client/SharedComponents/TermSearchInput.fs
@@ -242,6 +242,7 @@ type TermSearch =
Html.div [
prop.id id
prop.className [
+ "min-w-[400px]"
"grid grid-cols-[auto,1fr,1fr,auto] absolute left-0 z-50 w-full
bg-base-200 rounded shadow-md border-2 border-primary py-2 pl-4 max-h-[400px] overflow-y-auto w-full"
if not show then "hidden";
diff --git a/src/Client/SidebarComponents/Navbar.fs b/src/Client/SidebarComponents/Navbar.fs
index b7e8c8f7..876fab13 100644
--- a/src/Client/SidebarComponents/Navbar.fs
+++ b/src/Client/SidebarComponents/Navbar.fs
@@ -89,7 +89,7 @@ let NoMetadataModalContent refresh (dispatch: Messages.Msg -> unit) =
AddMetaDataButtons refresh dispatch
])
-let UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal (dispatch: Messages.Msg -> unit) =
+let UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal model (dispatch: Messages.Msg -> unit) =
React.fragment [
match excelMetadataType with
| { Metadata = Some (ArcFiles.Assay assay)} ->
@@ -100,7 +100,7 @@ let UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal
}
let setAssayDataMap (assay: ArcAssay) (dataMap: DataMap option) =
assay.DataMap <- dataMap
- Assay.Main(assay, setAssay, setAssayDataMap)
+ Assay.Main(assay, setAssay, setAssayDataMap, model)
| { Metadata = Some (ArcFiles.Study (study, assays))} ->
let setStudy (study: ArcStudy, assays: ArcAssay list) =
setExcelMetadataType {
@@ -109,14 +109,14 @@ let UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal
}
let setStudyDataMap (study: ArcStudy) (dataMap: DataMap option) =
study.DataMap <- dataMap
- Study.Main(study, assays, setStudy, setStudyDataMap)
+ Study.Main(study, assays, setStudy, setStudyDataMap, model)
| { Metadata = Some (ArcFiles.Investigation investigation)} ->
let setInvestigation (investigation: ArcInvestigation) =
setExcelMetadataType {
excelMetadataType with
Metadata = Some (ArcFiles.Investigation investigation)
}
- Investigation.Main(investigation, setInvestigation)
+ Investigation.Main(investigation, setInvestigation, model)
| { Metadata = Some (ArcFiles.Template template)} ->
let setTemplate (template: Template) =
setExcelMetadataType {
@@ -161,7 +161,7 @@ let UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal
// Define a modal dialog component
[]
-let SelectModalDialog (closeModal: unit -> unit) (dispatch: Messages.Msg -> unit) =
+let SelectModalDialog (closeModal: unit -> unit) model (dispatch: Messages.Msg -> unit) =
let (excelMetadataType, setExcelMetadataType) = React.useState(ExcelMetadataState.init)
let refreshMetadataState =
fun () ->
@@ -198,7 +198,7 @@ let SelectModalDialog (closeModal: unit -> unit) (dispatch: Messages.Msg -> unit
| { Metadata = None } ->
NoMetadataModalContent refreshMetadataState dispatch
| { Metadata = Some metadata } ->
- UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal dispatch
+ UpdateMetadataModalContent excelMetadataType setExcelMetadataType closeModal model dispatch
]
]
]
@@ -283,6 +283,7 @@ let NavbarComponent (model : Model) (dispatch : Messages.Msg -> unit) =
if state.ExcelMetadataModalActive then
SelectModalDialog
toggleMetdadataModal
+ model
dispatch
Html.div [
prop.ariaLabel "logo"
diff --git a/src/Client/Spreadsheet/IO.fs b/src/Client/Spreadsheet/IO.fs
index f9015d59..f3ce5a70 100644
--- a/src/Client/Spreadsheet/IO.fs
+++ b/src/Client/Spreadsheet/IO.fs
@@ -13,13 +13,13 @@ module Xlsx =
let ws = fswb.GetWorksheets()
let arcfile =
match ws with
- | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.ArcAssay.isMetadataSheetName ws.Name) ->
- ArcAssay.fromFsWorkbook fswb |> Assay
- | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.ArcStudy.isMetadataSheetName ws.Name) ->
+ | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.ArcAssay.isMetadataSheetName ws.Name) ->
+ ArcAssay.fromFsWorkbook fswb |> Assay
+ | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.ArcStudy.isMetadataSheetName ws.Name) ->
ArcStudy.fromFsWorkbook fswb |> Study
- | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.ArcInvestigation.isMetadataSheetName ws.Name) ->
+ | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.ArcInvestigation.isMetadataSheetName ws.Name) ->
ArcInvestigation.fromFsWorkbook fswb |> Investigation
- | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.Template.metaDataSheetName = ws.Name || ARCtrl.Spreadsheet.Template.obsoletemetaDataSheetName = ws.Name) ->
+ | _ when ws.Exists (fun ws -> ARCtrl.Spreadsheet.Template.metadataSheetName = ws.Name || ARCtrl.Spreadsheet.Template.obsoleteMetadataSheetName = ws.Name) ->
ARCtrl.Spreadsheet.Template.fromFsWorkbook fswb |> Template
| _ -> failwith "Unable to identify given file. Missing metadata sheet with correct name."
return arcfile
diff --git a/src/Client/Update.fs b/src/Client/Update.fs
index bf9ceef0..8f235c34 100644
--- a/src/Client/Update.fs
+++ b/src/Client/Update.fs
@@ -9,17 +9,16 @@ open Routing
open Messages
open Model
-let urlUpdate (route: Route option) (currentModel:Model) : Model * Cmd =
- match route with
- | Some (Route.Home queryIntegerOption) ->
- let swatehost = Swatehost.ofQueryParam queryIntegerOption
- let nextModel = {
- currentModel with
- Model.PersistentStorageState.Host = Some swatehost
- }
- nextModel,Cmd.none
- | None ->
- currentModel, Cmd.none
+let urlUpdate (route: Route option) (model:Model) : Model * Cmd =
+ log "hit urlUpdate"
+ let cmd (host: Swatehost) = SpreadsheetInterface.Initialize host |> InterfaceMsg |> Cmd.ofMsg
+ let host =
+ match route with
+ | Some (Routing.Route.Home queryIntegerOption) ->
+ Swatehost.ofQueryParam queryIntegerOption
+ | None ->
+ Swatehost.Browser
+ {model with Model.PersistentStorageState.Host = Some host}, cmd host
module AdvancedSearch =
diff --git a/src/Client/Update/InterfaceUpdate.fs b/src/Client/Update/InterfaceUpdate.fs
index 21de66ec..81e2b304 100644
--- a/src/Client/Update/InterfaceUpdate.fs
+++ b/src/Client/Update/InterfaceUpdate.fs
@@ -14,6 +14,26 @@ open Shared
open Fable.Core.JsInterop
open Shared.ARCtrlHelper
+module private ModelUtil =
+
+ open LocalHistory
+ open Model
+
+ type Model.Model with
+ member this.UpdateFromLocalStorage() =
+ match this.PersistentStorageState.Host with
+ | Some Swatehost.Browser ->
+ let dt = LocalStorage.Darkmode.DataTheme.GET()
+ LocalStorage.Darkmode.DataTheme.SET dt
+ { this with
+ Model.SpreadsheetModel = Spreadsheet.Model.fromLocalStorage()
+ Model.History = this.History.UpdateFromSessionStorage()
+ }
+ | _ ->
+ this
+
+open ModelUtil
+
/// This seems like such a hack :(
module private ExcelHelper =
@@ -62,7 +82,6 @@ module Interface =
let innerUpdate (model: Model) (msg: SpreadsheetInterface.Msg) =
match msg with
- // This is very bloated, might be good to reduce
| Initialize host ->
let cmd =
Cmd.batch [
@@ -79,7 +98,9 @@ module Interface =
ARCitect.ARCitect.send ARCitect.Init
)
]
- model, cmd
+ /// Updates from local storage if standalone in browser
+ let nextModel = model.UpdateFromLocalStorage()
+ nextModel, cmd
| CreateAnnotationTable usePrevOutput ->
match host with
| Some Swatehost.Excel ->
diff --git a/src/Client/Update/SpreadsheetUpdate.fs b/src/Client/Update/SpreadsheetUpdate.fs
index d99f6b4c..12fd7c91 100644
--- a/src/Client/Update/SpreadsheetUpdate.fs
+++ b/src/Client/Update/SpreadsheetUpdate.fs
@@ -23,11 +23,11 @@ module Spreadsheet =
///
let updateHistoryStorageMsg (msg: Spreadsheet.Msg) (state: Spreadsheet.Model, model: Model, cmd) =
match msg with
- | UpdateActiveView _ | UpdateHistoryPosition _ | Reset | UpdateSelectedCells _
- | UpdateActiveCell _ | CopySelectedCell | CopyCell _ | MoveSelectedCell _ | SetActiveCellFromSelected ->
+ | UpdateActiveView _ | UpdateHistoryPosition _ | Reset | UpdateSelectedCells _
+ | UpdateActiveCell _ | CopySelectedCell | CopyCell _ | MoveSelectedCell _ | SetActiveCellFromSelected ->
state.SaveToLocalStorage() // This will cache the most up to date table state to local storage.
state, model, cmd
- | _ ->
+ | _ ->
state.SaveToLocalStorage() // This will cache the most up to date table state to local storage.
let nextHistory = model.History.SaveSessionSnapshot state // this will cache the table state for certain operations in session storage.
if model.PersistentStorageState.Host = Some Swatehost.ARCitect then
@@ -54,7 +54,7 @@ module Spreadsheet =
// (Messages.curry Messages.GenericError Cmd.none >> Messages.DevMsg)
//let newHistoryController (state, model, cmd) =
- // updateSessionStorageMsg msg, model
+ // updateSessionStorageMsg msg, model
let innerUpdate (state: Spreadsheet.Model) (model: Model) (msg: Spreadsheet.Msg) =
match msg with
@@ -92,7 +92,7 @@ module Spreadsheet =
let msg = fun t -> JoinTable(t, index, options) |> SpreadsheetMsg
let cmd =
Table.selectiveTablePrepare state.ActiveTable table
- |> msg
+ |> msg
|> Cmd.ofMsg
state, model, cmd
| JoinTable (table, index, options) ->
@@ -103,8 +103,8 @@ module Spreadsheet =
let nextState =
if reset then
Spreadsheet.Model.init(arcFile)
- else
- { state with
+ else
+ { state with
ArcFile = Some arcFile
}
nextState, model, Cmd.none
@@ -125,18 +125,18 @@ module Spreadsheet =
nextState, model, Cmd.none
| UpdateCells arr ->
Controller.Generic.setCells arr state
- let nextState =
+ let nextState =
{state with ArcFile = state.ArcFile}
nextState, model, Cmd.none
| UpdateHeader (index, header) ->
- let nextState =
+ let nextState =
state.ActiveTable.UpdateHeader(index, header)
{state with ArcFile = state.ArcFile}
nextState, model, Cmd.none
| UpdateActiveView nextView ->
- let nextState = {
- state with
- ActiveView = nextView
+ let nextState = {
+ state with
+ ActiveView = nextView
SelectedCells = Set.empty
}
nextState, model, Cmd.none
@@ -156,7 +156,7 @@ module Spreadsheet =
state, model
| _ ->
/// Run this first so an error breaks the function before any mutables are changed
- let nextState =
+ let nextState =
Spreadsheet.Model.fromSessionStorage(newPosition)
Browser.WebStorage.sessionStorage.setItem(Keys.swate_session_history_position, string newPosition)
let nextModel = {model with History.HistoryCurrentPosition = newPosition}
@@ -203,7 +203,7 @@ module Spreadsheet =
let cmd =
match state.SelectedCells.IsEmpty with
| true -> Cmd.none
- | false ->
+ | false ->
let moveBy =
match keypressed with
| Key.Down -> (0,1)
@@ -224,7 +224,7 @@ module Spreadsheet =
UpdateSelectedCells s |> SpreadsheetMsg |> Cmd.ofMsg
state, model, cmd
| SetActiveCellFromSelected ->
- let cmd =
+ let cmd =
if state.SelectedCells.IsEmpty then
Cmd.none
else
@@ -236,30 +236,30 @@ module Spreadsheet =
let nextState = { state with ActiveCell = next }
nextState, model, Cmd.none
| CopyCell index ->
- let cmd =
- Cmd.OfPromise.attempt
- (Controller.Clipboard.copyCellByIndex index)
+ let cmd =
+ Cmd.OfPromise.attempt
+ (Controller.Clipboard.copyCellByIndex index)
state
(curry GenericError Cmd.none >> DevMsg)
state, model, cmd
| CopyCells indices ->
- let cmd =
- Cmd.OfPromise.attempt
- (Controller.Clipboard.copyCellsByIndex indices)
+ let cmd =
+ Cmd.OfPromise.attempt
+ (Controller.Clipboard.copyCellsByIndex indices)
state
(curry GenericError Cmd.none >> DevMsg)
state, model, cmd
| CopySelectedCell ->
- let cmd =
- Cmd.OfPromise.attempt
- (Controller.Clipboard.copySelectedCell)
+ let cmd =
+ Cmd.OfPromise.attempt
+ (Controller.Clipboard.copySelectedCell)
state
(curry GenericError Cmd.none >> DevMsg)
state, model, cmd
| CopySelectedCells ->
- let cmd =
- Cmd.OfPromise.attempt
- (Controller.Clipboard.copySelectedCells)
+ let cmd =
+ Cmd.OfPromise.attempt
+ (Controller.Clipboard.copySelectedCells)
state
(curry GenericError Cmd.none >> DevMsg)
state, model, cmd
@@ -319,7 +319,7 @@ module Spreadsheet =
let nextState = Controller.Table.fillColumnWithCell index state
nextState, model, Cmd.none
//| EditColumn (columnIndex, newCellType, b_type) ->
- // let cmd = createPromiseCmd <| fun _ -> Controller.editColumn (columnIndex, newCellType, b_type) state
+ // let cmd = createPromiseCmd <| fun _ -> Controller.editColumn (columnIndex, newCellType, b_type) state
// state, model, cmd
| ImportXlsx bytes ->
let cmd =
@@ -357,8 +357,8 @@ module Spreadsheet =
state, model, Cmd.none
try
innerUpdate state model msg
- |> Helper.updateHistoryStorageMsg msg
+ // |> Helper.updateHistoryStorageMsg msg
with
- | e ->
+ | e ->
let cmd = GenericError (Cmd.none, e) |> DevMsg |> Cmd.ofMsg
state, model, cmd
\ No newline at end of file
diff --git a/src/Client/Views/SpreadsheetView.fs b/src/Client/Views/SpreadsheetView.fs
index dc029a3c..c9deac7e 100644
--- a/src/Client/Views/SpreadsheetView.fs
+++ b/src/Client/Views/SpreadsheetView.fs
@@ -90,17 +90,17 @@ let Main (model: Model, dispatch) =
assay |> Assay |> Spreadsheet.UpdateArcFile |> SpreadsheetMsg |> dispatch
let setAssayDataMap assay dataMap =
dataMap |> SpreadsheetInterface.UpdateDatamap |> InterfaceMsg |> dispatch
- Components.Metadata.Assay.Main(assay, setAssay, setAssayDataMap)
+ Components.Metadata.Assay.Main(assay, setAssay, setAssayDataMap, model)
| Some (ArcFiles.Study (study, assays)) ->
let setStudy (study, assays) =
(study, assays) |> Study |> Spreadsheet.UpdateArcFile |> SpreadsheetMsg |> dispatch
let setStudyDataMap study dataMap =
dataMap |> SpreadsheetInterface.UpdateDatamap |> InterfaceMsg |> dispatch
- Components.Metadata.Study.Main(study, assays, setStudy, setStudyDataMap)
+ Components.Metadata.Study.Main(study, assays, setStudy, setStudyDataMap, model)
| Some (ArcFiles.Investigation investigation) ->
let setInvesigation investigation =
investigation |> Investigation |> Spreadsheet.UpdateArcFile |> SpreadsheetMsg |> dispatch
- Components.Metadata.Investigation.Main(investigation, setInvesigation)
+ Components.Metadata.Investigation.Main(investigation, setInvesigation, model)
| Some (ArcFiles.Template template) ->
let setTemplate template =
template |> ArcFiles.Template |> Spreadsheet.UpdateArcFile |> SpreadsheetMsg |> dispatch
diff --git a/src/Server/Server.fsproj b/src/Server/Server.fsproj
index d92ebb54..e5db47cb 100644
--- a/src/Server/Server.fsproj
+++ b/src/Server/Server.fsproj
@@ -19,7 +19,7 @@
-
+
diff --git a/src/Shared/ARCtrl.Helper.fs b/src/Shared/ARCtrl.Helper.fs
index 8b23df91..67abd0a4 100644
--- a/src/Shared/ARCtrl.Helper.fs
+++ b/src/Shared/ARCtrl.Helper.fs
@@ -24,7 +24,7 @@ module ARCtrlHelper =
with
member this.HasTableAt(index: int) =
match this with
- | Template _ -> index = 0 // Template always has exactly one table
+ | Template _ -> index = 0 // Template always has exactly one table
| Investigation i -> false
| Study (s,_) -> s.TableCount <= index
| Assay a -> a.TableCount <= index
@@ -56,6 +56,13 @@ module ARCtrlHelper =
| "rocrate" -> ROCrate
| _ -> failwithf "Unknown JSON export format: %s" str
+ member this.AsStringRdbl =
+ match this with
+ | ARCtrl -> "ARCtrl"
+ | ARCtrlCompressed -> "ARCtrl Compressed"
+ | ISA -> "ISA"
+ | ROCrate -> "RO-Crate Metadata"
+
module Table =
///
@@ -82,7 +89,7 @@ module Table =
/// It removes all values from the new table.
/// It also fills new Input/Output columns with the input/output values of the active table.
///
- /// The output of this function can be used with the SpreadsheetInterface.JoinTable Message.
+ /// The output of this function can be used with the SpreadsheetInterface.JoinTable Message.
///
/// The active/current table
/// The new table, which will be added to the existing one.
@@ -123,7 +130,7 @@ module Helper =
let ele = arr.[currentColumnIndex]
arr.RemoveAt(currentColumnIndex)
arr.Insert(newColumnIndex, ele)
-
+
let dictMoveColumn (currentColumnIndex: int) (newColumnIndex: int) (table: Dictionary) =
/// This is necessary to always access the correct value for an index.
/// It is possible to only copy the specific target column at "currentColumnIndex" and sort the keys in the for loop depending on "currentColumnIndex" and "newColumnIndex".
@@ -133,7 +140,7 @@ module Helper =
let range = [System.Math.Min(currentColumnIndex, newColumnIndex) .. System.Math.Max(currentColumnIndex,newColumnIndex)]
for columnIndex, rowIndex in backupTable.Keys do
let value = backupTable.[(columnIndex,rowIndex)]
- let newColumnIndex =
+ let newColumnIndex =
if columnIndex = currentColumnIndex then
newColumnIndex
elif List.contains columnIndex range then
@@ -171,7 +178,7 @@ with
| Component
| Characteristic
| Factor
- | Parameter
+ | Parameter
| ProtocolType -> true
| _ -> false
member this.HasOA() =
@@ -184,7 +191,7 @@ with
member this.HasIOType() =
match this with
- | Input
+ | Input
| Output -> true
| _ -> false
@@ -321,10 +328,10 @@ module Extensions =
let updateBody =
Helper.dictMoveColumn currentIndex nextIndex this.Values
()
-
+
type Template with
- member this.FileName
+ member this.FileName
with get() = this.Name.Replace(" ","_") + ".xlsx"
type CompositeHeader with
@@ -349,18 +356,18 @@ module Extensions =
/// This will only run successfully if the inner values are of the same type
///
/// The header from which the inner value will be taken.
- member this.UpdateDeepWith(other:CompositeHeader) =
+ member this.UpdateDeepWith(other:CompositeHeader) =
match this, other with
| h1, h2 when this.IsIOType && other.IsIOType ->
let io1 = h2.TryIOType().Value
- match h1 with
- | CompositeHeader.Input _ -> CompositeHeader.Input io1
+ match h1 with
+ | CompositeHeader.Input _ -> CompositeHeader.Input io1
| CompositeHeader.Output _ -> CompositeHeader.Output io1
| _ -> failwith "Error 1 in UpdateSurfaceTo. This should never hit."
| h1, h2 when this.IsTermColumn && other.IsTermColumn && not this.IsFeaturedColumn && not other.IsFeaturedColumn ->
let oa1 = h2.ToTerm()
h1.UpdateWithOA oa1
- | _ ->
+ | _ ->
this
member this.TryOA() =
@@ -394,7 +401,7 @@ module Extensions =
///
/// This is an override of an existing ARCtrl version which does not return what i want 😤
///
- member this.GetContentSwate() =
+ member this.GetContentSwate() =
match this with
| CompositeCell.FreeText s -> [|s|]
| CompositeCell.Term oa -> [| oa.NameText; defaultArg oa.TermSourceREF ""; defaultArg oa.TermAccessionNumber ""|]
@@ -414,7 +421,7 @@ module Extensions =
// | Error msg -> raise (exn msg)
///
- ///
+ ///
///
///
///
@@ -445,19 +452,19 @@ module Extensions =
member this.ToTabStr() = this.GetContentSwate() |> String.concat "\t"
- static member fromTabStr (str:string) (header: CompositeHeader) =
+ static member fromTabStr (str:string) (header: CompositeHeader) =
let content = str.Split('\t', System.StringSplitOptions.TrimEntries)
CompositeCell.fromContentValid(content, header)
static member ToTabTxt (cells: CompositeCell []) =
- cells
+ cells
|> Array.map (fun c -> c.ToTabStr())
|> String.concat (System.Environment.NewLine)
static member fromTabTxt (tabTxt: string) (header: CompositeHeader) =
let lines = tabTxt.Split(System.Environment.NewLine, System.StringSplitOptions.None)
let cells = lines |> Array.map (fun line -> CompositeCell.fromTabStr line header)
- cells
+ cells
member this.ConvertToValidCell (header: CompositeHeader) =
match this with
@@ -492,7 +499,7 @@ module Extensions =
member this.UpdateMainField(s: string) =
match this with
- | CompositeCell.Term oa ->
+ | CompositeCell.Term oa ->
oa.Name <- Some s
CompositeCell.Term oa
| CompositeCell.Unitized (_, oa) -> CompositeCell.Unitized (s, oa)
diff --git a/src/Shared/Shared.fsproj b/src/Shared/Shared.fsproj
index 18beb732..31d37d4f 100644
--- a/src/Shared/Shared.fsproj
+++ b/src/Shared/Shared.fsproj
@@ -14,7 +14,7 @@
-
-
+
+
\ No newline at end of file