From 67ad14381ad8ac8bdbbaefd0ebfa82193c8f94b9 Mon Sep 17 00:00:00 2001 From: Kevin F Date: Fri, 22 Jan 2021 11:11:13 +0100 Subject: [PATCH 01/23] Update manifest.xml (Issue #86). --- .assets/swate.zip | Bin 2408 -> 0 bytes .assets/swate/manifest.xml | 126 +++++++++++++++++++ .assets/swate/swate.cmd | 4 + .assets/swate/swate.sh | 3 + build.fsx | 20 ++- manifest.xml | 30 ++--- tests/manifest.xml | 32 ++--- tests/manifest_old.xml | 244 ++++++++++++++++++------------------- 8 files changed, 305 insertions(+), 154 deletions(-) delete mode 100644 .assets/swate.zip create mode 100644 .assets/swate/manifest.xml create mode 100644 .assets/swate/swate.cmd create mode 100644 .assets/swate/swate.sh diff --git a/.assets/swate.zip b/.assets/swate.zip deleted file mode 100644 index e19102f40e9073894daf3e9337c1229ba1eceed2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2408 zcmZ`*2{e>#8=etq$eOLmma&zuL}bf82_rL;WbB!-Oc;z^W=N4bh9aYoF!r(2m+iAf zh_Pi$Qns>3iI`&k@%8ur`j+QC_j|qXbDncu*Rz~+JqXx7Rt~^!bGLOs{`v9W7bg=D zzAhJCJYAgpToe(^fdb5~1AwnK4#>WFWcuO#06?`U03iJ9K%A4;RaX~3|C7Nu&thw& z_t+WUFo`lo(^Vc~1y+HY$667SZEd@69z1AXR~3fXd4|fcZ8y1uN)REG72dKyjx<` z0Kf98+SurHC9tJU`mi!~=%;#d+y{o@Bdeio6{#ar=eM};NoKyuLp2d{qYiJp=_WzZ z_ob*@V*G7`igNL$AjIkF{v^3!g92?Sss*M13Y_Sr%zwlFL0E}PYbI-na@p}j-}DGl z7l%UH*F*`iQY)R&mHB}0@-(>RJ$gD%SA-qCW3BzGdF%r2}>fB%?tG53+O zSMy8i0S%J?ky{)0rIq4C%V^mA=Pbti5fSZ@2K+z+APY=78+`Y=9_-*#tYgaKD3Z>n zSEmYv&E^Ehj-L*UysEcEN{FEOWVj1ksP2#FMR6D>Mm3W$dH$B*ZG+2;E2uK{0j2tQ zPH$9zQt!(|{HUjzK!g}?(%75U*C>!>j$bc-_JVeJNt{_Pug+PJue3_WjXlK@l5!jxA zPK64&f^uI*TjGC*HIOf$o~)&ARLoDc&!uNtcDwR*9;=a?Q))gROSy0+Atzk~u9Jya zho8%DO)q~0Yn6%XX(K!9JClIzH=u_Wvt4JWg;a(LmxDo6W5rA!5j>rYFXH^lZ!37@ zio}`L6-LedhYL_0WrISKYctaNgi_<*kj1*aoBYSFsTm%3P~{W=h>_^^Rz*(k^Iz~u zIW^{F3U}Lc8NFU1woUbJ&BQbhQCIits<=Utf{CQJE6B!4vZK*GC9B+$-X{{O^0wgU zE70P>-tr!w*@Jax`+bWaMXMkiof_>98g&YJkYQDHV6;}12d%{IN`2a5Kx^Z+Kw;z-E$wNl5g>x+$HVy{Zs zzxg}CBo^u~H^7TkrU>0nV_I%CyL04TLWFKo@NWGb(d7R9kID;cmmYKpFY|H6AUr}o zG|4IErHskfb{Q8n0#?vMUSKzZk%p`(9;$HuN#K_LEGf)kF5}Male8xT{S5w#S~BZ- zIXi=c>5u6am%>vP;FjC-R9%<#oZ`z<*G>ee_CFYiXt0rAq70J66Oz|Nh8f8UhZZ>7&e zBxf{r18rE7is;oP2s9A$h5iw!k}hB({+BdAi2wT;kmuuOZ41bs2UFLY^l})xUJ^ z5B2*F%G{Sl3;Tu?G5y{`o*ToyK7+o2+@?ck2J)WgtEp!h;LMxVj;|dG&sZN@O5Q4| zqCROlYQAlx$d?g#$K48AN4(;{oCX$ijCvPr;{fc5ZB5$+A zW7ay+?|lnCn?^POOq6k_dc1X@IyYtROcPk#b#o$ZU=#-7d!o(Om2|R|yL54cBJu9W|a!r%iv+{ePP5#tx=L zkt>9mBJs@H&6qv0;}_)Q?{X4@bJnK8I9enHj3z^xw7)x-cwmp+>QOe%#AJ=I$ATA5 z;J0K1G<9d|=EjI^XD^^7k0`W7b*EZ@`o>@0x&%%|gU(MKh>Lt5Lc}^-B;>UrOk>f! zhND{4uP+i*dUB-1iqm<`3({s72yJhlK?l2_4oBJ3_#$rhV#i;t3PXq-UQCO(n04r% ztomWKY5LqZC3%e|>+b|@PK$r+i<0Zh_J{<^c3$aJ@g-nV{26c0>sXn^)ZVR-ri~8( zlXA_^PNKW}%usJj1B~#`;!~d4XvMaucZ?!2&hWOVCNvA~U7~n__6(z}Ui83VV6hxc z@pP2R$n}_~M-VU|iv-}`B3znjakugQfW0fr0g(K&69^Ciu;E*D^Gb$+KhaSF-IUAx z|3Ut5vHz2Nm**I>_H5hUOTbg@Ty3jy*#EJ0E*hKA8NN&QAp4 t{yv>um0ve=uZk4=KdAU&_lo>ntG^-w#>TV=0I)Kjcpw1K%%lPU{sZwd3#|YE diff --git a/.assets/swate/manifest.xml b/.assets/swate/manifest.xml new file mode 100644 index 00000000..35a02f8d --- /dev/null +++ b/.assets/swate/manifest.xml @@ -0,0 +1,126 @@ + + + 5d6f5462-3401-48ec-9406-d12882e9ad83 + 0.2.1 + Computational Systems Biology + en-US + + + + + + + bio.uni-kl.de + + + + + + + + ReadWriteDocument + + + + + + + <Description resid="GetStarted.Description"/> + <LearnMoreUrl resid="GetStarted.LearnMoreUrl"/> + </GetStarted> + <ExtensionPoint xsi:type="PrimaryCommandSurface"> + <OfficeTab id="TabData"> + <Group id="SwateCommands"> + <Label resid="SwateCommands.Label"/> + <Icon> + <bt:Image size="16" resid="Icon.16x16"/> + <bt:Image size="20" resid="Icon.20x20"/> + <bt:Image size="24" resid="Icon.24x24"/> + <bt:Image size="32" resid="Icon.32x32"/> + <bt:Image size="40" resid="Icon.40x40"/> + <bt:Image size="48" resid="Icon.48x48"/> + <bt:Image size="64" resid="Icon.64x64"/> + <bt:Image size="80" resid="Icon.80x80"/> + <bt:Image size="96" resid="Icon.96x96"/> + </Icon> + <!--<Control xsi:type="Button" id="TermSearch"> + <Label resid="TermSearch.Label"/> + <Supertip> + <Title resid="TermSearch.Label"/> + <Description resid="TermSearch.Tooltip"/> + </Supertip> + <Icon> + <bt:Image size="16" resid="Icon.16x16"/> + <bt:Image size="20" resid="Icon.20x20"/> + <bt:Image size="24" resid="Icon.24x24"/> + <bt:Image size="32" resid="Icon.32x32"/> + <bt:Image size="40" resid="Icon.40x40"/> + <bt:Image size="48" resid="Icon.48x48"/> + <bt:Image size="64" resid="Icon.64x64"/> + <bt:Image size="80" resid="Icon.80x80"/> + <bt:Image size="96" resid="Icon.96x96"/> + </Icon> + <Action xsi:type="ShowTaskpane"> + <TaskpaneId>ButtonId1</TaskpaneId> + <SourceLocation resid="TermSearch.Url"/> + </Action> + </Control>--> + <Control xsi:type="Button" id="AddBuildingBlock"> + <Label resid="AddBuildingBlock.Label"/> + <Supertip> + <Title resid="AddBuildingBlock.Label"/> + <Description resid="AddBuildingBlock.Tooltip"/> + </Supertip> + <Icon> + <bt:Image size="16" resid="Icon.16x16"/> + <bt:Image size="20" resid="Icon.20x20"/> + <bt:Image size="24" resid="Icon.24x24"/> + <bt:Image size="32" resid="Icon.32x32"/> + <bt:Image size="40" resid="Icon.40x40"/> + <bt:Image size="48" resid="Icon.48x48"/> + <bt:Image size="64" resid="Icon.64x64"/> + <bt:Image size="80" resid="Icon.80x80"/> + <bt:Image size="96" resid="Icon.96x96"/> + </Icon> + <Action xsi:type="ShowTaskpane"> + <TaskpaneId>ButtonId2</TaskpaneId> + <SourceLocation resid="AddBuildingBlock.Url"/> + </Action> + </Control> + </Group> + </OfficeTab> + </ExtensionPoint> + </DesktopFormFactor> + </Host> + </Hosts> + <Resources> + <bt:Images> + <bt:Image id="Icon.16x16" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-16.png"/> + <bt:Image id="Icon.20x20" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-20.png"/> + <bt:Image id="Icon.24x24" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-24.png"/> + <bt:Image id="Icon.32x32" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-32.png"/> + <bt:Image id="Icon.40x40" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-40.png"/> + <bt:Image id="Icon.48x48" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-48.png"/> + <bt:Image id="Icon.64x64" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-64.png"/> + <bt:Image id="Icon.80x80" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-80.png"/> + <bt:Image id="Icon.96x96" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-96.png"/> + </bt:Images> + <bt:Urls> + <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> + <!--<bt:Url id="TermSearch.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#TermSearch"/>--> + <bt:Url id="AddBuildingBlock.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#AddBuildingBlock"/> + </bt:Urls> + <bt:ShortStrings> + <bt:String id="GetStarted.Title" DefaultValue="Get started annotating your data for greater good!"/> + <bt:String id="SwateCommands.Label" DefaultValue="Swate"/> + <!--<bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/>--> + <bt:String id="AddBuildingBlock.Label" DefaultValue="Swate"/> + </bt:ShortStrings> + <bt:LongStrings> + <bt:String id="GetStarted.Description" DefaultValue="Swate was loaded succesfully. Go to the DATA tab and click the 'Swate' button to get started."/> + <!--<bt:String id="TermSearch.Tooltip" DefaultValue="Open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/>--> + <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="Open a task pane to gain full access to the Swate functionality."/> + </bt:LongStrings> + </Resources> + </VersionOverrides> +</OfficeApp> diff --git a/.assets/swate/swate.cmd b/.assets/swate/swate.cmd new file mode 100644 index 00000000..7eb5d841 --- /dev/null +++ b/.assets/swate/swate.cmd @@ -0,0 +1,4 @@ +@ECHO OFF +echo "Starting Excel instance with the SWATE manifest ..." + +npx office-addin-debugging start manifest.xml desktop --debug-method web \ No newline at end of file diff --git a/.assets/swate/swate.sh b/.assets/swate/swate.sh new file mode 100644 index 00000000..be647d24 --- /dev/null +++ b/.assets/swate/swate.sh @@ -0,0 +1,3 @@ +echo "Starting Excel instance with the SWATE manifest ..." + +npx office-addin-debugging start manifest.xml desktop --debug-method web \ No newline at end of file diff --git a/build.fsx b/build.fsx index a1408273..46b3fe59 100644 --- a/build.fsx +++ b/build.fsx @@ -2,8 +2,8 @@ #load "./.fake/build.fsx/intellisense.fsx" #r "netstandard" - open System +open System.Text open Fake open Fake.Core open Fake.DotNet @@ -521,6 +521,24 @@ Target.create "Release" (fun config -> ] Trace.trace "Update Version.fs done!" + + /// Update maniefest.xmls + + Trace.trace "Update manifest.xml" + + let _ = + let newVer = sprintf "<Version>%i.%i.%i</Version>" newRelease.SemVer.Major newRelease.SemVer.Minor newRelease.SemVer.Patch + Shell.regexReplaceInFilesWithEncoding + "<Version>[0-9]+.[0-9]+.[0-9]+</Version>" + newVer + Encoding.UTF8 + [ + (Path.combine __SOURCE_DIRECTORY__ ".assets\swate\manifest.xml") + (Path.combine __SOURCE_DIRECTORY__ "manifest.xml") + (Path.combine __SOURCE_DIRECTORY__ "tests\manifest.xml") + ] + + Trace.trace "Update manifest.xml done!" ) Target.create "GithubDraft" (fun config -> diff --git a/manifest.xml b/manifest.xml index dd819e94..792dcd64 100644 --- a/manifest.xml +++ b/manifest.xml @@ -1,11 +1,11 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp"> <Id>5d6f5462-3401-48ec-9406-d12882e9ad83</Id> - <Version>1.0.0.0</Version> + <Version>0.2.1</Version> <ProviderName>Computational Systems Biology</ProviderName> <DefaultLocale>en-US</DefaultLocale> - <DisplayName DefaultValue="CSBAnnotator"/> - <Description DefaultValue="Utility functions to annotate data in a fast and safe way"/> + <DisplayName DefaultValue="Swate"/> + <Description DefaultValue="Utility functions to annotate data in a fast and safe way."/> <IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png"/> <HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-80.png"/> <SupportUrl DefaultValue="https://csb.bio.uni-kl.de/"/> @@ -30,8 +30,8 @@ </GetStarted> <ExtensionPoint xsi:type="PrimaryCommandSurface"> <OfficeTab id="TabData"> - <Group id="CSBAnnotatorCommands"> - <Label resid="CSBAnnotatorCommands.Label"/> + <Group id="SwateCommands"> + <Label resid="SwateCommands.Label"/> <Icon> <bt:Image size="16" resid="Icon.16x16"/> <bt:Image size="20" resid="Icon.20x20"/> @@ -43,7 +43,7 @@ <bt:Image size="80" resid="Icon.80x80"/> <bt:Image size="96" resid="Icon.96x96"/> </Icon> - <Control xsi:type="Button" id="TermSearch"> + <!--<Control xsi:type="Button" id="TermSearch"> <Label resid="TermSearch.Label"/> <Supertip> <Title resid="TermSearch.Label"/> @@ -64,7 +64,7 @@ <TaskpaneId>ButtonId1</TaskpaneId> <SourceLocation resid="TermSearch.Url"/> </Action> - </Control> + </Control>--> <Control xsi:type="Button" id="AddBuildingBlock"> <Label resid="AddBuildingBlock.Label"/> <Supertip> @@ -107,19 +107,19 @@ </bt:Images> <bt:Urls> <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> - <bt:Url id="TermSearch.Url" DefaultValue="https://localhost:3000/#TermSearch"/> + <!--<bt:Url id="TermSearch.Url" DefaultValue="https://localhost:3000/#TermSearch"/>--> <bt:Url id="AddBuildingBlock.Url" DefaultValue="https://localhost:3000/#AddBuildingBlock"/> </bt:Urls> <bt:ShortStrings> <bt:String id="GetStarted.Title" DefaultValue="Get started annotating your data for greater good!"/> - <bt:String id="CSBAnnotatorCommands.Label" DefaultValue="CSBAnnotator Commands"/> - <bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/> - <bt:String id="AddBuildingBlock.Label" DefaultValue="Add Annotation Building Block"/> + <bt:String id="SwateCommands.Label" DefaultValue="Swate"/> + <!--<bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/>--> + <bt:String id="AddBuildingBlock.Label" DefaultValue="Swate"/> </bt:ShortStrings> <bt:LongStrings> - <bt:String id="GetStarted.Description" DefaultValue="CSBAnnotator succesfully. Go to the DATA tab and click the 'Show Annotation Pane' button to get started."/> - <bt:String id="TermSearch.Tooltip" DefaultValue="open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/> - <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="open a taskpane where you can select annotation building block and add them to yourt anotation table."/> + <bt:String id="GetStarted.Description" DefaultValue="Swate was loaded succesfully. Go to the DATA tab and click the 'Swate' button to get started."/> + <!--<bt:String id="TermSearch.Tooltip" DefaultValue="Open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/>--> + <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="Open a task pane to gain full access to the Swate functionality."/> </bt:LongStrings> </Resources> </VersionOverrides> diff --git a/tests/manifest.xml b/tests/manifest.xml index 965238cb..35a02f8d 100644 --- a/tests/manifest.xml +++ b/tests/manifest.xml @@ -1,11 +1,11 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp"> <Id>5d6f5462-3401-48ec-9406-d12882e9ad83</Id> - <Version>1.0.0.0</Version> + <Version>0.2.1</Version> <ProviderName>Computational Systems Biology</ProviderName> <DefaultLocale>en-US</DefaultLocale> - <DisplayName DefaultValue="CSBAnnotator"/> - <Description DefaultValue="Utility functions to annotate data in a fast and safe way"/> + <DisplayName DefaultValue="Swate"/> + <Description DefaultValue="Utility functions to annotate data in a fast and safe way."/> <IconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-32.png"/> <HighResolutionIconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-80.png"/> <SupportUrl DefaultValue="https://csb.bio.uni-kl.de/"/> @@ -30,8 +30,8 @@ </GetStarted> <ExtensionPoint xsi:type="PrimaryCommandSurface"> <OfficeTab id="TabData"> - <Group id="CSBAnnotatorCommands"> - <Label resid="CSBAnnotatorCommands.Label"/> + <Group id="SwateCommands"> + <Label resid="SwateCommands.Label"/> <Icon> <bt:Image size="16" resid="Icon.16x16"/> <bt:Image size="20" resid="Icon.20x20"/> @@ -43,7 +43,7 @@ <bt:Image size="80" resid="Icon.80x80"/> <bt:Image size="96" resid="Icon.96x96"/> </Icon> - <Control xsi:type="Button" id="TermSearch"> + <!--<Control xsi:type="Button" id="TermSearch"> <Label resid="TermSearch.Label"/> <Supertip> <Title resid="TermSearch.Label"/> @@ -64,7 +64,7 @@ <TaskpaneId>ButtonId1</TaskpaneId> <SourceLocation resid="TermSearch.Url"/> </Action> - </Control> + </Control>--> <Control xsi:type="Button" id="AddBuildingBlock"> <Label resid="AddBuildingBlock.Label"/> <Supertip> @@ -107,20 +107,20 @@ </bt:Images> <bt:Urls> <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> - <bt:Url id="TermSearch.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#TermSearch"/> + <!--<bt:Url id="TermSearch.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#TermSearch"/>--> <bt:Url id="AddBuildingBlock.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#AddBuildingBlock"/> </bt:Urls> <bt:ShortStrings> <bt:String id="GetStarted.Title" DefaultValue="Get started annotating your data for greater good!"/> - <bt:String id="CSBAnnotatorCommands.Label" DefaultValue="CSBAnnotator Commands"/> - <bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/> - <bt:String id="AddBuildingBlock.Label" DefaultValue="Add Annotation Building Block"/> + <bt:String id="SwateCommands.Label" DefaultValue="Swate"/> + <!--<bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/>--> + <bt:String id="AddBuildingBlock.Label" DefaultValue="Swate"/> </bt:ShortStrings> <bt:LongStrings> - <bt:String id="GetStarted.Description" DefaultValue="CSBAnnotator succesfully. Go to the DATA tab and click the 'Show Annotation Pane' button to get started."/> - <bt:String id="TermSearch.Tooltip" DefaultValue="open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/> - <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="open a taskpane where you can select annotation building block and add them to yourt anotation table."/> + <bt:String id="GetStarted.Description" DefaultValue="Swate was loaded succesfully. Go to the DATA tab and click the 'Swate' button to get started."/> + <!--<bt:String id="TermSearch.Tooltip" DefaultValue="Open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/>--> + <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="Open a task pane to gain full access to the Swate functionality."/> </bt:LongStrings> </Resources> </VersionOverrides> -</OfficeApp> \ No newline at end of file +</OfficeApp> diff --git a/tests/manifest_old.xml b/tests/manifest_old.xml index 7a116f5d..965238cb 100644 --- a/tests/manifest_old.xml +++ b/tests/manifest_old.xml @@ -1,126 +1,126 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp"> - <Id>5d6f5462-3401-48ec-9406-d12882e9ad83</Id> - <Version>1.0.0.0</Version> - <ProviderName>Computational Systems Biology</ProviderName> - <DefaultLocale>en-US</DefaultLocale> - <DisplayName DefaultValue="CSBAnnotator"/> - <Description DefaultValue="Utility functions to annotate data in a fast and safe way"/> - <IconUrl DefaultValue="https://swate.bio.uni-kl.de/assets/icon-32.png"/> - <HighResolutionIconUrl DefaultValue="https://swate.bio.uni-kl.de/assets/icon-80.png"/> - <SupportUrl DefaultValue="https://csb.bio.uni-kl.de/"/> - <AppDomains> - <AppDomain>bio.uni-kl.de</AppDomain> - </AppDomains> + <Id>5d6f5462-3401-48ec-9406-d12882e9ad83</Id> + <Version>1.0.0.0</Version> + <ProviderName>Computational Systems Biology</ProviderName> + <DefaultLocale>en-US</DefaultLocale> + <DisplayName DefaultValue="CSBAnnotator"/> + <Description DefaultValue="Utility functions to annotate data in a fast and safe way"/> + <IconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-32.png"/> + <HighResolutionIconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-80.png"/> + <SupportUrl DefaultValue="https://csb.bio.uni-kl.de/"/> + <AppDomains> + <AppDomain>bio.uni-kl.de</AppDomain> + </AppDomains> + <Hosts> + <Host Name="Workbook"/> + </Hosts> + <DefaultSettings> + <SourceLocation DefaultValue="https://swate.denbi.uni-tuebingen.de/"/> + </DefaultSettings> + <Permissions>ReadWriteDocument</Permissions> + <VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0"> <Hosts> - <Host Name="Workbook"/> + <Host xsi:type="Workbook"> + <DesktopFormFactor> + <GetStarted> + <Title resid="GetStarted.Title"/> + <Description resid="GetStarted.Description"/> + <LearnMoreUrl resid="GetStarted.LearnMoreUrl"/> + </GetStarted> + <ExtensionPoint xsi:type="PrimaryCommandSurface"> + <OfficeTab id="TabData"> + <Group id="CSBAnnotatorCommands"> + <Label resid="CSBAnnotatorCommands.Label"/> + <Icon> + <bt:Image size="16" resid="Icon.16x16"/> + <bt:Image size="20" resid="Icon.20x20"/> + <bt:Image size="24" resid="Icon.24x24"/> + <bt:Image size="32" resid="Icon.32x32"/> + <bt:Image size="40" resid="Icon.40x40"/> + <bt:Image size="48" resid="Icon.48x48"/> + <bt:Image size="64" resid="Icon.64x64"/> + <bt:Image size="80" resid="Icon.80x80"/> + <bt:Image size="96" resid="Icon.96x96"/> + </Icon> + <Control xsi:type="Button" id="TermSearch"> + <Label resid="TermSearch.Label"/> + <Supertip> + <Title resid="TermSearch.Label"/> + <Description resid="TermSearch.Tooltip"/> + </Supertip> + <Icon> + <bt:Image size="16" resid="Icon.16x16"/> + <bt:Image size="20" resid="Icon.20x20"/> + <bt:Image size="24" resid="Icon.24x24"/> + <bt:Image size="32" resid="Icon.32x32"/> + <bt:Image size="40" resid="Icon.40x40"/> + <bt:Image size="48" resid="Icon.48x48"/> + <bt:Image size="64" resid="Icon.64x64"/> + <bt:Image size="80" resid="Icon.80x80"/> + <bt:Image size="96" resid="Icon.96x96"/> + </Icon> + <Action xsi:type="ShowTaskpane"> + <TaskpaneId>ButtonId1</TaskpaneId> + <SourceLocation resid="TermSearch.Url"/> + </Action> + </Control> + <Control xsi:type="Button" id="AddBuildingBlock"> + <Label resid="AddBuildingBlock.Label"/> + <Supertip> + <Title resid="AddBuildingBlock.Label"/> + <Description resid="AddBuildingBlock.Tooltip"/> + </Supertip> + <Icon> + <bt:Image size="16" resid="Icon.16x16"/> + <bt:Image size="20" resid="Icon.20x20"/> + <bt:Image size="24" resid="Icon.24x24"/> + <bt:Image size="32" resid="Icon.32x32"/> + <bt:Image size="40" resid="Icon.40x40"/> + <bt:Image size="48" resid="Icon.48x48"/> + <bt:Image size="64" resid="Icon.64x64"/> + <bt:Image size="80" resid="Icon.80x80"/> + <bt:Image size="96" resid="Icon.96x96"/> + </Icon> + <Action xsi:type="ShowTaskpane"> + <TaskpaneId>ButtonId2</TaskpaneId> + <SourceLocation resid="AddBuildingBlock.Url"/> + </Action> + </Control> + </Group> + </OfficeTab> + </ExtensionPoint> + </DesktopFormFactor> + </Host> </Hosts> - <DefaultSettings> - <SourceLocation DefaultValue="https://swate.bio.uni-kl.de/"/> - </DefaultSettings> - <Permissions>ReadWriteDocument</Permissions> - <VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0"> - <Hosts> - <Host xsi:type="Workbook"> - <DesktopFormFactor> - <GetStarted> - <Title resid="GetStarted.Title"/> - <Description resid="GetStarted.Description"/> - <LearnMoreUrl resid="GetStarted.LearnMoreUrl"/> - </GetStarted> - <ExtensionPoint xsi:type="PrimaryCommandSurface"> - <OfficeTab id="TabData"> - <Group id="CSBAnnotatorCommands"> - <Label resid="CSBAnnotatorCommands.Label"/> - <Icon> - <bt:Image size="16" resid="Icon.16x16"/> - <bt:Image size="20" resid="Icon.20x20"/> - <bt:Image size="24" resid="Icon.24x24"/> - <bt:Image size="32" resid="Icon.32x32"/> - <bt:Image size="40" resid="Icon.40x40"/> - <bt:Image size="48" resid="Icon.48x48"/> - <bt:Image size="64" resid="Icon.64x64"/> - <bt:Image size="80" resid="Icon.80x80"/> - <bt:Image size="96" resid="Icon.96x96"/> - </Icon> - <Control xsi:type="Button" id="TermSearch"> - <Label resid="TermSearch.Label"/> - <Supertip> - <Title resid="TermSearch.Label"/> - <Description resid="TermSearch.Tooltip"/> - </Supertip> - <Icon> - <bt:Image size="16" resid="Icon.16x16"/> - <bt:Image size="20" resid="Icon.20x20"/> - <bt:Image size="24" resid="Icon.24x24"/> - <bt:Image size="32" resid="Icon.32x32"/> - <bt:Image size="40" resid="Icon.40x40"/> - <bt:Image size="48" resid="Icon.48x48"/> - <bt:Image size="64" resid="Icon.64x64"/> - <bt:Image size="80" resid="Icon.80x80"/> - <bt:Image size="96" resid="Icon.96x96"/> - </Icon> - <Action xsi:type="ShowTaskpane"> - <TaskpaneId>ButtonId1</TaskpaneId> - <SourceLocation resid="TermSearch.Url"/> - </Action> - </Control> - <Control xsi:type="Button" id="AddBuildingBlock"> - <Label resid="AddBuildingBlock.Label"/> - <Supertip> - <Title resid="AddBuildingBlock.Label"/> - <Description resid="AddBuildingBlock.Tooltip"/> - </Supertip> - <Icon> - <bt:Image size="16" resid="Icon.16x16"/> - <bt:Image size="20" resid="Icon.20x20"/> - <bt:Image size="24" resid="Icon.24x24"/> - <bt:Image size="32" resid="Icon.32x32"/> - <bt:Image size="40" resid="Icon.40x40"/> - <bt:Image size="48" resid="Icon.48x48"/> - <bt:Image size="64" resid="Icon.64x64"/> - <bt:Image size="80" resid="Icon.80x80"/> - <bt:Image size="96" resid="Icon.96x96"/> - </Icon> - <Action xsi:type="ShowTaskpane"> - <TaskpaneId>ButtonId2</TaskpaneId> - <SourceLocation resid="AddBuildingBlock.Url"/> - </Action> - </Control> - </Group> - </OfficeTab> - </ExtensionPoint> - </DesktopFormFactor> - </Host> - </Hosts> - <Resources> - <bt:Images> - <bt:Image id="Icon.16x16" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-16.png"/> - <bt:Image id="Icon.20x20" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-20.png"/> - <bt:Image id="Icon.24x24" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-24.png"/> - <bt:Image id="Icon.32x32" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-32.png"/> - <bt:Image id="Icon.40x40" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-40.png"/> - <bt:Image id="Icon.48x48" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-48.png"/> - <bt:Image id="Icon.64x64" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-64.png"/> - <bt:Image id="Icon.80x80" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-80.png"/> - <bt:Image id="Icon.96x96" DefaultValue="https://swate.bio.uni-kl.de/assets/icon-96.png"/> - </bt:Images> - <bt:Urls> - <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> - <bt:Url id="TermSearch.Url" DefaultValue="https://swate.bio.uni-kl.de/#TermSearch"/> - <bt:Url id="AddBuildingBlock.Url" DefaultValue="https://swate.bio.uni-kl.de/#AddBuildingBlock"/> - </bt:Urls> - <bt:ShortStrings> - <bt:String id="GetStarted.Title" DefaultValue="Get started annotating your data for greater good!"/> - <bt:String id="CSBAnnotatorCommands.Label" DefaultValue="CSBAnnotator Commands"/> - <bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/> - <bt:String id="AddBuildingBlock.Label" DefaultValue="Add Annotation Building Block"/> - </bt:ShortStrings> - <bt:LongStrings> - <bt:String id="GetStarted.Description" DefaultValue="CSBAnnotator succesfully. Go to the DATA tab and click the 'Show Annotation Pane' button to get started."/> - <bt:String id="TermSearch.Tooltip" DefaultValue="open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/> - <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="open a taskpane where you can select annotation building block and add them to yourt anotation table."/> - </bt:LongStrings> - </Resources> - </VersionOverrides> + <Resources> + <bt:Images> + <bt:Image id="Icon.16x16" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-16.png"/> + <bt:Image id="Icon.20x20" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-20.png"/> + <bt:Image id="Icon.24x24" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-24.png"/> + <bt:Image id="Icon.32x32" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-32.png"/> + <bt:Image id="Icon.40x40" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-40.png"/> + <bt:Image id="Icon.48x48" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-48.png"/> + <bt:Image id="Icon.64x64" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-64.png"/> + <bt:Image id="Icon.80x80" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-80.png"/> + <bt:Image id="Icon.96x96" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-96.png"/> + </bt:Images> + <bt:Urls> + <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> + <bt:Url id="TermSearch.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#TermSearch"/> + <bt:Url id="AddBuildingBlock.Url" DefaultValue="https://swate.denbi.uni-tuebingen.de/#AddBuildingBlock"/> + </bt:Urls> + <bt:ShortStrings> + <bt:String id="GetStarted.Title" DefaultValue="Get started annotating your data for greater good!"/> + <bt:String id="CSBAnnotatorCommands.Label" DefaultValue="CSBAnnotator Commands"/> + <bt:String id="TermSearch.Label" DefaultValue="Insert Ontology Term"/> + <bt:String id="AddBuildingBlock.Label" DefaultValue="Add Annotation Building Block"/> + </bt:ShortStrings> + <bt:LongStrings> + <bt:String id="GetStarted.Description" DefaultValue="CSBAnnotator succesfully. Go to the DATA tab and click the 'Show Annotation Pane' button to get started."/> + <bt:String id="TermSearch.Tooltip" DefaultValue="open a taskpane where you can search for ontology terms in multiple ways and fill the results into your sheet."/> + <bt:String id="AddBuildingBlock.Tooltip" DefaultValue="open a taskpane where you can select annotation building block and add them to yourt anotation table."/> + </bt:LongStrings> + </Resources> + </VersionOverrides> </OfficeApp> \ No newline at end of file From 630fd5c876b2a73d47fb6935d993be46188162e1 Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Fri, 22 Jan 2021 12:04:21 +0100 Subject: [PATCH 02/23] Update GithubDraft target to account for changed folder structure. --- .assets/{swate => assets}/manifest.xml | 0 .assets/{swate => assets}/swate.cmd | 0 .assets/{swate => assets}/swate.sh | 0 .assets/swate.zip | Bin 0 -> 2128 bytes RELEASE_NOTES.md | 5 + build.fsx | 17 +- paket.dependencies | 4 + paket.lock | 372 +++---------------------- 8 files changed, 64 insertions(+), 334 deletions(-) rename .assets/{swate => assets}/manifest.xml (100%) rename .assets/{swate => assets}/swate.cmd (100%) rename .assets/{swate => assets}/swate.sh (100%) create mode 100644 .assets/swate.zip diff --git a/.assets/swate/manifest.xml b/.assets/assets/manifest.xml similarity index 100% rename from .assets/swate/manifest.xml rename to .assets/assets/manifest.xml diff --git a/.assets/swate/swate.cmd b/.assets/assets/swate.cmd similarity index 100% rename from .assets/swate/swate.cmd rename to .assets/assets/swate.cmd diff --git a/.assets/swate/swate.sh b/.assets/assets/swate.sh similarity index 100% rename from .assets/swate/swate.sh rename to .assets/assets/swate.sh diff --git a/.assets/swate.zip b/.assets/swate.zip new file mode 100644 index 0000000000000000000000000000000000000000..bcd12b5f3062d67c7aa2fd183311973fa99fcdd1 GIT binary patch literal 2128 zcmZ{lc{Cg78pdM}TBB+hiYc)Uq9t0CUKFu6mR1lHL8PQeBx<SFmPxDBT1!RkYb2Dk z(@JP9Q%i@jl(8!_QCloUL(5I?AD!Mg_kQ1b&-cCWd!BQC=lSP>+41p90ssIYzyWd2 zIWp>JaXmo*04WCm9OF(yeKEm-0azS3Dl~-R?t`5$5RY%mKM<>Bms}n<Rfp=PI1V8u z`^z8NE3Pr7fu6SoC%3F4?%ZmLd6tgznZK$ls5seKbHKYWdbo|=V~sAi#UJj>VitgL zAOtKowTL_!DQ?3nHH0+8lLOfoKtjT#EODroqJI!HX&b+_qI1~cXT}#%R0)JA`>ocO z+f$7%^J_}@&v!%S>}kn3KB*XcY>a_}bSnGDXv{!QGL@d7AQ^J*6ahQ0%lxoEjTtyt z8UF0LvN~vSQ{sU+8eHi9=BRyFPE_`_mu*tjEX1vYsqX@6gjX3j-QDH!-xvr6Dw=Hw zy4h}z=krX0Xl5umprrYsm%+`GV$wGRJ8rT32G=45K@vEy(6q1G>JGH*;xC=^ORx5B zJBh~jj9z|@nO);}Z&r^f7#;|!a*7R9vj|#_dL)(lcR&Y%c_#evsa_@e6lX@5n#)uX zePp>s7BEmcnTaD;G6}Z*oN8-Ot4ji^?UMjhrga9Fs1n|4UIa97$cekRW;672ue=A+ z=5ek-=COHY-#KkF#oQl$=l5-HH|I66;MD<6%oTYqF-759ogh2vgn9|y_Lun-<$Ra( zb|`2dQq0g!;_*#5P$?N|c8OKWuIy=o?Pq}9ib>a;Dj)6Js9JdqcS7u3x&s(9rv1}~ z0Uj(P=Ux#f>wHfs|JT^hA<n955=;VOFq5pZ9FH_tXs#A2-;G#}4Tv=f3h~POkd|s0 zVNc55APc?M=!-IS#k;Oz%dW|%UUA>}Q8>K@CIeP278YxZ_^C%*v?)(nB6A#mu5O`3 zo%s*|>yV{8#J>ML{pQ{uBB3Xy%9a${h0<Cb-)2^@WzuICOm#6@ueOAgswA*BTl?p) z2D)1Dhby5B@M$3pmFx~Qt#Ah}rF*rnbdP^~@#KPq3da2{f}Rvd?T$Z6rzn#|7C~hs znR2M3e?I}>b9UqqvLJelhIx@4?-v-AmaVrDFG};p)@+35Run)JhrR36v9)8J*odgM zlXy3s9Nw}DNto-PZvdFO?$@epJ;>hhW0bh4yXj(XJQK(qv!>6Q<g5{%nxfS&(2zo& zr}eWKOU1q3AGj0M3$$1T+<#V0Na&Z9ya)S&T*#dfdpwe3yo}*~c84Zr`{t#ra|{<o zmG2+b4sXsjT0}_6sDx+P2uJ2u8JW&Vih$u){-hOkLD%&(9>wPYA3`XImd47GA$0%Q zq@YyGYfpYtW7oUvM2<CVO^kZKSibHSzxET&>o~pc6+UvjQet4FbeV>WK}){Fb)9<> zS2#EFwwKIfwA&iSHb;#dN8f)mYL~N8@#&@s(_$U1@^*C-IrQFDyBJ!ya;CKhRh|}m z{)DKb(ZlGG#tL#GDQK`N)l>%pBU-BHvrfEsw>L_+UCXF3F=~NU@2Za~)J&9JiRnbA zdxU1JXyHGrM~^DP+jtU+%o?35M*ZC{K{O-x$(WrrYy!bR9nQ)e-X`8Wy}f)H$;o(T zuqwmyk8&>K+ga}3q>fL4dZxnbmL?r#qc8an!LDl(iFEq@v=trlpqZ|Z^3x<fDmD_Y zZOKV=@$^izI@|AC-$HRZ>1jCE(xM;I>|+Qy9C`0Sp~zWGPCRd3>D%kwq15v={~<vA zOO=(Ps?XHU*RSyiQ7WisJl)%fkxn~k`wq$&{*H3dOje4ry9rI$C=6fx;P}FN*jc6X z=mEodIJoPRa(l19M_M>g>%3|fQN_VB2c+9)2zMKkxm%KFrTM%3<LHaoDJ#Owi~I;; zeD^E2icY=yD{s<&OYOT%7#MUh3h}gEm*6?B5p7+runOw(X>myDEm-HsuyIS8Aj-(> z6C@{7{tWB>l@#A89av`=uu!oHaIx;5)?GY!zkMY14&vo>$Ihy(O&*|DGvRdUOOGs{ z>zpxE!v*QCR%1;4K|+``k*AMA%&zVu`FW(C(|kqhm5`j{7uK$GN&eoGm&1ErC#>Q` zqEvy^KKK&qsWjwn^Vp!;%hGqe#K>OK_lnM(gHlTDOmI2ls_&gsJkJt&glKoE%w(sA z#Z4V>5bb&G*^bKX$F0*$!URCRp;9a{B2w?!jbG=ic*%!Cu&?2Q_Vjl0Z_qg&%?*_d zZV7V>OYp@7fc-;}CjDk2iD$&E<{5MHx2DvBP#PKQ2zZ!$mW}R+a;eLQkD(g4qZz{4 zrw6x7*pn%U+9j*T!Z6aAsxkotzOn0sST4U!Quy<W$C|X|P|_&M3wm&26S-QE1`1%X zN{!!8e`p(mjxWY9>FI1V|Er<_)@C1&>1rZYF#F$t(x5nz8(gpyZUMgnVo_W^vBc9~ z_(+703kvIl$!av4F(99P_RH6hh)?w3cZZDh*oHi*$f_pg{^?<{+)78|dA~P<_HgfX zR_ePXkbZItUX~dCpscL>H91xEP8Yw&tj6bZYS?nzxHq03UHF#oui||3g6r*;D_qxj zcqIY<Ka{y--<)qF`dj7ya{O<Z7dPa;`u|VaKYjRHcKB6>MZxR@xE%n%$GuhDH%sVC F_iyS8!2tjO literal 0 HcmV?d00001 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e08dfdab..e8926bab 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,8 @@ +### 0.2.1+67ad143 (Released 2021-1-22) +* Additions: + * latest commit #67ad143 + * [[#67ad143](https://github.com/nfdi4plants/Swate/commit/67ad14381ad8ac8bdbbaefd0ebfa82193c8f94b9)] Update manifest.xml (Issue #86). + ### 0.2.0+899b535 (Released 2021-1-11) * Additions: * latest commit #899b535 diff --git a/build.fsx b/build.fsx index 46b3fe59..b83775ed 100644 --- a/build.fsx +++ b/build.fsx @@ -541,6 +541,18 @@ Target.create "Release" (fun config -> Trace.trace "Update manifest.xml done!" ) +Target.create "ZipAssets" (fun _ -> + + let assetPath = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@".assets\assets") + let assetDir = Fake.IO.DirectoryInfo.ofPath assetPath + + let files = + let assetsPaths = Fake.IO.DirectoryInfo.getFiles assetDir + assetsPaths |> Array.map (fun x -> x.FullName) + + Zip.zip assetDir.FullName ".assets\swate.zip" files +) + Target.create "GithubDraft" (fun config -> let prevReleaseNotes = @@ -594,7 +606,6 @@ Target.create "GithubDraft" (fun config -> let release = ReleaseNotes.load "RELEASE_NOTES.md" let semVer = (sprintf "v%i.%i.%i" release.SemVer.Major release.SemVer.Minor release.SemVer.Patch) - let token = match Environment.environVarOrDefault "github_token" "", tokenOpt with | s, None when System.String.IsNullOrWhiteSpace s |> not -> s @@ -609,6 +620,7 @@ Target.create "GithubDraft" (fun config -> let files = let assetPath = System.IO.Path.Combine(__SOURCE_DIRECTORY__,@".assets") let assetDir = Fake.IO.DirectoryInfo.ofPath assetPath + /// This only accesses files and not folders. So in this case it will only access the .zip file created by "ZipAssets" let assetsPaths = Fake.IO.DirectoryInfo.getFiles assetDir assetsPaths |> Array.map (fun x -> x.FullName) @@ -709,6 +721,9 @@ open Fake.Core.TargetOperators "IsExistingReleaseNotes" ==> "Release" +"ZipAssets" + ==> "GithubDraft" + "InstallOfficeAddinTooling" ==> "WebpackConfigSetup" ==> "LocalConnectionStringSetup" diff --git a/paket.dependencies b/paket.dependencies index 6f5e1cf6..78b7f28d 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -5,8 +5,10 @@ storage: none nuget Fable.Remoting.Giraffe nuget Fable.SimpleJson 3.11.0 nuget Fable.SimpleXml +nuget FSharp.Data nuget Fulma.Extensions.Wikiki.Checkradio nuget Fulma.Extensions.Wikiki.Slider +nuget ISADotNet nuget Saturn nuget Expecto nuget MySql.Data 8.0.21 @@ -28,6 +30,7 @@ nuget Fable.Browser.MediaQueryList nuget Fable.Elmish.Browser nuget Fulma.Extensions.Wikiki.Tooltip nuget Fulma.Extensions.Wikiki.Switch +nuget System.Text.Encodings.Web nuget Thoth.Elmish.Debouncer group Build @@ -37,6 +40,7 @@ group Build nuget Fake.Api.GitHub nuget Fake.DotNet.AssemblyInfoFile 5.20.3 +nuget Fake.IO.Zip nuget Fake.Tools.Git 5.20.3 nuget FSharp.Core 4.7.2 nuget Fake.Core.ReleaseNotes diff --git a/paket.lock b/paket.lock index 24769978..98919937 100644 --- a/paket.lock +++ b/paket.lock @@ -32,8 +32,8 @@ NUGET Fable.Browser.Event (>= 1.2.1) Fable.Core (>= 3.0) FSharp.Core (>= 4.7) - Fable.Core (3.2.2) - FSharp.Core (>= 4.7) + Fable.Core (3.2.3) + FSharp.Core (>= 4.7.2) Fable.Elmish (3.1) Fable.Core (>= 3.0) FSharp.Core (>= 4.6.2) @@ -109,7 +109,11 @@ NUGET FSharp.Control.Websockets (0.2.2) FSharp.Core (>= 4.3.4) Microsoft.IO.RecyclableMemoryStream (>= 1.2.2) - FSharp.Core (5.0) + FSharp.Core (4.7.2) + FSharp.Data (3.3.3) + FSharp.Core (>= 4.3.4) + FSharp.SystemTextJson (0.15.14) + FSharp.Core (>= 4.7) Fulma (2.10) Fable.Core (>= 3.0) Fable.React (>= 5.1) @@ -138,6 +142,10 @@ NUGET Google.Protobuf (3.14) System.Memory (>= 4.5.3) System.Runtime.CompilerServices.Unsafe (>= 4.5.2) + ISADotNet (0.0.2) + FSharp.Core (4.7.2) + FSharp.SystemTextJson (>= 0.15.14 < 0.16) + System.Text.Json (>= 5.0.1 < 5.1) K4os.Compression.LZ4 (1.2.6) System.Memory (>= 4.5.4) K4os.Compression.LZ4.Streams (1.2.6) @@ -191,9 +199,8 @@ NUGET Microsoft.CSharp (>= 4.5) Microsoft.IdentityModel.Logging (>= 6.8) System.Security.Cryptography.Cng (>= 4.5) - Microsoft.IO.RecyclableMemoryStream (1.3.6) + Microsoft.IO.RecyclableMemoryStream (1.4) Microsoft.NETCore.Platforms (5.0) - Microsoft.NETCore.Targets (5.0) Microsoft.Win32.SystemEvents (5.0) Microsoft.NETCore.Platforms (>= 5.0) Mono.Cecil (0.11.3) @@ -212,354 +219,49 @@ NUGET NETStandard.Library (2.0.3) Microsoft.NETCore.Platforms (>= 1.1) Newtonsoft.Json (12.0.3) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.native.System (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) Saturn (0.14.1) FSharp.Control.Websockets (>= 0.2.2) FSharp.Core (>= 4.7.2) Giraffe (>= 4.1) Microsoft.AspNetCore.Authentication.JwtBearer (>= 3.0.3) System.Threading.Tasks.Dataflow (>= 4.11.1) - SSH.NET (2016.1) - Microsoft.CSharp (>= 4.0.1) - SshNet.Security.Cryptography (1.2) - System.Diagnostics.Debug (>= 4.0.11) - System.Diagnostics.Tools (>= 4.0.1) - System.Diagnostics.TraceSource (>= 4.0) - System.Globalization (>= 4.0.11) - System.IO (>= 4.1) - System.IO.FileSystem (>= 4.0.1) - System.IO.FileSystem.Primitives (>= 4.0.1) - System.Linq (>= 4.1) - System.Net.NameResolution (>= 4.0) - System.Net.Sockets (>= 4.1) - System.Reflection.Extensions (>= 4.0.1) - System.Runtime.Extensions (>= 4.1) - System.Security.Cryptography.Algorithms (>= 4.2) - System.Text.RegularExpressions (>= 4.1) - System.Threading (>= 4.0.11) - System.Threading.Thread (>= 4.0) - System.Threading.ThreadPool (>= 4.0.10) - System.Threading.Timer (>= 4.0.1) - System.Xml.XmlDocument (>= 4.0.1) - System.Xml.XPath.XmlDocument (>= 4.0.1) - SshNet.Security.Cryptography (1.2) - System.IO (>= 4.1) - System.Security.Cryptography.Primitives (>= 4.0) + SSH.NET (2020.0) + SshNet.Security.Cryptography (1.3) + SshNet.Security.Cryptography (1.3) System.Buffers (4.5.1) - System.Collections (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Collections.Concurrent (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) System.Configuration.ConfigurationManager (5.0) System.Security.Cryptography.ProtectedData (>= 5.0) System.Security.Permissions (>= 5.0) - System.Diagnostics.Debug (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.Tools (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.TraceSource (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Diagnostics.Tracing (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) System.Drawing.Common (5.0) Microsoft.Win32.SystemEvents (>= 5.0) System.Formats.Asn1 (5.0) - System.Globalization (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) System.IdentityModel.Tokens.Jwt (6.8) Microsoft.IdentityModel.JsonWebTokens (>= 6.8) Microsoft.IdentityModel.Tokens (>= 6.8) - System.IO (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem.Primitives (4.3) - System.Runtime (>= 4.3) - System.Linq (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) System.Memory (4.5.4) - System.Net.NameResolution (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Principal.Windows (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Primitives (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (>= 4.3) - System.Net.Sockets (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Reflection (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) System.Reflection.Emit (4.7) System.Reflection.Emit.Lightweight (4.7) - System.Reflection.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Resources.ResourceManager (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) System.Runtime.CompilerServices.Unsafe (5.0) - System.Runtime.Extensions (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.Numerics (4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) System.Security.AccessControl (5.0) Microsoft.NETCore.Platforms (>= 5.0) System.Security.Principal.Windows (>= 5.0) - System.Security.Cryptography.Algorithms (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) System.Security.Cryptography.Cng (5.0) System.Formats.Asn1 (>= 5.0) - System.Security.Cryptography.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Linq (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) System.Security.Cryptography.ProtectedData (5.0) System.Security.Permissions (5.0) System.Security.AccessControl (>= 5.0) System.Windows.Extensions (>= 5.0) System.Security.Principal.Windows (5.0) - System.Text.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) System.Text.Encoding.CodePages (5.0) Microsoft.NETCore.Platforms (>= 5.0) System.Runtime.CompilerServices.Unsafe (>= 5.0) - System.Text.Encoding.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Json (5.0) - System.Text.RegularExpressions (4.3.1) - System.Runtime (>= 4.3.1) - System.Threading (4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Tasks (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) + System.Text.Encodings.Web (5.0) + System.Text.Json (5.0.1) System.Threading.Tasks.Dataflow (5.0) System.Threading.Tasks.Extensions (4.5.4) - System.Threading.Thread (4.3) - System.Runtime (>= 4.3) - System.Threading.ThreadPool (4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Threading.Timer (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) System.ValueTuple (4.5) System.Windows.Extensions (5.0) System.Drawing.Common (>= 5.0) - System.Xml.ReaderWriter (4.3.1) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Encoding.Extensions (>= 4.3) - System.Text.RegularExpressions (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Tasks.Extensions (>= 4.3) - System.Xml.XmlDocument (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Xml.ReaderWriter (>= 4.3) - System.Xml.XPath (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Xml.ReaderWriter (>= 4.3) - System.Xml.XPath.XmlDocument (4.3) - System.Collections (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Xml.ReaderWriter (>= 4.3) - System.Xml.XmlDocument (>= 4.3) - System.Xml.XPath (>= 4.3) TaskBuilder.fs (2.1) FSharp.Core (>= 4.1.17) NETStandard.Library (>= 1.6.1) @@ -570,9 +272,9 @@ NUGET Fable.Promise (>= 2.0) Fable.React (>= 5.1) FSharp.Core (>= 4.6.2) - Thoth.Json (5.0) - Fable.Core (>= 3.1.4) - FSharp.Core (>= 4.7) + Thoth.Json (5.1) + Fable.Core (>= 3.1.6) + FSharp.Core (>= 4.7.2) TypeShape (9.0) FSharp.Core (>= 4.3.2) Utf8Json (1.3.7) @@ -680,6 +382,10 @@ NUGET Fake.IO.FileSystem (5.20.3) Fake.Core.String (>= 5.20.3) FSharp.Core (>= 4.7.2) + Fake.IO.Zip (5.20.3) + Fake.Core.String (>= 5.20.3) + Fake.IO.FileSystem (>= 5.20.3) + FSharp.Core (>= 4.7.2) Fake.Net.Http (5.20.3) Fake.Core.Trace (>= 5.20.3) FSharp.Core (>= 4.7.2) @@ -691,7 +397,7 @@ NUGET Fake.Core.Trace (>= 5.20.3) Fake.IO.FileSystem (>= 5.20.3) FSharp.Core (>= 4.7.2) - Farmer (1.3) + Farmer (1.3.2) FSharp.Core (>= 4.7.1) Newtonsoft.Json (>= 12.0.2) FParsec (1.1.1) @@ -731,27 +437,27 @@ NUGET System.Security.AccessControl (>= 5.0) System.Security.Principal.Windows (>= 5.0) Mono.Posix.NETStandard (1.0) - MSBuild.StructuredLogger (2.1.215) + MSBuild.StructuredLogger (2.1.303) Microsoft.Build (>= 16.4) Microsoft.Build.Framework (>= 16.4) Microsoft.Build.Tasks.Core (>= 16.4) Microsoft.Build.Utilities.Core (>= 16.4) Newtonsoft.Json (12.0.3) - NuGet.Common (5.8) - NuGet.Frameworks (>= 5.8) - NuGet.Configuration (5.8) - NuGet.Common (>= 5.8) + NuGet.Common (5.8.1) + NuGet.Frameworks (>= 5.8.1) + NuGet.Configuration (5.8.1) + NuGet.Common (>= 5.8.1) System.Security.Cryptography.ProtectedData (>= 4.4) - NuGet.Frameworks (5.8) - NuGet.Packaging (5.8) + NuGet.Frameworks (5.8.1) + NuGet.Packaging (5.8.1) Newtonsoft.Json (>= 9.0.1) - NuGet.Configuration (>= 5.8) - NuGet.Versioning (>= 5.8) - System.Security.Cryptography.Cng (>= 5.0.0-preview.3.20214.6) - System.Security.Cryptography.Pkcs (>= 5.0.0-preview.3.20214.6) - NuGet.Protocol (5.8) - NuGet.Packaging (>= 5.8) - NuGet.Versioning (5.8) + NuGet.Configuration (>= 5.8.1) + NuGet.Versioning (>= 5.8.1) + System.Security.Cryptography.Cng (>= 5.0) + System.Security.Cryptography.Pkcs (>= 5.0) + NuGet.Protocol (5.8.1) + NuGet.Packaging (>= 5.8.1) + NuGet.Versioning (5.8.1) Octokit (0.48) System.Buffers (4.5.1) System.CodeDom (5.0) From 30a48731adfcec3355b73bee2870f10e30d415a5 Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 05:03:22 +0100 Subject: [PATCH 03/23] Add basic logic for #84 (process.json management). --- SAFEOfficeAddInn.sln => Swate.sln | 0 src/Client/Api.fs | 7 +- src/Client/Client.fs | 7 ++ src/Client/Client.fsproj | 1 + src/Client/Messages.fs | 9 +++ src/Client/Model.fs | 12 ++++ src/Client/Routing.fs | 5 ++ src/Client/Update.fs | 40 +++++++++++- src/Client/Views/BaseView.fs | 47 +++++++++----- src/Client/Views/FileUploadJsonView.fs | 85 +++++++++++++++++++++++++ src/Client/paket.references | 4 +- src/Server/Docs/DocsAnnotationAPIvs1.fs | 2 +- src/Server/Docs/DocsISADotNetAPIvs1.fs | 50 +++++++++++++++ src/Server/Server.fs | 27 +++++++- src/Server/Server.fsproj | 1 + src/Server/Version.fs | 8 +-- src/Server/paket.references | 4 +- src/Shared/Shared.fs | 7 +- src/Shared/Shared.fsproj | 6 +- src/Shared/paket.references | 1 + 20 files changed, 292 insertions(+), 31 deletions(-) rename SAFEOfficeAddInn.sln => Swate.sln (100%) create mode 100644 src/Client/Views/FileUploadJsonView.fs create mode 100644 src/Server/Docs/DocsISADotNetAPIvs1.fs create mode 100644 src/Shared/paket.references diff --git a/SAFEOfficeAddInn.sln b/Swate.sln similarity index 100% rename from SAFEOfficeAddInn.sln rename to Swate.sln diff --git a/src/Client/Api.fs b/src/Client/Api.fs index e43c021c..8335e50c 100644 --- a/src/Client/Api.fs +++ b/src/Client/Api.fs @@ -12,4 +12,9 @@ let api : IAnnotatorAPIv1 = let serviceApi : IServiceAPIv1 = Remoting.createApi() |> Remoting.withRouteBuilder Route.builder - |> Remoting.buildProxy<IServiceAPIv1> \ No newline at end of file + |> Remoting.buildProxy<IServiceAPIv1> + +let isaDotNetApi : IISADotNetAPIv1 = + Remoting.createApi() + |> Remoting.withRouteBuilder Route.builder + |> Remoting.buildProxy<IISADotNetAPIv1> \ No newline at end of file diff --git a/src/Client/Client.fs b/src/Client/Client.fs index 2ef8661a..a44247df 100644 --- a/src/Client/Client.fs +++ b/src/Client/Client.fs @@ -80,6 +80,13 @@ let view (model : Model) (dispatch : Msg -> unit) = Text.p [] [str ""] ] + | Routing.Route.FileUploadJson -> + BaseView.baseViewComponent model dispatch [ + FileUploadJsonView.fileUploadViewComponent model dispatch + ] [ + Text.p [] [str ""] + ] + | Routing.Route.ActivityLog -> BaseView.baseViewComponent model dispatch [ ActivityLogView.activityLogComponent model dispatch diff --git a/src/Client/Client.fsproj b/src/Client/Client.fsproj index b1a24fb8..10759268 100644 --- a/src/Client/Client.fsproj +++ b/src/Client/Client.fsproj @@ -40,6 +40,7 @@ <Compile Include="Views\ValidationView.fs" /> <Compile Include="Views\InfoView.fs" /> <Compile Include="Views\ActivityLogView.fs" /> + <Compile Include="Views\FileUploadJsonView.fs" /> <Compile Include="Views\SettingsView.fs" /> <Compile Include="Views\NotFoundView.fs" /> <Compile Include="Client.fs" /> diff --git a/src/Client/Messages.fs b/src/Client/Messages.fs index 80bc2f45..db527d66 100644 --- a/src/Client/Messages.fs +++ b/src/Client/Messages.fs @@ -3,6 +3,8 @@ module Messages open Elmish open Thoth.Elmish +open ISADotNet + open Shared open ExcelColors @@ -137,6 +139,12 @@ type ValidationMsg = // OfficeInterop | StoreTableRepresentationFromOfficeInterop of OfficeInterop.Types.XmlValidationTypes.TableValidation * buildingBlocks:OfficeInterop.Types.BuildingBlockTypes.BuildingBlock [] * msg:string +type FileUploadJsonMsg = + // Client + | UpdateUploadData of string + | ParseJsonToProcessRequest of string + | ParseJsonToProcessResult of Result<Process,exn> + type Msg = | Bounce of (System.TimeSpan*string*Msg) | Api of ApiMsg @@ -150,6 +158,7 @@ type Msg = | FilePicker of FilePickerMsg | AddBuildingBlock of AddBuildingBlockMsg | Validation of ValidationMsg + | FileUploadJson of FileUploadJsonMsg | UpdatePageState of Routing.Route option | Batch of seq<Msg> | DoNothing diff --git a/src/Client/Model.fs b/src/Client/Model.fs index 4d5a361c..5ed26a2b 100644 --- a/src/Client/Model.fs +++ b/src/Client/Model.fs @@ -339,6 +339,15 @@ type ValidationState = { DisplayedOptionsId = None } +type FileUploadJsonState = { + UploadData: string + ProcessModel: ISADotNet.Process option +} with + static member init () = { + UploadData = "" + ProcessModel = None + } + type Model = { //PageState @@ -370,6 +379,8 @@ type Model = { //States regarding File picker functionality FilePickerState : FilePickerState + FileUploadJsonState : FileUploadJsonState + //Insert annotation columns AddBuildingBlockState : AddBuildingBlockState @@ -392,4 +403,5 @@ let initializeModel (pageOpt: Route option) = { FilePickerState = FilePickerState .init () AddBuildingBlockState = AddBuildingBlockState .init () ValidationState = ValidationState .init () + FileUploadJsonState = FileUploadJsonState .init () } diff --git a/src/Client/Routing.fs b/src/Client/Routing.fs index 93786b05..32a85b40 100644 --- a/src/Client/Routing.fs +++ b/src/Client/Routing.fs @@ -13,6 +13,7 @@ type Route = | Validation | FilePicker | Info +| FileUploadJson | ActivityLog | Settings | NotFound @@ -24,6 +25,7 @@ type Route = | Route.TermSearch -> "/#TermSearch" | Route.Validation -> "/#Validation" | Route.FilePicker -> "/#FilePicker" + | Route.FileUploadJson -> "/#FileUploadJson" | Route.Info -> "/#Info" | Route.ActivityLog -> "/#ActivityLog" | Route.Settings -> "/#Settings" @@ -35,6 +37,7 @@ type Route = | Route.AddBuildingBlock -> "AddBuildingBlock" | Route.TermSearch -> "TermSearch" | Route.Validation -> "Validation" + | Route.FileUploadJson -> "FileUpload" | Route.Info -> "Info" | Route.FilePicker -> "FilePicker" | Route.ActivityLog -> "ActivityLog" @@ -60,6 +63,7 @@ type Route = | Route.Validation -> createElem [Fa.Solid.ClipboardCheck ] (p |> Route.toString) | Route.AddBuildingBlock -> createElem [Fa.Solid.Columns; Fa.Solid.PlusCircle ] (p |> Route.toString) | Route.FilePicker -> createElem [Fa.Solid.FileUpload ] (p |> Route.toString) + | Route.FileUploadJson -> createElem [Fa.Solid.Upload ] (p |> Route.toString) | Route.ActivityLog -> createElem [Fa.Solid.History ] (p |> Route.toString) | _ -> Fa.i [Fa.Solid.QuestionCircle] [] @@ -80,6 +84,7 @@ module Routing = map Route.Validation (s "Validation") map Route.FilePicker (s "FilePicker") map Route.Info (s "Info") + map Route.FileUploadJson (s "FileUploadJson") map Route.ActivityLog (s "ActivityLog") map Route.Settings (s "Settings") map Route.NotFound (s "NotFound") diff --git a/src/Client/Update.fs b/src/Client/Update.fs index 217f64e1..bcfd6419 100644 --- a/src/Client/Update.fs +++ b/src/Client/Update.fs @@ -9,7 +9,6 @@ open Shared open Routing open Model open Messages -open OfficeInterop open OfficeInterop.Types @@ -1156,6 +1155,34 @@ let handleValidationMsg (validationMsg:ValidationMsg) (currentState: ValidationS } nextState, Cmd.none +let handleFileUploadJsonMsg (fujMsg:FileUploadJsonMsg) (currentState: FileUploadJsonState) : FileUploadJsonState * Cmd<Msg> = + match fujMsg with + // Client + | UpdateUploadData newDataString -> + let nextState = { + currentState with + UploadData = newDataString + } + nextState, Cmd.none + | ParseJsonToProcessRequest parsableString -> + let cmd = + Cmd.OfAsync.either + Api.isaDotNetApi.parseJsonToProcess + parsableString + (Ok >> ParseJsonToProcessResult) + (Result.Error >> ParseJsonToProcessResult) + currentState, Cmd.map FileUploadJson cmd + | ParseJsonToProcessResult (Ok isaProcess) -> + let nextState = { + currentState with + ProcessModel = Some isaProcess + } + nextState, Cmd.none + | ParseJsonToProcessResult (Result.Error e) -> + let cmd = + GenericError e |> Dev |> Cmd.ofMsg + currentState, cmd + let update (msg : Msg) (currentModel : Model) : Model * Cmd<Msg> = match msg with | DoNothing -> currentModel,Cmd.none @@ -1325,4 +1352,15 @@ let update (msg : Msg) (currentModel : Model) : Model * Cmd<Msg> = currentModel with ValidationState = nextValidationState } + nextModel, nextCmd + + | FileUploadJson fileUploadJsonMsg -> + let nextFileUploadJsonState, nextCmd = + currentModel.FileUploadJsonState + |> handleFileUploadJsonMsg fileUploadJsonMsg + + let nextModel = { + currentModel with + FileUploadJsonState = nextFileUploadJsonState + } nextModel, nextCmd \ No newline at end of file diff --git a/src/Client/Views/BaseView.fs b/src/Client/Views/BaseView.fs index 2dc32b48..6d5e8a0a 100644 --- a/src/Client/Views/BaseView.fs +++ b/src/Client/Views/BaseView.fs @@ -14,7 +14,7 @@ open CustomComponents let createNavigationTab (pageLink: Routing.Route) (model:Model) (dispatch:Msg-> unit) = let isActive = (model.PageState.CurrentPage = pageLink) - Tabs.tab [Tabs.Tab.IsActive isActive;] [ + Tabs.tab [Tabs.Tab.IsActive isActive] [ a [ //Href (Routing.Route.toRouteUrl pageLink) Style [ if isActive then @@ -41,6 +41,34 @@ let createNavigationTab (pageLink: Routing.Route) (model:Model) (dispatch:Msg-> ] ] +let tabRow (model:Model) dispatch (tabs: seq<ReactElement>)= + Tabs.tabs[ + Tabs.IsCentered; Tabs.IsFullWidth; Tabs.IsBoxed + Tabs.Props [ + Style [ + BackgroundColor model.SiteStyleState.ColorMode.BodyBackground + OverflowX OverflowOptions.Hidden + ] + ] + ] [ + yield! tabs + ] + +let firstRowTabs (model:Model) dispatch = + tabRow model dispatch [ + createNavigationTab Routing.Route.AddBuildingBlock model dispatch + createNavigationTab Routing.Route.TermSearch model dispatch + createNavigationTab Routing.Route.Validation model dispatch + createNavigationTab Routing.Route.FilePicker model dispatch + createNavigationTab Routing.Route.FileUploadJson model dispatch + createNavigationTab Routing.Route.Info model dispatch + ] + +let sndRowTabs (model:Model) dispatch = + tabRow model dispatch [ + + ] + let footerContentStatic (model:Model) dispatch = div [][ str "Swate Release Version " @@ -58,21 +86,8 @@ let baseViewComponent (model: Model) (dispatch: Msg -> unit) (bodyChildren: Reac Container.IsFluid ] [ br [] - Tabs.tabs[ - Tabs.IsCentered; Tabs.IsFullWidth; Tabs.IsBoxed - Tabs.Props [ - Style [ - BackgroundColor model.SiteStyleState.ColorMode.BodyBackground - OverflowX OverflowOptions.Hidden - ] - ] - ] [ - createNavigationTab Routing.Route.AddBuildingBlock model dispatch - createNavigationTab Routing.Route.TermSearch model dispatch - createNavigationTab Routing.Route.Validation model dispatch - createNavigationTab Routing.Route.FilePicker model dispatch - createNavigationTab Routing.Route.Info model dispatch - ] + firstRowTabs model dispatch + sndRowTabs model dispatch if (not model.ExcelState.HasAnnotationTable) then CustomComponents.AnnotationTableMissingWarning.annotationTableMissingWarningComponent model dispatch diff --git a/src/Client/Views/FileUploadJsonView.fs b/src/Client/Views/FileUploadJsonView.fs new file mode 100644 index 00000000..d90a80a2 --- /dev/null +++ b/src/Client/Views/FileUploadJsonView.fs @@ -0,0 +1,85 @@ +module FileUploadJsonView + +open Fulma +open Fable +open Fable.React +open Fable.React.Props +open Fable.FontAwesome +open Fable.Core.JS +open Fable.Core.JsInterop + +open ISADotNet + +open Model +open Messages +open Browser.Types +open Fulma.Extensions.Wikiki + +let fileUploadViewComponent (model:Model) dispatch = + let uploadId = "UploadFiles_ElementId" + div [][ + Button.button [ + Button.Props [Style [MarginBottom "1rem"]] + Button.IsFullWidth + Button.Color IsInfo + Button.OnClick (fun e -> + UpdateUploadData "" |> FileUploadJson |> dispatch + ) + ][ + str "Remove Test Data" + ] + + Label.label [][ + Input.input [ + Input.Props [ + Id uploadId + Type "file"; Style [Display DisplayOptions.None] + OnChange (fun ev -> + let files : FileList = ev.target?files + + let fileNames = + [ for i=0 to (files.length - 1) do yield files.item i ] + |> List.map (fun f -> f.slice() ) + + let reader = Browser.Dom.FileReader.Create() + + reader.onload <- fun evt -> + UpdateUploadData evt.target?result |> FileUploadJson |> dispatch + + reader.onerror <- fun evt -> + GenericLog ("Error", evt.Value) |> Dev |> dispatch + + reader.readAsText(fileNames |> List.head) + + let picker = Browser.Dom.document.getElementById(uploadId) + // https://stackoverflow.com/questions/3528359/html-input-type-file-file-selection-event/3528376 + picker?value <- null + ) + ] + ] + Button.a [Button.Color Color.IsPrimary; Button.IsFullWidth][ + str "Upload" + ] + ] + + Label.label [Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Show uploaded file data."] + str ( + let dataStr = model.FileUploadJsonState.UploadData + if dataStr = "" then "no upload data found" else sprintf "%A" model.FileUploadJsonState.UploadData + ) + + div [][ + Button.button [ + Button.IsFullWidth + Button.OnClick (fun e -> ParseJsonToProcessRequest model.FileUploadJsonState.UploadData |> FileUploadJson |> dispatch) + ][ + str "Parse json" + ] + div [][ + str ( + let dataStr = model.FileUploadJsonState.ProcessModel + if dataStr.IsNone then "no upload data found" else sprintf "%A" model.FileUploadJsonState.ProcessModel.Value + ) + ] + ] + ] \ No newline at end of file diff --git a/src/Client/paket.references b/src/Client/paket.references index 552c2bcb..df483a68 100644 --- a/src/Client/paket.references +++ b/src/Client/paket.references @@ -13,4 +13,6 @@ Fulma.Extensions.Wikiki.Slider Thoth.Elmish.Debouncer Fable.Browser.MediaQueryList Fable.SimpleJson -Fable.SimpleXml \ No newline at end of file +Fable.SimpleXml +FSharp.Data +ISADotNet \ No newline at end of file diff --git a/src/Server/Docs/DocsAnnotationAPIvs1.fs b/src/Server/Docs/DocsAnnotationAPIvs1.fs index 64917594..4d5adba1 100644 --- a/src/Server/Docs/DocsAnnotationAPIvs1.fs +++ b/src/Server/Docs/DocsAnnotationAPIvs1.fs @@ -44,7 +44,7 @@ let annotatorApiDocsv1 = "The result will contain the TestParam of some sort." (Parameter.create "TestValue" ParamString "") ) - |> annotatorDocsv1.example <@ fun api -> api.getTestString (System.DateTime(2020,11,17)) @> + |> annotatorDocsv1.example <@ fun api -> api.getTestString ("I am a small tester") @> ///////////////////////////////////////////////////////////// Ontology related requests ///////////////////////////////////////////////////////////// //////// diff --git a/src/Server/Docs/DocsISADotNetAPIvs1.fs b/src/Server/Docs/DocsISADotNetAPIvs1.fs new file mode 100644 index 00000000..b5078df0 --- /dev/null +++ b/src/Server/Docs/DocsISADotNetAPIvs1.fs @@ -0,0 +1,50 @@ +module DocsISADotNetAPIvs1 + +open Shared +open Giraffe +open Saturn +open Shared +open Shared.DbDomain + +open Fable.Remoting.Server +open Fable.Remoting.Giraffe + +open DocsFunctions + +let isaDotNetDocsv1 = Docs.createFor<IISADotNetAPIv1>() + +module IsaDotNetExamples = + + let jsonstring = """{ "@id": "#process/standard_trypsin_digestion", "name": "standard_trypsin_digestion", "executesProtocol": { "@id": "#protocols/peptide_digestion", "name": "peptide_digestion", "protocolType": { "@id": "protein_digestion", "annotationValue": "Protein Digestion", "termSource": "NCIT", "termAccession": "http://purl.obolibrary.org/obo/NCIT_C70845", "comments": [] }, "description": "The isolated proteins get solubilized. Given protease is added and the solution is heated to a given temperature. After a given amount of time, the digestion is stopped by adding a denaturation agent.", "uri": "http://madeUpProtocolWebsize.org/protein_digestion", "version": "1.0.0", "parameters": [ { "@id": "protease", "parameterName": { "@id": "protease", "annotationValue": "Peptidase", "termSource": "MS", "termAccession": "http://purl.obolibrary.org/obo/NCIT_C16965", "comments": [] } }, { "@id": "temperature", "parameterName": { "@id": "temperature", "annotationValue": "temperature", "termSource": "Ontobee", "termAccession": "http://purl.obolibrary.org/obo/NCRO_0000029", "comments": [] } }, { "@id": "time", "parameterName": { "@id": "time", "annotationValue": "time", "termSource": "EFO", "termAccession": "http://www.ebi.ac.uk/efo/EFO_0000721", "comments": [] } } ], "components": [ { "componentName": "digestion_stopper", "componentType": { "@id": "formic_acid", "annotationValue": "Formic Acid", "termSource": "NCIT", "termAccession": "http://purl.obolibrary.org/obo/NCIT_C83719", "comments": [] } }, { "componentName": "heater", "componentType": { "@id": "heater", "annotationValue": "Heater Device", "termSource": "NCIT", "termAccession": "http://purl.obolibrary.org/obo/NCIT_C49986", "comments": [] } } ], "comments": [] }, "parameterValues": [ { "category": { "@id": "protease", "parameterName": { "@id": "protease", "annotationValue": "Peptidase", "termSource": "MS", "termAccession": "http://purl.obolibrary.org/obo/NCIT_C16965", "comments": [] } }, "value": { "@id": "trypsin", "annotationValue": "Trypsin/P", "termSource": "NCI", "termAccession": "http://purl.obolibrary.org/obo/MS_1001313", "comments": [] } }, { "category": { "@id": "temperature", "parameterName": { "@id": "temperature", "annotationValue": "temperature", "termSource": "Ontobee", "termAccession": "http://purl.obolibrary.org/obo/NCRO_0000029", "comments": [] } }, "value": 37, "unit": { "@id": "degree_celcius", "annotationValue": "degree Celsius", "termSource": "OM2", "termAccession": "http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius", "comments": [] } }, { "category": { "@id": "time", "parameterName": { "@id": "time", "annotationValue": "time", "termSource": "EFO", "termAccession": "http://www.ebi.ac.uk/efo/EFO_0000721", "comments": [] } }, "value": 1, "unit": { "@id": "h", "annotationValue": "hour", "termSource": "UO", "termAccession": "http://purl.obolibrary.org/obo/UO_0000032", "comments": [] } } ], "date": "2020-10-23", "performer": "TUKL", "previousProcess": { "@id": "#process/protein_extraction" }, "nextProcess": { "@id": "#process/massspec_measurement"}, "inputs": [ { "@id": "#sample/WT_protein" }, { "@id": "#sample/MUT1_protein" }, { "@id": "#sample/MUT2_protein" } ], "outputs": [ { "@id": "#sample/WT_digested" }, { "@id": "#sample/MUT1_digested" }, { "@id": "#sample/MUT2_digested" } ], "comments": [] }""" + + let uriType name desc = + Parameter.create name ParamString desc + + /// Not finished, needs to represent ISADotNet.Process + let processType = + ParamRecordType [| + Parameter.create "ID" ([|uriType "URI" ""|] |> ParamRecordType) "" + Parameter.create "Name" ParamString "" + |] + +let isaDotNetApiDocsv1 = + Remoting.documentation (sprintf "Service API v1") [ + + ///////////////////////////////////////////////////////////// Development ///////////////////////////////////////////////////////////// + //////// + isaDotNetDocsv1.route <@ fun api -> api.parseJsonToProcess @> + |> isaDotNetDocsv1.alias "Parse Json to ISADotNet Process Model (<code>parseJsonToProcess</code>)" + |> isaDotNetDocsv1.description + ( + createDocumentationDescription + "This function is used to parse a json string value to the ISA process type defined by ISADotNet." + "<code>parseJsonToProcess</code> is executed when uploading a ISA process json file." + (Some [| + Parameter.create "JsonString" (ParamString) "This is a string of a isa process json format." + |]) + "Returns the parsed complex process type. More information can be found <a href=\"https://github.com/nfdi4plants/ISADotNet\">here</a>" + (Parameter.create "Placeholder" ParamString "Json Process Type") + ) + |> isaDotNetDocsv1.example <@ fun api -> api.parseJsonToProcess IsaDotNetExamples.jsonstring @> + +] \ No newline at end of file diff --git a/src/Server/Server.fs b/src/Server/Server.fs index ace1f9f3..b12e93e0 100644 --- a/src/Server/Server.fs +++ b/src/Server/Server.fs @@ -21,7 +21,14 @@ open Microsoft.AspNetCore.Hosting //let DevLocalConnectionString = "server=127.0.0.1;user id=root;password=example; port=42333;database=SwateDB;allowuservariables=True;persistsecurityinfo=True" let serviceApi = { - getAppVersion = fun () -> async {return System.AssemblyVersionInformation.AssemblyVersion} + getAppVersion = fun () -> async { return System.AssemblyVersionInformation.AssemblyVersion } +} + +let isaDotNetApi = { + parseJsonToProcess = fun jsonString -> async { + let parsedJson = ISADotNet.Json.Process.fromString jsonString + return parsedJson + } } let annotatorApi cString = { @@ -43,7 +50,7 @@ let annotatorApi cString = { definition created user - printfn "created ontology entry: \t%A" onto + printfn "created pseudo ontology entry: \t%A. No actual db insert has happened." onto return onto } @@ -140,6 +147,17 @@ let createIServiceAPIv1 = ) |> Remoting.buildHttpHandler +let createISADotNetAPIv1 = + Remoting.createApi() + |> Remoting.withRouteBuilder Route.builder + |> Remoting.fromValue isaDotNetApi + |> Remoting.withDocs "/api/IISADotNetAPIv1/docs" DocsISADotNetAPIvs1.isaDotNetApiDocsv1 + |> Remoting.withDiagnosticsLogger(printfn "%A") + |> Remoting.withErrorHandler( + (fun x y -> Propagate (sprintf "[SERVER SIDE ERROR]: %A @ %A" x y)) + ) + |> Remoting.buildHttpHandler + let createIAnnotatorApiv1 cString = Remoting.createApi() |> Remoting.withRouteBuilder Route.builder @@ -183,6 +201,11 @@ let topLevelRouter = router { forward @"" (fun next ctx -> createIServiceAPIv1 next ctx ) + + // + forward @"" (fun next ctx -> + createISADotNetAPIv1 next ctx + ) } let app = application { diff --git a/src/Server/Server.fsproj b/src/Server/Server.fsproj index 92fa0ece..76b3d55f 100644 --- a/src/Server/Server.fsproj +++ b/src/Server/Server.fsproj @@ -11,6 +11,7 @@ <Compile Include="OntologyDB.fs" /> <Compile Include="Docs\DocsFunctions.fs" /> <Compile Include="Docs\DocsServiceAPIvs1.fs" /> + <Compile Include="Docs\DocsISADotNetAPIvs1.fs" /> <Compile Include="Docs\DocsAnnotationAPIvs1.fs" /> <Compile Include="Server.fs" /> </ItemGroup> diff --git a/src/Server/Version.fs b/src/Server/Version.fs index eeaa2983..0a57686b 100644 --- a/src/Server/Version.fs +++ b/src/Server/Version.fs @@ -3,11 +3,11 @@ namespace System open System.Reflection [<assembly: AssemblyTitleAttribute("SWATE")>] -[<assembly: AssemblyVersionAttribute("0.2.0")>] -[<assembly: AssemblyMetadataAttribute("ReleaseDate","11/01/2021")>] +[<assembly: AssemblyVersionAttribute("0.2.1")>] +[<assembly: AssemblyMetadataAttribute("ReleaseDate","22/01/2021")>] do () module internal AssemblyVersionInformation = let [<Literal>] AssemblyTitle = "SWATE" - let [<Literal>] AssemblyVersion = "0.2.0" - let [<Literal>] AssemblyMetadata_ReleaseDate = "11/01/2021" + let [<Literal>] AssemblyVersion = "0.2.1" + let [<Literal>] AssemblyMetadata_ReleaseDate = "22/01/2021" diff --git a/src/Server/paket.references b/src/Server/paket.references index 657cc0fb..92306e98 100644 --- a/src/Server/paket.references +++ b/src/Server/paket.references @@ -1,4 +1,6 @@ Saturn Fable.Remoting.Giraffe MySql.Data -Microsoft.Extensions.Configuration.UserSecrets \ No newline at end of file +Microsoft.Extensions.Configuration.UserSecrets +ISADotNet +System.Text.Encodings.Web \ No newline at end of file diff --git a/src/Shared/Shared.fs b/src/Shared/Shared.fs index 6438f869..9572c592 100644 --- a/src/Shared/Shared.fs +++ b/src/Shared/Shared.fs @@ -1,6 +1,7 @@ namespace Shared open System +open ISADotNet module URLs = @@ -134,6 +135,10 @@ type ITestAPI = { getTestNumber : unit -> Async<int> } +type IISADotNetAPIv1 = { + parseJsonToProcess : string -> Async<Process> +} + type IServiceAPIv1 = { getAppVersion : unit -> Async<string> } @@ -141,7 +146,7 @@ type IServiceAPIv1 = { type IAnnotatorAPIv1 = { // Development getTestNumber : unit -> Async<int> - getTestString : System.DateTime -> Async<string> + getTestString : string -> Async<string> // Ontology related requests /// (name,version,definition,created,user) testOntologyInsert : (string*string*string*System.DateTime*string) -> Async<DbDomain.Ontology> diff --git a/src/Shared/Shared.fsproj b/src/Shared/Shared.fsproj index f67db174..ca2b8cc3 100644 --- a/src/Shared/Shared.fsproj +++ b/src/Shared/Shared.fsproj @@ -3,9 +3,9 @@ <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> - <ItemGroup> + <None Include="paket.references" /> <Compile Include="Shared.fs" /> </ItemGroup> - -</Project> + <Import Project="..\..\.paket\Paket.Restore.targets" /> +</Project> \ No newline at end of file diff --git a/src/Shared/paket.references b/src/Shared/paket.references new file mode 100644 index 00000000..d4bb206a --- /dev/null +++ b/src/Shared/paket.references @@ -0,0 +1 @@ +ISADotNet \ No newline at end of file From 9da9c55a23d737aa05ff7c12759446ce5387902f Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 05:16:00 +0100 Subject: [PATCH 04/23] Remove event handlers (input assist, #87) --- src/Client/Messages.fs | 3 - src/Client/OfficeInterop/EventHandlers.fs | 222 +++++++++++----------- src/Client/OfficeInterop/OfficeInterop.fs | 100 +--------- src/Client/Update.fs | 25 +-- src/Client/Views/SettingsView.fs | 32 ---- 5 files changed, 113 insertions(+), 269 deletions(-) diff --git a/src/Client/Messages.fs b/src/Client/Messages.fs index db527d66..82397b6d 100644 --- a/src/Client/Messages.fs +++ b/src/Client/Messages.fs @@ -35,9 +35,6 @@ type ExcelInteropMsg = | DeleteAllCustomXml | GetSwateValidationXml // - | ToggleEventHandler - | UpdateTablesHaveAutoEditHandler - // | FillHiddenColsRequest of activeAnnotationTable:TryFindAnnoTableResult | FillHiddenColumns of tableName:string*SearchTermI [] | UpdateFillHiddenColsState of FillHiddenColsState diff --git a/src/Client/OfficeInterop/EventHandlers.fs b/src/Client/OfficeInterop/EventHandlers.fs index a4e99cf4..b089d3a5 100644 --- a/src/Client/OfficeInterop/EventHandlers.fs +++ b/src/Client/OfficeInterop/EventHandlers.fs @@ -23,114 +23,114 @@ open BuildingBlockTypes // Subscription.TestSubscription m |> dispatch // Cmd.ofSub sub -/// This module is loaded client side and is meant to work as a storage for office information. -/// This could possible be refractured into a model type design. -module EventHandlerStates = - - /// This mutable variable contains the information of which table currently has an existing eventhandler for assisted deleting from hidden columns. - /// In addition the 'OfficeExtension.EventHandlerResult<TableChangedEventArgs>' object is needed to access the specific handler again and to individually remove it. - let mutable adaptHiddenColsHandlerList: Map<string,OfficeExtension.EventHandlerResult<TableChangedEventArgs>> = Map.empty - -/// This functions works as event handler that can be added to tables and triggers on OnChanged event. -/// It is used to delete anything written in the hidden columns (referenced by '#h' in the column header tag array). -let adaptHiddenColsHandler (tableChangeArgs:TableChangedEventArgs, tableName) = - Excel.run(fun context -> - - /// get active worksheet to execute function on - let worksheet = context.workbook.worksheets.getActiveWorksheet() - /// As we found out the getItem() function does not only operate on the sheet it is executed on therefore we need the annotationTable-name of the active sheet. - /// The table name is passed by a previous function and allows us to access a specific annotation table on any worksheet in the excel workbook - let table = worksheet.tables.getItem(tableName) - - // The next part loads relevant information from the excel objects and allows us to access them after 'context.sync()' - - let tableHeader = table.getHeaderRowRange() - let _ = tableHeader.load(U2.Case2 (ResizeArray[|"values"; "columnIndex"|])) - - let tableRange = table.getRange() - let _ = tableRange.load(U2.Case2 (ResizeArray[|"values"; "rowIndex"|])) - - let changedRange = tableChangeArgs.getRange(context) - let _ = changedRange.load(U2.Case2 (ResizeArray[|"columnIndex"; "rowIndex"; "rowCount"|])) - - let r = context.runtime.load(U2.Case1 "enableEvents") - - context.sync() - .``then``(fun t -> - - /// during our function we want all eventHandlers to be deactivated to prevent any cross reactions. - r.enableEvents <- false - - // This is necessary to find the correct table index for changed cell - // As the Range in which the change occured is always referenced from the worksheet and not from the table we need to calculate the table index - // e.g. If a table starts at cell 'C5' then the table index is 0 but the worksheet index is 2.# - - /// Calculate the table column index for the changed range - let recalcChangedTableColIndex = - let tableHeaderRangeColIndex = tableHeader.columnIndex - let selectColIndex = changedRange.columnIndex - selectColIndex - tableHeaderRangeColIndex - - /// Calculate the table row index for the changed range - let recalcChangedTableRowIndex = - let tableRangedRowIndex = tableRange.rowIndex - let selectRowIndex = changedRange.rowIndex - selectRowIndex - tableRangedRowIndex - - /// Get an array of all headers. We have a lot of information in our headers, e.g. tag array - let headerVals = tableHeader.values.[0] |> Array.ofSeq - - /// find the index of the next non hidden column. We assume, that all columns in between are part of the building block that got changed. - let nextNonHiddenColForward = findIndexNextNotHiddenCol headerVals (recalcChangedTableColIndex+1.) - - //printfn "Try access fields at row: %.0f for column: %.0f - %.0f" recalcChangedTableRowIndex (recalcChangedTableColIndex+1.) (nextNonHiddenColForward-1.) - - /// This gives us the header of the column in which something was changed. - let header = tableHeader.values.[0].[int recalcChangedTableColIndex] - - /// Parse header to allow for easy access on any relevant information in form of the 'ColHeader' record type. - let parsedHeader = parseColHeader (string header.Value) - - /// This function will change the value of all cells of the same row and the same building block as the cells changed. - /// E.g. changed cells C5 to C8, which have 5 hidden columns as part of the building block. Then it will delete D6:H8. - let changeHidden () = - // We cannot work with the tableChangeArgs.details.valueAfter to see if we delete the hidden cols or adapt to user specific. - // tableChangeArgs.details.valueAfter works only on single cell changes - - /// This creates a one cell range with an empty input. We use this as insert to simulate a delete. - let input = - ResizeArray([ - ResizeArray([ - "" |> box |> Some - ]) - ]) - - /// Iterate over all rows starting from our table index of the rows changed (this will always be the index of the first row changed) - /// and ending with the same index plus the number of rows changed. - /// tl;dr iterate over all rows with a changed cell - for rowInd in recalcChangedTableRowIndex .. 1. .. (recalcChangedTableRowIndex + changedRange.rowCount - 1.) do - - /// Iterate over all columns starting from our table index of the columns changed (this will always be the index of the first col changed) + 1 - /// and ending with the index of the next non-hidden col - 1, so with the last hidden col. - /// tl;dr iterate over all hidden cols - for colInd in recalcChangedTableColIndex+1. .. 1. .. nextNonHiddenColForward-1. do - - /// for all these combinations get the cell object for these indices and insert our empty input. - /// Effectively deleting their previous value. - let c = tableRange.getCell(rowInd, colInd) - c.values <- input - - /// This is a failsafe to prevent firing the event when a reference (hidden) column is changed. - match parsedHeader.TagArr with - | Some tagArr -> - if tagArr |> Array.contains ColumnTags.HiddenTag then () else changeHidden() - | None -> - changeHidden() - - /// activate events again - r.enableEvents <- true - - /// This is not accessed and could very well be anything - t - ) - ) \ No newline at end of file +///// This module is loaded client side and is meant to work as a storage for office information. +///// This could possible be refractured into a model type design. +//module EventHandlerStates = + +// /// This mutable variable contains the information of which table currently has an existing eventhandler for assisted deleting from hidden columns. +// /// In addition the 'OfficeExtension.EventHandlerResult<TableChangedEventArgs>' object is needed to access the specific handler again and to individually remove it. +// let mutable adaptHiddenColsHandlerList: Map<string,OfficeExtension.EventHandlerResult<TableChangedEventArgs>> = Map.empty + +///// This functions works as event handler that can be added to tables and triggers on OnChanged event. +///// It is used to delete anything written in the hidden columns (referenced by '#h' in the column header tag array). +//let adaptHiddenColsHandler (tableChangeArgs:TableChangedEventArgs, tableName) = +// Excel.run(fun context -> + +// /// get active worksheet to execute function on +// let worksheet = context.workbook.worksheets.getActiveWorksheet() +// /// As we found out the getItem() function does not only operate on the sheet it is executed on therefore we need the annotationTable-name of the active sheet. +// /// The table name is passed by a previous function and allows us to access a specific annotation table on any worksheet in the excel workbook +// let table = worksheet.tables.getItem(tableName) + +// // The next part loads relevant information from the excel objects and allows us to access them after 'context.sync()' + +// let tableHeader = table.getHeaderRowRange() +// let _ = tableHeader.load(U2.Case2 (ResizeArray[|"values"; "columnIndex"|])) + +// let tableRange = table.getRange() +// let _ = tableRange.load(U2.Case2 (ResizeArray[|"values"; "rowIndex"|])) + +// let changedRange = tableChangeArgs.getRange(context) +// let _ = changedRange.load(U2.Case2 (ResizeArray[|"columnIndex"; "rowIndex"; "rowCount"|])) + +// let r = context.runtime.load(U2.Case1 "enableEvents") + +// context.sync() +// .``then``(fun t -> + +// /// during our function we want all eventHandlers to be deactivated to prevent any cross reactions. +// r.enableEvents <- false + +// // This is necessary to find the correct table index for changed cell +// // As the Range in which the change occured is always referenced from the worksheet and not from the table we need to calculate the table index +// // e.g. If a table starts at cell 'C5' then the table index is 0 but the worksheet index is 2.# + +// /// Calculate the table column index for the changed range +// let recalcChangedTableColIndex = +// let tableHeaderRangeColIndex = tableHeader.columnIndex +// let selectColIndex = changedRange.columnIndex +// selectColIndex - tableHeaderRangeColIndex + +// /// Calculate the table row index for the changed range +// let recalcChangedTableRowIndex = +// let tableRangedRowIndex = tableRange.rowIndex +// let selectRowIndex = changedRange.rowIndex +// selectRowIndex - tableRangedRowIndex + +// /// Get an array of all headers. We have a lot of information in our headers, e.g. tag array +// let headerVals = tableHeader.values.[0] |> Array.ofSeq + +// /// find the index of the next non hidden column. We assume, that all columns in between are part of the building block that got changed. +// let nextNonHiddenColForward = findIndexNextNotHiddenCol headerVals (recalcChangedTableColIndex+1.) + +// //printfn "Try access fields at row: %.0f for column: %.0f - %.0f" recalcChangedTableRowIndex (recalcChangedTableColIndex+1.) (nextNonHiddenColForward-1.) + +// /// This gives us the header of the column in which something was changed. +// let header = tableHeader.values.[0].[int recalcChangedTableColIndex] + +// /// Parse header to allow for easy access on any relevant information in form of the 'ColHeader' record type. +// let parsedHeader = parseColHeader (string header.Value) + +// /// This function will change the value of all cells of the same row and the same building block as the cells changed. +// /// E.g. changed cells C5 to C8, which have 5 hidden columns as part of the building block. Then it will delete D6:H8. +// let changeHidden () = +// // We cannot work with the tableChangeArgs.details.valueAfter to see if we delete the hidden cols or adapt to user specific. +// // tableChangeArgs.details.valueAfter works only on single cell changes + +// /// This creates a one cell range with an empty input. We use this as insert to simulate a delete. +// let input = +// ResizeArray([ +// ResizeArray([ +// "" |> box |> Some +// ]) +// ]) + +// /// Iterate over all rows starting from our table index of the rows changed (this will always be the index of the first row changed) +// /// and ending with the same index plus the number of rows changed. +// /// tl;dr iterate over all rows with a changed cell +// for rowInd in recalcChangedTableRowIndex .. 1. .. (recalcChangedTableRowIndex + changedRange.rowCount - 1.) do + +// /// Iterate over all columns starting from our table index of the columns changed (this will always be the index of the first col changed) + 1 +// /// and ending with the index of the next non-hidden col - 1, so with the last hidden col. +// /// tl;dr iterate over all hidden cols +// for colInd in recalcChangedTableColIndex+1. .. 1. .. nextNonHiddenColForward-1. do + +// /// for all these combinations get the cell object for these indices and insert our empty input. +// /// Effectively deleting their previous value. +// let c = tableRange.getCell(rowInd, colInd) +// c.values <- input + +// /// This is a failsafe to prevent firing the event when a reference (hidden) column is changed. +// match parsedHeader.TagArr with +// | Some tagArr -> +// if tagArr |> Array.contains ColumnTags.HiddenTag then () else changeHidden() +// | None -> +// changeHidden() + +// /// activate events again +// r.enableEvents <- true + +// /// This is not accessed and could very well be anything +// t +// ) +// ) \ No newline at end of file diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 3eb8a95b..4a3824e4 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -183,24 +183,10 @@ let createAnnotationTable ((allTableNames:String []),isDark:bool) = let annoTableName = allTableNames |> Array.filter (fun x -> x.StartsWith "annotationTable") - /// Should event handlers be active, then add them to the new table, otherwise don't. - /// If the storage map is empty then eventhanderls should be deactivated. - let updateEventHandler = - if EventHandlerStates.adaptHiddenColsHandlerList.IsEmpty |> not then - EventHandlerStates.adaptHiddenColsHandlerList <- - EventHandlerStates.adaptHiddenColsHandlerList.Add (newName, annotationTable.onChanged.add(fun eventArgs -> adaptHiddenColsHandler (eventArgs,newName)) ) - false - elif annoTableName |> Array.isEmpty then - EventHandlerStates.adaptHiddenColsHandlerList <- - EventHandlerStates.adaptHiddenColsHandlerList.Add (newName, annotationTable.onChanged.add(fun eventArgs -> adaptHiddenColsHandler (eventArgs,newName)) ) - true - else - false - r.enableEvents <- true /// Return info message - TryFindAnnoTableResult.Success newName, updateEventHandler, sprintf "Annotation Table created in [%s] with dimensions 2c x (%.0f + 1h)r" tableRange.address (tableRange.rowCount - 1.) + TryFindAnnoTableResult.Success newName, sprintf "Annotation Table created in [%s] with dimensions 2c x (%.0f + 1h)r" tableRange.address (tableRange.rowCount - 1.) ) //.catch (fun e -> e |> unbox<System.Exception> |> fun x -> x.Message) ) @@ -258,90 +244,6 @@ let getTableInfoForAnnoTableCreation() = ) ) -/// This function is used to either add eventHandlers to all annotationTables or to remove all eventHanderls. -let toggleAdaptHiddenColsEventHandler () = - /// Check if storage for eventHandlers is empty - let isEmpty = EventHandlerStates.adaptHiddenColsHandlerList.IsEmpty - /// If it is empty when the function is called then we want to add event handlers. - if isEmpty then - Excel.run(fun context -> - - /// This function recursevly adds eventHandlers to all elements of the 'tables' [] and stores the reference to the event handler in 'map' - let rec addEventToTable (map:Map<string,OfficeExtension.EventHandlerResult<TableChangedEventArgs>>) ind (tables: Table []) = - if ind > tables.Length-1 then - map - else - let newMap = map.Add (tables.[ind].name, tables.[ind].onChanged.add(fun eventArgs -> adaptHiddenColsHandler (eventArgs,tables.[ind].name))) - addEventToTable newMap (ind+1) tables - - // Ref. 2 - - let tableCollection = context.workbook.tables.load(propertyNames = U2.Case1 "items") - - context.sync() - .``then``(fun _ -> - - /// Get all annotationTables - let annoTables = - tableCollection.items - |> Seq.filter (fun x -> x.name.StartsWith "annotationTable") - |> Array.ofSeq - - /// Add eventHandlers to all of them ... - let newHandlers = annoTables |> addEventToTable EventHandlerStates.adaptHiddenColsHandlerList 0 - /// ... and store reference in event handler storage. - /// This is necessary as we need these objects to remove them (see 'removeHandler' below) - EventHandlerStates.adaptHiddenColsHandlerList <- newHandlers - - /// Create message - let tableMessageStr = annoTables |> Seq.map (fun x -> x.name) |> String.concat ", " - - /// Return message in array due to how removing the handlers is structured. - /// (if .. then .. else needs same output.) - [|sprintf "Event handler added to tables: %s" tableMessageStr|] - ) - ) - else - /// creates a list of "Promises", which each remove one eventHandler and the reference from the event handler storage. - let rec removeHandler ind promises (handlerArr:(string*OfficeExtension.EventHandlerResult<TableChangedEventArgs>) []) = - - if ind > handlerArr.Length-1 then - promises - else - /// get current handler from event handler storage - let (name,handler):string*OfficeExtension.EventHandlerResult<TableChangedEventArgs> = handlerArr.[ind] - - /// Give handler.context as input for 'Excel.run' and remove it from the table and the event handler storage. - let promise = - Excel.run(handler.context, fun context -> - - let _ = handler.remove() - - let newMap = EventHandlerStates.adaptHiddenColsHandlerList.Remove(name) - - EventHandlerStates.adaptHiddenColsHandlerList <- newMap - - context.sync() - .``then``(fun t -> - // As we will 'String.concat' these messages later we want the first message to give more context ... - if ind = 0 then - sprintf "Event handler removed from tables: %s" name - // ... and every other message to just contain the table name. - else - name - ) - ) - - // iterate through the whole event handler storage - removeHandler (ind+1) (promise::promises) handlerArr - - // create all promises to remove event handlers - removeHandler 0 [] (Map.toArray EventHandlerStates.adaptHiddenColsHandlerList) - // this is done to create readable output. - |> List.rev - // execute all promises - |> Promise.Parallel - /// This function is used to hide all '#h' tagged columns and to fit rows and columns to their values. /// The main goal is to improve readability of the table with this function. let autoFitTable (annotationTable) = diff --git a/src/Client/Update.fs b/src/Client/Update.fs index bcfd6419..52e612ce 100644 --- a/src/Client/Update.fs +++ b/src/Client/Update.fs @@ -105,7 +105,6 @@ let handleExcelInteropMsg (excelInteropMsg: ExcelInteropMsg) (currentState:Excel () (AnnotationTableExists >> ExcelInterop) (GenericError >> Dev) - Cmd.ofMsg (ToggleEventHandler |> ExcelInterop) Cmd.ofMsg (("Info",welcomeMsg) |> (GenericLog >> Dev)) ] @@ -186,10 +185,9 @@ let handleExcelInteropMsg (excelInteropMsg: ExcelInteropMsg) (currentState:Excel Cmd.OfPromise.either OfficeInterop.createAnnotationTable (allTableNames,isDark) - (fun (res,updateEventHandler,msg) -> + (fun (res,msg) -> Msg.Batch [ AnnotationtableCreated (res,msg) |> ExcelInterop - if updateEventHandler then UpdateTablesHaveAutoEditHandler |> ExcelInterop ] ) (GenericError >> Dev) @@ -255,27 +253,6 @@ let handleExcelInteropMsg (excelInteropMsg: ExcelInteropMsg) (currentState:Excel (GenericError >> Dev) currentState, cmd // - | ToggleEventHandler -> - let cmd = - Cmd.OfPromise.either - OfficeInterop.toggleAdaptHiddenColsEventHandler - () - (fun msg -> - let msg' = msg |> String.concat ", " - Msg.Batch [ - GenericLog ("Info",msg') |> Dev - UpdateTablesHaveAutoEditHandler |> ExcelInterop - ] - ) - (GenericError >> Dev) - currentState, cmd - | UpdateTablesHaveAutoEditHandler -> - let nextState = { - currentState with - TablesHaveAutoEditHandler = not OfficeInterop.EventHandlers.EventHandlerStates.adaptHiddenColsHandlerList.IsEmpty - } - nextState, Cmd.none - // | FillHiddenColsRequest activeTableNameRes -> let cmd name = Cmd.OfPromise.either diff --git a/src/Client/Views/SettingsView.fs b/src/Client/Views/SettingsView.fs index f74d76aa..0e1c4651 100644 --- a/src/Client/Views/SettingsView.fs +++ b/src/Client/Views/SettingsView.fs @@ -28,26 +28,6 @@ let toggleDarkModeElement (model:Model) dispatch = ] ] -let toggleAutoDeleteAssistElement (model:Model) dispatch = - Level.level [Level.Level.IsMobile][ - Level.left [Props [Style [Display DisplayOptions.Block]]] [ - str "Toggle Reference Column Input Assist" - ] - Level.right [Props [Title "Toggle Reference Column Input Assist"]][ - Button.a [ - Button.Props [Style []] - Button.OnClick (fun _ -> - ToggleEventHandler |> ExcelInterop |> dispatch - ) - ] [ - Fa.span [Fa.Solid.Edit][] - Fa.span [ - Fa.Solid.Sync - if model.ExcelState.TablesHaveAutoEditHandler then Fa.Spin][] - ] - ] - ] - let settingsViewComponent (model:Model) dispatch = div [ @@ -55,16 +35,4 @@ let settingsViewComponent (model:Model) dispatch = Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Swate Settings"] Label.label [][str "Customize Swate"] toggleDarkModeElement model dispatch - - Label.label [][ - str "Adjust Swate Settings" - Fa.i [ - Fa.Solid.QuestionCircle; - Fa.Props [ - Style [MarginLeft "3px"; Cursor "pointer"] - Title "Swate creates hidden reference columns for each building block. With this setting turned on this information will be deleted whenever the main column value changes." - ] - ][] - ] - toggleAutoDeleteAssistElement model dispatch ] \ No newline at end of file From 474cf73cb48227d58e88d239e6e9e50e8676c78a Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 05:23:19 +0100 Subject: [PATCH 05/23] Fix bug creating wrong TAN with insertTerm. --- src/Client/OfficeInterop/OfficeInterop.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 4a3824e4..1b9fe376 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -730,7 +730,7 @@ let fillValue (annotationTable,term,termBackground:Shared.DbDomain.Term option) Some ("user-specific" |> box) | 1, Some term -> //add "Term Accession Number" - let replace = Shared.URLs.TermAccessionBaseUrl + "/" + term.Accession.Replace(@":",@"_") + let replace = Shared.URLs.TermAccessionBaseUrl + term.Accession.Replace(@":",@"_") Some ( replace |> box ) | 0, Some term -> //add "Term Source REF" From 374e326f2123a2f61825f281bc4886b109d5261d Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 06:04:32 +0100 Subject: [PATCH 06/23] Add features from #68 to Update Reference Columns (Issue 87#). --- src/Client/CustomComponents/Navbar.fs | 2 +- src/Client/OfficeInterop/OfficeInterop.fs | 67 +++++++++++++---------- src/Server/Server.fs | 10 +++- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/Client/CustomComponents/Navbar.fs b/src/Client/CustomComponents/Navbar.fs index 0297bf6a..d850c9c7 100644 --- a/src/Client/CustomComponents/Navbar.fs +++ b/src/Client/CustomComponents/Navbar.fs @@ -43,7 +43,7 @@ let navbarComponent (model : Model) (dispatch : Msg -> unit) = Fa.i [Fa.Solid.SyncAlt][] ] ] - Navbar.Item.a [Navbar.Item.Props [Title "Fill Reference Columns"; Style [ Color model.SiteStyleState.ColorMode.Text]]] [ + Navbar.Item.a [Navbar.Item.Props [Title "Update Reference Columns"; Style [ Color model.SiteStyleState.ColorMode.Text]]] [ Button.a [ Button.Props [Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]] Button.OnClick (fun _ -> diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 1b9fe376..69a1dcb2 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -781,16 +781,12 @@ let createSearchTermsIFromTable (annotationTable') = // group cells by value so we don't get doubles. bBlock.MainColumn.Cells |> Array.groupBy (fun cell -> - cell.Value.IsSome, cell.Value.Value + cell.Value.Value ) - // only keep cells with value and create InsertTerm types that will be passed to the server to get filled with a term option. - |> Array.choose (fun ((isSome,searchStr),cellArr) -> - if isSome && searchStr <> "" then - let rowIndices = cellArr |> Array.map (fun cell -> cell.Index) - Shared.SearchTermI.create tsrTanColIndices searchStr rowIndices - |> Some - else - None + // create SearchTermI types that will be passed to the server to get filled with a term option. + |> Array.map (fun (searchStr,cellArr) -> + let rowIndices = cellArr |> Array.map (fun cell -> cell.Index) + Shared.SearchTermI.create tsrTanColIndices searchStr rowIndices ) /// We differentiate between building blocks with and without unit as unit building blocks will not contain terms as values but e.g. numbers. /// In this case we do not want to search the database for the cell values but the parent ontology in the header. @@ -835,7 +831,7 @@ let createSearchTermsIFromTable (annotationTable') = /// This function will be executed after the SearchTerm types from 'createSearchTermsFromTable' where send to the server to search the database for them. /// Here the results will be written into the table by the stored col and row indices. -let UpdateTableBySearchTermsI (annotationTable,insertTerms:SearchTermI []) = +let UpdateTableBySearchTermsI (annotationTable,terms:SearchTermI []) = Excel.run(fun context -> /// This will create a single cell value arr @@ -846,14 +842,12 @@ let UpdateTableBySearchTermsI (annotationTable,insertTerms:SearchTermI []) = ]) ]) - // Ref. 2 let sheet = context.workbook.worksheets.getActiveWorksheet() let annotationTable = sheet.tables.getItem(annotationTable) let annoBodyRange = annotationTable.getDataBodyRange() let _ = annoBodyRange.load(U2.Case2 (ResizeArray [|"values"|])) |> ignore - // Ref. 1 let r = context.runtime.load(U2.Case1 "enableEvents") @@ -861,30 +855,45 @@ let UpdateTableBySearchTermsI (annotationTable,insertTerms:SearchTermI []) = ``then``(fun _ -> r.enableEvents <- false /// Filter for only terms which returned a result and therefore were not custom user input. - let foundTerms = insertTerms |> Array.filter (fun x -> x.TermOpt.IsSome) + let foundTerms = terms |> Array.filter (fun x -> x.TermOpt.IsSome) /// Insert terms into related cells for all stored row-/ col-indices let insert() = - foundTerms + terms // iterate over all found terms |> Array.map ( - fun insertTerm -> - /// Term search result from database - let t = insertTerm.TermOpt.Value - /// Get ontology and accession from Term.Accession - let ont, accession = - let a = t.Accession - let splitA = a.Split":" - let accession = Shared.URLs.TermAccessionBaseUrl + a.Replace(":","_") - splitA.[0], accession + fun term -> + let t,ont,accession = + if term.TermOpt.IsSome then + /// Term search result from database + let t = term.TermOpt.Value + /// Get ontology and accession from Term.Accession + let ont, accession = + let a = t.Accession + let splitA = a.Split":" + let accession = Shared.URLs.TermAccessionBaseUrl + a.Replace(":","_") + splitA.[0], accession + t.Name,ont,accession + elif term.SearchString = "" then + let t = "" + let ont = "" + let accession = "" + t, ont, accession + elif term.TermOpt = None then + let t = term.SearchString + let ont = "user-specific" + let accession = "user-specific" + t, ont, accession + else + failwith "Swate encountered an error in (UpdateTableBySearchTermsI.insert()) trying to parse database search results to Swate table." /// Distinguish between core building blocks and unit buildingblocks. let inputVals = [| /// if the n of cols is 2 then it is a core building block. - if insertTerm.ColIndices.Length = 2 then + if term.ColIndices.Length = 2 then createCellValueInput ont createCellValueInput accession /// if the n of cols is 3 then it is a unit building block. - elif insertTerm.ColIndices.Length = 3 then - createCellValueInput t.Name + elif term.ColIndices.Length = 3 then + createCellValueInput t createCellValueInput ont createCellValueInput accession |] @@ -896,12 +905,12 @@ let UpdateTableBySearchTermsI (annotationTable,insertTerms:SearchTermI []) = /// This led to the first column to be erased for the same rows that were found to be replaced. // iterate over all columns (in this case in form of the index of their array. as we need the index to access the correct 'inputVal' value - for i in 0 .. insertTerm.ColIndices.Length-1 do + for i in 0 .. term.ColIndices.Length-1 do // iterate over all rows and insert the correct inputVal - for rowInd in insertTerm.RowIndices do + for rowInd in term.RowIndices do - let cell = annoBodyRange.getCell(float rowInd, float insertTerm.ColIndices.[i]) + let cell = annoBodyRange.getCell(float rowInd, float term.ColIndices.[i]) cell.values <- inputVals.[i] ) diff --git a/src/Server/Server.fs b/src/Server/Server.fs index b12e93e0..304a426e 100644 --- a/src/Server/Server.fs +++ b/src/Server/Server.fs @@ -129,8 +129,14 @@ let annotatorApi cString = { async { let result = queryArr |> Array.map (fun searchTerm -> - let searchRes = OntologyDB.getTermByName cString searchTerm.SearchString - {searchTerm with TermOpt = if Array.isEmpty searchRes then None else searchRes |> Array.head |> Some } + {searchTerm with + TermOpt = + // check if search string is empty. This case should delete TAN and TSR in table + if searchTerm.SearchString = "" then None + else + let searchRes = OntologyDB.getTermByName cString searchTerm.SearchString + if Array.isEmpty searchRes then None else searchRes |> Array.head |> Some + } ) return result } From 4e0d0c9e32c5be606542f9ca0f05b74be6626e1d Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 06:50:56 +0100 Subject: [PATCH 07/23] Add easy to access navigation option to advanced search (Issue #91). --- src/Client/CustomComponents/AdvancedSearch.fs | 5 ++++- src/Client/Views/AddBuildingBlockView.fs | 12 ++++++++++-- src/Client/Views/TermSearchView.fs | 5 ++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Client/CustomComponents/AdvancedSearch.fs b/src/Client/CustomComponents/AdvancedSearch.fs index 464aeca3..b41b83b2 100644 --- a/src/Client/CustomComponents/AdvancedSearch.fs +++ b/src/Client/CustomComponents/AdvancedSearch.fs @@ -115,13 +115,16 @@ let advancedTermSearchComponent (model:Model) (dispatch: Msg -> unit) = ] ] Dropdown.menu [Props[colorControl model.SiteStyleState.ColorMode];] [ - Dropdown.content [] [ + Dropdown.content [ + Props [Style [MaxHeight "180px"; OverflowY OverflowOptions.Scroll; MarginRight "-100px"; PaddingRight "100px"; Border "1px solid darkgrey"]] + ] [ // all ontologies found in database yield createOntologyDropdownItem model dispatch None yield! ( model.PersistentStorageState.SearchableOntologies |> Array.map snd |> Array.toList + |> List.sortBy (fun o -> o.Name) |> List.map (fun ont -> createOntologyDropdownItem model dispatch (Some ont)) ) ] diff --git a/src/Client/Views/AddBuildingBlockView.fs b/src/Client/Views/AddBuildingBlockView.fs index 070a3985..42a38154 100644 --- a/src/Client/Views/AddBuildingBlockView.fs +++ b/src/Client/Views/AddBuildingBlockView.fs @@ -89,10 +89,10 @@ let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) ] [ Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Annotation building block selection"] + br [] Field.div [] [ - Label.label [Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [ str "Building block"] - Help.help [] [str "Select the type of annotation building block (column) to add to the annotation table"] + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Select the type of annotation building block (column) to add to the annotation table."] Field.div [Field.HasAddons] [ Control.div [] [ Dropdown.dropdown [Dropdown.IsActive model.AddBuildingBlockState.ShowBuildingBlockSelection] [ @@ -155,9 +155,17 @@ let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = // if BuildingBlockHasUnit = false then disabled = true (model.AddBuildingBlockState.BuildingBlockHasUnit |> not) ] + + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use Advanced Search" + ] + | _ -> () + + ] + // Fill selection confirmation Field.div [] [ Control.div [] [ diff --git a/src/Client/Views/TermSearchView.fs b/src/Client/Views/TermSearchView.fs index f0e6ee95..d71a377a 100644 --- a/src/Client/Views/TermSearchView.fs +++ b/src/Client/Views/TermSearchView.fs @@ -48,6 +48,7 @@ let simpleSearchComponent (model:Model) (dispatch: Msg -> unit) = Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Ontology term search"] br [] + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Search for an ontology term to fill into the selected field(s)"] AutocompleteSearch.autocompleteTermSearchComponentOfParentOntology dispatch model.SiteStyleState.ColorMode @@ -69,6 +70,9 @@ let simpleSearchComponent (model:Model) (dispatch: Msg -> unit) = ) ] [ str "Use related term directed search." ] ] + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use Advanced Search" + ] //Control.div [] [ @@ -85,7 +89,6 @@ let simpleSearchComponent (model:Model) (dispatch: Msg -> unit) = // model.TermSearchState.Simple.HasSuggestionsLoading // (createTermSuggestions model dispatch) //] - Help.help [] [str "When applicable, search for an ontology term to fill into the selected field(s)"] ] From 1e5eb3d6c2b0f2f0527d4843c8bc0addabdb0b04 Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 07:10:45 +0100 Subject: [PATCH 08/23] Fix reset of unit search input when unchecking (Issue #92). --- src/Client/Views/AddBuildingBlockView.fs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Client/Views/AddBuildingBlockView.fs b/src/Client/Views/AddBuildingBlockView.fs index 42a38154..e6d516eb 100644 --- a/src/Client/Views/AddBuildingBlockView.fs +++ b/src/Client/Views/AddBuildingBlockView.fs @@ -5,12 +5,15 @@ open Fable.React.Props open Fulma open Fulma.Extensions.Wikiki open Fable.FontAwesome +open Fable.Core +open Fable.Core.JsInterop + open ExcelColors open Model open Messages open Shared open CustomComponents -open Fable.Core + let isValidBuildingBlock (block : AnnotationBuildingBlock) = match block.Type with @@ -132,7 +135,15 @@ let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = | Parameter | Characteristics | Factor -> Field.div [Field.HasAddons] [ Control.div [] [ - Button.a [ Button.OnClick (fun _ -> ToggleBuildingBlockHasUnit |> AddBuildingBlock |> dispatch)] [ + Button.a [ + Button.OnClick (fun _ -> + let inputId = (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState).InputId + if model.AddBuildingBlockState.BuildingBlockHasUnit = true then + let e = Browser.Dom.document.getElementById inputId + e?value <- null + ToggleBuildingBlockHasUnit |> AddBuildingBlock |> dispatch + ) + ] [ Fa.stack [Fa.Stack.Size Fa.FaSmall; Fa.Stack.Props [Style [ Color "#666666"]]][ Fa.i [Fa.Regular.Square; Fa.Stack2x][] if model.AddBuildingBlockState.BuildingBlockHasUnit then From 9158bb75696399492050109ebb0d04be59eeb9b6 Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 07:16:54 +0100 Subject: [PATCH 09/23] Update unit search to only search UO ontology (Issue #93). --- src/Client/Update.fs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Client/Update.fs b/src/Client/Update.fs index 52e612ce..ff605f11 100644 --- a/src/Client/Update.fs +++ b/src/Client/Update.fs @@ -581,6 +581,25 @@ let handleApiRequestMsg (reqMsg: ApiRequestMsg) (currentState: ApiState) : ApiSt nextState,nextCmd + let handleUnitTermSuggestionRequest (apiFunctionname:string) (responseHandler: DbDomain.Term [] -> ApiMsg) queryString = + let currentCall = { + FunctionName = apiFunctionname + Status = Pending + } + + let nextState = { + currentState with + currentCall = currentCall + } + let nextCmd = + Cmd.OfAsync.either + Api.api.getUnitTermSuggestions + (5,queryString) + (responseHandler >> Api) + (ApiError >> Api) + + nextState,nextCmd + let handleTermSuggestionByParentTermRequest (apiFunctionname:string) (responseHandler: DbDomain.Term [] -> ApiMsg) queryString parentOntology = let currentCall = { FunctionName = apiFunctionname @@ -651,7 +670,7 @@ let handleApiRequestMsg (reqMsg: ApiRequestMsg) (currentState: ApiState) : ApiSt parentOntology | GetNewUnitTermSuggestions queryString -> - handleTermSuggestionRequest + handleUnitTermSuggestionRequest "getUnitTermSuggestions" (UnitTermSuggestionResponse >> Response) queryString From b73c9c41eeab30457473da101dd09e74646157fa Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 09:04:58 +0100 Subject: [PATCH 10/23] Update subpage tabs. --- src/Client/Routing.fs | 1 + src/Client/Views/BaseView.fs | 4 ++-- src/Client/style.scss | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Client/Routing.fs b/src/Client/Routing.fs index 32a85b40..3ac96505 100644 --- a/src/Client/Routing.fs +++ b/src/Client/Routing.fs @@ -65,6 +65,7 @@ type Route = | Route.FilePicker -> createElem [Fa.Solid.FileUpload ] (p |> Route.toString) | Route.FileUploadJson -> createElem [Fa.Solid.Upload ] (p |> Route.toString) | Route.ActivityLog -> createElem [Fa.Solid.History ] (p |> Route.toString) + | Route.Info -> createElem [Fa.Solid.Question ] (p |> Route.toString) | _ -> Fa.i [Fa.Solid.QuestionCircle] [] ///explained here: https://elmish.github.io/browser/routing.html diff --git a/src/Client/Views/BaseView.fs b/src/Client/Views/BaseView.fs index 6d5e8a0a..7c9454e7 100644 --- a/src/Client/Views/BaseView.fs +++ b/src/Client/Views/BaseView.fs @@ -34,8 +34,8 @@ let createNavigationTab (pageLink: Routing.Route) (model:Model) (dispatch:Msg-> // str (pageLink |> Routing.Route.toString) //else // pageLink |> Routing.Route.toIcon - span [Class "hideUnder575px"][str (pageLink |> Routing.Route.toString)] - span [Class "hideOver575px"][pageLink |> Routing.Route.toIcon] + span [Class "hideUnder775px"][str (pageLink |> Routing.Route.toString)] + span [Class "hideOver775px"][pageLink |> Routing.Route.toIcon] ] ] diff --git a/src/Client/style.scss b/src/Client/style.scss index 0d10140d..bda085b2 100644 --- a/src/Client/style.scss +++ b/src/Client/style.scss @@ -225,4 +225,4 @@ input::-ms-clear { margin-bottom: 0.5rem; font-size: 0.8rem; } -} \ No newline at end of file +} From 99871849bc83cfa4bd4fe7760c2f43dae524d76b Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 09:35:06 +0100 Subject: [PATCH 11/23] Add sorensen dice sorting to advanced term search (Issue #95). --- src/Server/Server.fs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Server/Server.fs b/src/Server/Server.fs index 304a426e..87d4e377 100644 --- a/src/Server/Server.fs +++ b/src/Server/Server.fs @@ -102,7 +102,11 @@ let annotatorApi cString = { getTermsForAdvancedSearch = fun (ontOpt,searchName,mustContainName,searchDefinition,mustContainDefinition,keepObsolete) -> async { let result = + let searchSet = searchName + mustContainName + searchDefinition + mustContainDefinition|> Suggestion.createBigrams OntologyDB.getAdvancedTermSearchResults cString ontOpt searchName mustContainName searchDefinition mustContainDefinition keepObsolete + |> Array.sortByDescending (fun sugg -> + Suggestion.sorensenDice (Suggestion.createBigrams sugg.Name) searchSet + ) return result } From cc26e81e895d7ec7fc7abef885e5d7afb4c0a7c2 Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 09:43:43 +0100 Subject: [PATCH 12/23] Fix bug overloading computers when creating an annotation table for whole rows (Issue #63). --- src/Client/OfficeInterop/OfficeInterop.fs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 69a1dcb2..474f77ca 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -128,7 +128,7 @@ let createAnnotationTable ((allTableNames:String []),isDark:bool) = let activeTables = activeSheet.tables.load(propertyNames=U2.Case1 "items") let tableRange = context.workbook.getSelectedRange() - let _ = tableRange.load(U2.Case2 (ResizeArray(["rowIndex"; "columnIndex"; "rowCount";"address"; ]))) + let _ = tableRange.load(U2.Case2 (ResizeArray(["rowIndex"; "columnIndex"; "rowCount";"address"; "isEntireColumn"]))) let r = context.runtime.load(U2.Case1 "enableEvents") @@ -160,7 +160,9 @@ let createAnnotationTable ((allTableNames:String []),isDark:bool) = /// We do not want to create annotation tables of any size. The recommended workflow is to use the addBuildingBlock functionality. /// Therefore we recreate the tableRange but with a columncount of 2. The 2 Basic columns in any annotation table. /// "Source Name" | "Sample Name" - let adaptedRange = activeSheet.getRangeByIndexes(tableRange.rowIndex,tableRange.columnIndex,tableRange.rowCount,2.) + let adaptedRange = + let rowCount = if tableRange.isEntireColumn then 21. else tableRange.rowCount + activeSheet.getRangeByIndexes(tableRange.rowIndex,tableRange.columnIndex,rowCount,2.) /// Create table in current worksheet let annotationTable = activeSheet.tables.add(U2.Case1 adaptedRange,true) From 5c2e56a46b57fa627c5b37b7e8307ab633a4e12b Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Wed, 27 Jan 2021 13:30:57 +0100 Subject: [PATCH 13/23] Add option to add unit cols to existing building block (Issue #94). --- .../CustomComponents/AutocompleteSearch.fs | 28 ++- src/Client/Messages.fs | 13 +- src/Client/Model.fs | 32 ++- src/Client/OfficeInterop/HelperFunctions.fs | 84 ++++++- src/Client/OfficeInterop/OfficeInterop.fs | 170 +++++++------ src/Client/OfficeInterop/Regex.fs | 13 +- src/Client/OfficeInterop/Types.fs | 14 +- src/Client/Update.fs | 134 +++++++--- src/Client/Views/AddBuildingBlockView.fs | 231 ++++++++++++------ src/Server/Docs/DocsAnnotationAPIvs1.fs | 8 +- src/Server/Server.fs | 4 +- src/Shared/Shared.fs | 10 +- 12 files changed, 490 insertions(+), 251 deletions(-) diff --git a/src/Client/CustomComponents/AutocompleteSearch.fs b/src/Client/CustomComponents/AutocompleteSearch.fs index 6ce59dc0..67179958 100644 --- a/src/Client/CustomComponents/AutocompleteSearch.fs +++ b/src/Client/CustomComponents/AutocompleteSearch.fs @@ -90,11 +90,29 @@ with DropDownIsLoading = state.HasUnitTermSuggestionsLoading AdvancedSearchLinkText = "Can't find the unit you are looking for?" - OnInputChangeMsg = (SearchUnitTermTextChange >> AddBuildingBlock) - OnSuggestionSelect = (fun sugg -> (sugg.Name,sugg.Accession) |> UnitTermSuggestionUsed |> AddBuildingBlock) + OnInputChangeMsg = (fun str -> SearchUnitTermTextChange (str, Unit1) |> AddBuildingBlock) + OnSuggestionSelect = (fun sugg -> (sugg.Name, Unit1) |> UnitTermSuggestionUsed |> AddBuildingBlock) HasAdvancedSearch = true - OnAdvancedSearch = (fun sugg -> (sugg.Name,sugg.Accession) |> UnitTermSuggestionUsed |> AddBuildingBlock) + OnAdvancedSearch = (fun sugg -> (sugg.Name, Unit1) |> UnitTermSuggestionUsed |> AddBuildingBlock) + } + + static member ofAddBuildingBlockUnit2State (state:AddBuildingBlockState) : AutocompleteParameters<DbDomain.Term> = { + ModalId = "Unit2Search_ID" + InputId = "Unit2SearchInput_ID" + + StateBinding = state.Unit2TermSearchText + Suggestions = state.Unit2TermSuggestions |> Array.map AutocompleteSuggestion<DbDomain.Term>.ofTerm + MaxItems = 5 + DropDownIsVisible = state.ShowUnit2TermSuggestions + DropDownIsLoading = state.HasUnit2TermSuggestionsLoading + + AdvancedSearchLinkText = "Can't find the unit you are looking for?" + OnInputChangeMsg = (fun str -> SearchUnitTermTextChange (str,Unit2) |> AddBuildingBlock) + OnSuggestionSelect = (fun sugg -> (sugg.Name, Unit2) |> UnitTermSuggestionUsed |> AddBuildingBlock) + + HasAdvancedSearch = true + OnAdvancedSearch = (fun sugg -> (sugg.Name, Unit2) |> UnitTermSuggestionUsed |> AddBuildingBlock) } static member ofAddBuildingBlockState (state:AddBuildingBlockState) : AutocompleteParameters<DbDomain.Term> = { @@ -104,8 +122,8 @@ with StateBinding = state.CurrentBuildingBlock.Name Suggestions = state.BuildingBlockNameSuggestions |> Array.map AutocompleteSuggestion<DbDomain.Term>.ofTerm MaxItems = 5 - DropDownIsVisible = state.ShowBuildingBlockNameSuggestions - DropDownIsLoading = state.HasBuildingBlockNameSuggestionsLoading + DropDownIsVisible = state.ShowBuildingBlockTermSuggestions + DropDownIsLoading = state.HasBuildingBlockTermSuggestionsLoading OnInputChangeMsg = (BuildingBlockNameChange >> AddBuildingBlock) OnSuggestionSelect = (fun sugg -> sugg.Name |> BuildingBlockNameSuggestionUsed |> AddBuildingBlock) diff --git a/src/Client/Messages.fs b/src/Client/Messages.fs index 82397b6d..3813006c 100644 --- a/src/Client/Messages.fs +++ b/src/Client/Messages.fs @@ -21,7 +21,8 @@ type ExcelInteropMsg = | SyncContext of activeAnnotationTable:TryFindAnnoTableResult*string | InSync of string | FillSelection of activeAnnotationTable:TryFindAnnoTableResult * string * (DbDomain.Term option) - | AddColumn of activeAnnotationTable:TryFindAnnoTableResult * colname:string * format:(string*string option) option + | AddAnnotationBlock of activeAnnotationTable:TryFindAnnoTableResult * colname:string * format:string option + | AddUnitToAnnotationBlock of tryFindActiveAnnotationTable:TryFindAnnoTableResult * format:string option | FormatColumn of activeAnnotationTable:TryFindAnnoTableResult * colname:string * formatString:string * prevmsg:string /// This message does not need the active annotation table as `PipeCreateAnnotationTableInfo` checks if any annotationtables exist in the active worksheet, and if so, errors. | CreateAnnotationTable of allTableNames:string [] * isDark:bool @@ -78,7 +79,7 @@ type ApiRequestMsg = | GetNewTermSuggestions of string | GetNewTermSuggestionsByParentTerm of string*string | GetNewBuildingBlockNameSuggestions of string - | GetNewUnitTermSuggestions of string + | GetNewUnitTermSuggestions of string*relatedUnitSearch:UnitSearchRequest | GetNewAdvancedTermSearchResults of AdvancedTermSearchOptions | FetchAllOntologies /// This function is used to search for all values found in the table main columns. @@ -91,7 +92,7 @@ type ApiResponseMsg = | TermSuggestionResponse of DbDomain.Term [] | AdvancedTermSearchResultsResponse of DbDomain.Term [] | BuildingBlockNameSuggestionsResponse of DbDomain.Term [] - | UnitTermSuggestionResponse of DbDomain.Term [] + | UnitTermSuggestionResponse of DbDomain.Term [] * relatedUnitSearch:UnitSearchRequest | FetchAllOntologiesResponse of DbDomain.Ontology [] | SearchForInsertTermsResponse of tableName:string*SearchTermI [] // @@ -124,9 +125,9 @@ type AddBuildingBlockMsg = | BuildingBlockNameSuggestionUsed of string | NewBuildingBlockNameSuggestions of DbDomain.Term [] - | SearchUnitTermTextChange of string - | UnitTermSuggestionUsed of unitName:string*unitAccession:string - | NewUnitTermSuggestions of DbDomain.Term [] + | SearchUnitTermTextChange of searchString:string * relatedUnitSearch:UnitSearchRequest + | UnitTermSuggestionUsed of unitName:string * relatedUnitSearch:UnitSearchRequest + | NewUnitTermSuggestions of DbDomain.Term [] * relatedUnitSearch:UnitSearchRequest | ToggleBuildingBlockHasUnit type ValidationMsg = diff --git a/src/Client/Model.fs b/src/Client/Model.fs index 5ed26a2b..75afcaa1 100644 --- a/src/Client/Model.fs +++ b/src/Client/Model.fs @@ -297,33 +297,43 @@ type AddBuildingBlockState = { BuildingBlockNameSuggestions : DbDomain.Term [] ShowBuildingBlockSelection : bool BuildingBlockHasUnit : bool - ShowBuildingBlockNameSuggestions : bool - HasBuildingBlockNameSuggestionsLoading : bool + ShowBuildingBlockTermSuggestions : bool + HasBuildingBlockTermSuggestionsLoading : bool + /// This section is used to add a unit directly to a freshly created building block. UnitTermSearchText : string UnitTermSuggestions : DbDomain.Term [] HasUnitTermSuggestionsLoading : bool ShowUnitTermSuggestions : bool - /// This entry determines if the current UnitTermSearchText is a real term or if it is a customly typed unit. - /// If UnitTermSearchTextHasTermID.IsSome then the string is the Term.Accession else it is customely typed. - /// This is necessary to store the information about the Term.Accession for TAN in the unit columns. - UnitTermSearchTextHasTermAccession : string option + + /// This section is used to add a unit directly to an already existing building block + Unit2TermSearchText : string + Unit2TermSuggestions : DbDomain.Term [] + HasUnit2TermSuggestionsLoading : bool + ShowUnit2TermSuggestions : bool } with static member init () = { + ShowBuildingBlockSelection = false + CurrentBuildingBlock = AnnotationBuildingBlock.init NoneSelected BuildingBlockNameSuggestions = [||] - ShowBuildingBlockSelection = false + ShowBuildingBlockTermSuggestions = false + HasBuildingBlockTermSuggestionsLoading = false BuildingBlockHasUnit = false - ShowBuildingBlockNameSuggestions = false - HasBuildingBlockNameSuggestionsLoading = false + /// This section is used to add a unit directly to a freshly created building block. UnitTermSearchText = "" UnitTermSuggestions = [||] - HasUnitTermSuggestionsLoading = false ShowUnitTermSuggestions = false - UnitTermSearchTextHasTermAccession = None + HasUnitTermSuggestionsLoading = false + + /// This section is used to add a unit directly to an already existing building block + Unit2TermSearchText = "" + Unit2TermSuggestions = [||] + ShowUnit2TermSuggestions = false + HasUnit2TermSuggestionsLoading = false } /// Validation scheme for Table diff --git a/src/Client/OfficeInterop/HelperFunctions.fs b/src/Client/OfficeInterop/HelperFunctions.fs index 5c658aa9..4f587a6d 100644 --- a/src/Client/OfficeInterop/HelperFunctions.fs +++ b/src/Client/OfficeInterop/HelperFunctions.fs @@ -11,6 +11,76 @@ open OfficeInterop.Regex open OfficeInterop.Types open BuildingBlockTypes + +let createEmptyMatrixForTables (colCount:int) (rowCount:int) value = + [| + for i in 0 .. rowCount-1 do + yield [| + for i in 0 .. colCount-1 do yield U3<bool,string,float>.Case2 value + |] :> IList<U3<bool,string,float>> + |] :> IList<IList<U3<bool,string,float>>> + +/// This will create the column header attributes for a unit block. +/// as unit always has to be a term and cannot be for example "Source" or "Sample", both of which have a differen format than for exmaple "Parameter [TermName]", +/// we only need one function to generate id and attributes and bring the unit term in the right format. +let unitColAttributes (unitTermName:string) (id:int) = + match id with + | 1 -> + sprintf "[%s] (#h; #u)" unitTermName + | _ -> + sprintf "[%s] (#%i; #h; #u)" unitTermName id + +let createUnitColumns (allColHeaders:string []) (annotationTable:Table) newBaseColIndex rowCount (format:string option) = + let col = createEmptyMatrixForTables 1 rowCount "" + if format.IsSome then + let findNewIdForUnit() = + let rec loopingCheck int = + let isExisting = + allColHeaders + // Should a column with the same name already exist, then count up the id tag. + |> Array.exists (fun existingHeader -> + // We don't need to check TSR or TAN, because the main column always starts with "Unit" + existingHeader = sprintf "Unit %s" (unitColAttributes format.Value int) + ) + if isExisting then + loopingCheck (int+1) + else + int + loopingCheck 1 + + let newUnitId = findNewIdForUnit() + + /// create unit main column + let createdUnitCol1 = + annotationTable.columns.add( + index = newBaseColIndex+3., + values = U4.Case1 col, + name = sprintf "Unit %s" (unitColAttributes format.Value newUnitId) + ) + + /// create unit TSR + let createdUnitCol2 = + annotationTable.columns.add( + index = newBaseColIndex+4., + values = U4.Case1 col, + name = sprintf "Term Source REF %s" (unitColAttributes format.Value newUnitId) + ) + + /// create unit TAN + let createdUnitCol3 = + annotationTable.columns.add( + index = newBaseColIndex+5., + values = U4.Case1 col, + name = sprintf "Term Accession Number %s" (unitColAttributes format.Value newUnitId) + ) + + Some ( + sprintf " Added specified unit: %s" (format.Value), + sprintf "0.00 \"%s\"" (format.Value) + ) + else + None + /// Swaps 'Rows with column values' to 'Columns with row values'. let viewRowsByColumns (rows:ResizeArray<ResizeArray<'a>>) = rows @@ -194,11 +264,13 @@ module BuildingBlockTypes = then // There are multiple possibilities which column this is: TSR; TAN; Unit; Unit TSR; Unit TAN are the currently existing ones. // We first check if there is NO unit tag in the header tag array - if nextCol.Header.Value.TagArr.Value |> Array.exists (fun x -> x.StartsWith ColumnTags.UnitTagStart) |> not then + /// DEPRECATED! For now we keep "x.StartsWith ColumnTags.UnitTag" instead of contains, as we once (>0.2.1) added accession number behind unit tag + if nextCol.Header.Value.TagArr.Value |> Array.exists (fun x -> x.StartsWith ColumnTags.UnitTag) |> not then let updateCurrentBlock = checkForHiddenColType currentBlock nextCol sortColsIntoBuildingBlocks (index+1) updateCurrentBlock buildingBlockList /// Next we check for unit columns in the scheme of `Unit [Term] (#h; #u...) | TSR [Term] (#h; #u...) | TAN [Term] (#h; #u...)` - elif nextCol.Header.Value.TagArr.Value |> Array.exists (fun x -> x.StartsWith ColumnTags.UnitTagStart) then + /// DEPRECATED! For now we keep "x.StartsWith ColumnTags.UnitTag" instead of contains, as we once (>0.2.1) added accession number behind unit tag + elif nextCol.Header.Value.TagArr.Value |> Array.exists (fun x -> x.StartsWith ColumnTags.UnitTag) then /// Please notice that we update the unit building block in the following function and not the core building block. let updatedUnitBlock = checkForHiddenColType currentBlock.Value.Unit nextCol /// Update the core building block with the updated unit building block. @@ -295,14 +367,6 @@ let getCurrentValidationXml (customXmlParts:CustomXmlPartCollection) (context:Re return xmlParsed, currentSwateValidationXml } -let createEmptyMatrixForTables (colCount:int) (rowCount:int) value = - [| - for i in 0 .. rowCount-1 do - yield [| - for i in 0 .. colCount-1 do yield U3<bool,string,float>.Case2 value - |] :> IList<U3<bool,string,float>> - |] :> IList<IList<U3<bool,string,float>>> - let createValueMatrix (colCount:int) (rowCount:int) value = ResizeArray([ for outer in 0 .. rowCount-1 do diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 474f77ca..6038a83d 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -70,7 +70,7 @@ let exampleExcelFunction () = let customXmlParts = workbook.customXmlParts.load (propertyNames = U2.Case2 (ResizeArray[|"items"|])) promise { - return "test" + return "test1" } ) @@ -84,14 +84,7 @@ let exampleExcelFunction2 () = let customXmlParts = workbook.customXmlParts.load (propertyNames = U2.Case2 (ResizeArray[|"items"|])) promise { - - let! xmlParsed, currentSwateValidationXml = getCurrentValidationXml customXmlParts context - - let currentSwateVersion = "0.1.3" - let currentSwateValidationXml' = - if currentSwateValidationXml.IsNone then SwateValidation.init (currentSwateVersion) else currentSwateValidationXml.Value - - return sprintf "%A" currentSwateValidationXml' + return "test2" } ) @@ -373,7 +366,7 @@ let getTableRepresentation(annotationTable) = ) /// This function is used to add a new building block to the active annotationTable. -let addAnnotationBlock (annotationTable,colName:string,format:(string*(string option)) option) = +let addAnnotationBlock (annotationTable,colName:string,format:string option) = /// The following cols are currently always singles (cannot have TSR, TAN, unit cols). For easier refactoring these names are saved in OfficeInterop.Types. let isSingleCol = @@ -404,18 +397,6 @@ let addAnnotationBlock (annotationTable,colName:string,format:(string*(string op | _ -> (sprintf "[%s] (#%i; #h)" coreName id) - /// This will create the column header attributes for a unit block. - /// as unit always has to be a term and cannot be for example "Source" or "Sample", both of which have a differen format than for exmaple "Parameter [TermName]", - /// we only need one function to generate id and attributes and bring the unit term in the right format. - let unitColAttributes (unitTermInfo:string*string option) (id:int) = - let unitTermName = fst unitTermInfo - let unitAccession = if (snd unitTermInfo).IsNone then "" else (snd unitTermInfo).Value - match id with - | 1 -> - sprintf "[%s] (#h; #u%s)" unitTermName unitAccession - | _ -> - sprintf "[%s] (#%i; #h; #u%s)" unitTermName id unitAccession - Excel.run(fun context -> let sheet = context.workbook.worksheets.getActiveWorksheet() let annotationTable = sheet.tables.getItem(annotationTable) @@ -423,9 +404,8 @@ let addAnnotationBlock (annotationTable,colName:string,format:(string*(string op // Ref. 2 // This is necessary to place new columns next to selected col - let tables = annotationTable.columns.load(propertyNames = U2.Case1 "items") let annoHeaderRange = annotationTable.getHeaderRowRange() - let _ = annoHeaderRange.load(U2.Case2 (ResizeArray[|"values";"columnIndex"|])) + let _ = annoHeaderRange.load(U2.Case2 (ResizeArray[|"values";"columnIndex"; "columnCount"|])) let tableRange = annotationTable.getRange() let _ = tableRange.load(U2.Case2 (ResizeArray(["columnCount";"rowCount"]))) let range = context.workbook.getSelectedRange() @@ -446,8 +426,8 @@ let addAnnotationBlock (annotationTable,colName:string,format:(string*(string op let tableHeaderRangeColIndex = annoHeaderRange.columnIndex let selectColIndex = range.columnIndex let diff = selectColIndex - tableHeaderRangeColIndex |> int - let vals = tables.items - let maxLength = vals.Count-1 + let vals = annoHeaderRange.columnCount |> int + let maxLength = vals-1 if diff < 0 then maxLength+1 elif diff > maxLength then @@ -540,54 +520,7 @@ let addAnnotationBlock (annotationTable,colName:string,format:(string*(string op /// if format.isSome then we need to also add unit columns in the following scheme: /// Unit [UnitTermName] (#id; #h; #u) | Term Source REF [UnitTermName] (#id; #h; #u) | Term Accession Number [UnitTermName] (#id; #h; #u) let createUnitColsIfNeeded = - if format.IsSome then - let findNewIdForUnit() = - let rec loopingCheck int = - let isExisting = - allColHeaders - // Should a column with the same name already exist, then count up the id tag. - |> Array.exists (fun existingHeader -> - // We don't need to check TSR or TAN, because the main column always starts with "Unit" - existingHeader = sprintf "Unit %s" (unitColAttributes format.Value int) - ) - if isExisting then - loopingCheck (int+1) - else - int - loopingCheck 1 - - let newUnitId = findNewIdForUnit() - - /// create unit main column - let createdUnitCol1 = - annotationTable.columns.add( - index = newBaseColIndex'+3., - values = U4.Case1 col, - name = sprintf "Unit %s" (unitColAttributes format.Value newUnitId) - ) - - /// create unit TSR - let createdUnitCol2 = - annotationTable.columns.add( - index = newBaseColIndex'+4., - values = U4.Case1 col, - name = sprintf "Term Source REF %s" (unitColAttributes format.Value newUnitId) - ) - - /// create unit TAN - let createdUnitCol3 = - annotationTable.columns.add( - index = newBaseColIndex'+5., - values = U4.Case1 col, - name = sprintf "Term Accession Number %s" (unitColAttributes format.Value newUnitId) - ) - - Some ( - sprintf " Added specified unit: %s" (fst format.Value), - sprintf "0.00 \"%s\"" (fst format.Value) - ) - else - None + OfficeInterop.HelperFunctions.createUnitColumns allColHeaders annotationTable newBaseColIndex' rowCount format /// If unit block was added then return some msg information let unitColCreationMsg = if createUnitColsIfNeeded.IsSome then fst createUnitColsIfNeeded.Value else "" @@ -595,7 +528,7 @@ let addAnnotationBlock (annotationTable,colName:string,format:(string*(string op r.enableEvents <- true /// return main col names, unit column format and a message. The first two params are used in a follow up message (executing 'changeTableColumnFormat') - mainColName colName newId, unitColFormat, sprintf "%s column was added.%s" colName unitColCreationMsg + mainColName colName newId, unitColFormat, sprintf "%s column was added. %s" colName unitColCreationMsg ) ) @@ -1098,4 +1031,91 @@ let writeTableValidationToXml(tableValidation:TableValidation,currentSwateVersio newTableValidation.TableName ( newTableValidation.DateTime.ToString("yyyy-MM-dd HH:mm") ) } + ) + +/// This function is used to add unit reference columns to an existing building block without unit reference columns +let addUnitToExistingBuildingBlock (annotationTable:string,format:string option) = + Excel.run(fun context -> + + let annotationTableName = annotationTable + + let sheet = context.workbook.worksheets.getActiveWorksheet() + let annotationTable = sheet.tables.getItem(annotationTableName) + + // Ref. 2 + + // This is necessary to place new columns next to selected col + let annoHeaderRange = annotationTable.getHeaderRowRange() + let _ = annoHeaderRange.load(U2.Case2 (ResizeArray[|"values"; "columnIndex"; "columnCount"|])) + + let tableRange = annotationTable.getRange() + let _ = tableRange.load(U2.Case2 (ResizeArray(["columnCount";"rowCount"]))) + + let selectedRange = context.workbook.getSelectedRange() + let _ = selectedRange.load(U2.Case2 (ResizeArray(["values";"columnIndex"; "columnCount"]))) + + // Ref. 2 + let annoHeaderRange, annoBodyRange = BuildingBlockTypes.getBuildingBlocksPreSync context annotationTableName + + context.sync() + .``then``( fun _ -> + + if selectedRange.columnCount <> 1. then + failwith "To add a unit please select a single column" + + let newSelectedColIndex = + // recalculate the selected range index based on table + let diff = selectedRange.columnIndex - annoHeaderRange.columnIndex + // if index is smaller 0 it is outside of table range + if diff <= 0. then 0. + // if index is bigger than columnCount-1 then it is outside of tableRange + elif diff >= annoHeaderRange.columnCount-1. then annoHeaderRange.columnCount-1. + else diff + + /// Sort all columns into building blocks. + let buildingBlocks = + getBuildingBlocks annoHeaderRange annoBodyRange + + /// find building block with the closest main column index from left + let findLeftClosestBuildingBlock = + buildingBlocks + |> Array.filter (fun x -> x.MainColumn.Index <= int newSelectedColIndex) + |> Array.minBy (fun x -> Math.Abs(x.MainColumn.Index - int newSelectedColIndex)) + + if findLeftClosestBuildingBlock.TAN.IsNone || findLeftClosestBuildingBlock.TSR.IsNone then + failwith ( + sprintf + "Swate can only add a unit to columns of the type: %s, %s, %s." + OfficeInterop.Types.ColumnCoreNames.Shown.Parameter + OfficeInterop.Types.ColumnCoreNames.Shown.Characteristics + OfficeInterop.Types.ColumnCoreNames.Shown.Factor + ) + + if findLeftClosestBuildingBlock.Unit.IsSome then + failwith ( + sprintf + "Swate cannot add a unit to a building block already containing a unit: %A" + findLeftClosestBuildingBlock.Unit.Value.MainColumn.Header.Value.CoreName + ) + + // This is necessary to skip over hidden cols + /// Get an array of the headers + let headerVals = annoHeaderRange.values.[0] |> Array.ofSeq + + let allColHeaders = + headerVals + |> Array.choose id + |> Array.map string + + let unitColumnResult = + createUnitColumns allColHeaders annotationTable (float findLeftClosestBuildingBlock.MainColumn.Index) (int tableRange.rowCount) format + + let maincolName = findLeftClosestBuildingBlock.MainColumn.Header.Value.Header + + /// If unit block was added then return some msg information + let unitColCreationMsg = if unitColumnResult.IsSome then fst unitColumnResult.Value else "" + let unitColFormat = if unitColumnResult.IsSome then snd unitColumnResult.Value else "0.00" + + maincolName, unitColFormat, unitColCreationMsg + ) ) \ No newline at end of file diff --git a/src/Client/OfficeInterop/Regex.fs b/src/Client/OfficeInterop/Regex.fs index 297ed941..0530e68a 100644 --- a/src/Client/OfficeInterop/Regex.fs +++ b/src/Client/OfficeInterop/Regex.fs @@ -61,21 +61,16 @@ let parseColHeader (headerStr:string) = let coreName = parseCoreName headerStr let ontology = parseSquaredBrackets headerStr let tagArr = parseBrackets headerStr - let isUnit, accessionOpt = + let isUnit = match tagArr with - | None -> - false, None + | None -> false | Some ta -> - let checkForAccession = ta |> Array.choose parseUnitAccession - let isUnit = ta |> Array.exists (fun x -> x.StartsWith ColumnTags.UnitTagStart) - match checkForAccession.Length with - | 1 -> isUnit, checkForAccession.[0].Replace(ColumnTags.UnitTagStart,"") |> Some - | _ -> isUnit, None + let isUnit = ta |> Array.exists (fun x -> x.StartsWith ColumnTags.UnitTag) + isUnit { Header = headerStr CoreName = coreName Ontology = ontology TagArr = tagArr - HasUnitAccession = accessionOpt IsUnitCol = isUnit } \ No newline at end of file diff --git a/src/Client/OfficeInterop/Types.fs b/src/Client/OfficeInterop/Types.fs index e9359021..ede38043 100644 --- a/src/Client/OfficeInterop/Types.fs +++ b/src/Client/OfficeInterop/Types.fs @@ -84,8 +84,7 @@ module ColumnTags = let HiddenTag = "#h" [<Literal>] - /// As for now, unit tags can contain a accession number if they are existing unit terms. - let UnitTagStart = "#u" + let UnitTag = "#u" open System open Fable.SimpleXml @@ -274,12 +273,11 @@ type TryFindAnnoTableResult = Error "Could not process message. Swate was not able to identify the given annotation tables with a known case." type ColHeader = { - Header : string - CoreName: string option - Ontology: string option - TagArr: string [] option - HasUnitAccession : string option - IsUnitCol: bool + Header: string + CoreName: string option + Ontology: string option + TagArr: string [] option + IsUnitCol: bool } /// This module contains types to handle value search for TSR and TAN columns. diff --git a/src/Client/Update.fs b/src/Client/Update.fs index ff605f11..9af60bcf 100644 --- a/src/Client/Update.fs +++ b/src/Client/Update.fs @@ -154,10 +154,9 @@ let handleExcelInteropMsg (excelInteropMsg: ExcelInteropMsg) (currentState:Excel let cmd = matchActiveTableResToMsg activeTableNameRes cmd currentState, cmd - | AddColumn (activeTableNameRes,colName,format) -> + | AddAnnotationBlock (activeTableNameRes,colName,format) -> let cmd name= Cmd.OfPromise.either - //OfficeInterop.addAnnotationColumn OfficeInterop.addAnnotationBlock (name,colName,format) (fun (newColName,format,msg) -> @@ -167,6 +166,18 @@ let handleExcelInteropMsg (excelInteropMsg: ExcelInteropMsg) (currentState:Excel let cmd = matchActiveTableResToMsg activeTableNameRes cmd currentState, cmd + | AddUnitToAnnotationBlock (activeTableNameRes, format) -> + let cmd name = + Cmd.OfPromise.either + OfficeInterop.addUnitToExistingBuildingBlock + (name,format) + (fun (newColName,format,msg) -> + FormatColumn (activeTableNameRes, newColName, format, msg) |> ExcelInterop + ) + (GenericError >> Dev) + let cmd = matchActiveTableResToMsg activeTableNameRes cmd + currentState, cmd + | FormatColumn (activeTableNameRes,colName,format,msg) -> let cmd name = Cmd.batch [ @@ -581,7 +592,7 @@ let handleApiRequestMsg (reqMsg: ApiRequestMsg) (currentState: ApiState) : ApiSt nextState,nextCmd - let handleUnitTermSuggestionRequest (apiFunctionname:string) (responseHandler: DbDomain.Term [] -> ApiMsg) queryString = + let handleUnitTermSuggestionRequest (apiFunctionname:string) (responseHandler: (DbDomain.Term [] * UnitSearchRequest) -> ApiMsg) queryString (relUnit:UnitSearchRequest) = let currentCall = { FunctionName = apiFunctionname Status = Pending @@ -594,7 +605,7 @@ let handleApiRequestMsg (reqMsg: ApiRequestMsg) (currentState: ApiState) : ApiSt let nextCmd = Cmd.OfAsync.either Api.api.getUnitTermSuggestions - (5,queryString) + (5,queryString,relUnit) (responseHandler >> Api) (ApiError >> Api) @@ -669,11 +680,12 @@ let handleApiRequestMsg (reqMsg: ApiRequestMsg) (currentState: ApiState) : ApiSt queryString parentOntology - | GetNewUnitTermSuggestions queryString -> + | GetNewUnitTermSuggestions (queryString,relUnit) -> handleUnitTermSuggestionRequest "getUnitTermSuggestions" (UnitTermSuggestionResponse >> Response) queryString + relUnit | GetNewBuildingBlockNameSuggestions queryString -> handleTermSuggestionRequest @@ -783,6 +795,25 @@ let handleApiResponseMsg (resMsg: ApiResponseMsg) (currentState: ApiState) : Api nextState, cmds + let handleUnitTermSuggestionResponse (responseHandler: DbDomain.Term [] * UnitSearchRequest -> Msg) (suggestions: DbDomain.Term[]) (relatedUnitSearch:UnitSearchRequest) = + let finishedCall = { + currentState.currentCall with + Status = Successfull + } + + let nextState = { + currentState with + currentCall = noCall + callHistory = finishedCall::currentState.callHistory + } + + let cmds = Cmd.batch [ + ("Debug",sprintf "[ApiSuccess]: Call %s successfull." finishedCall.FunctionName) |> ApiSuccess |> Api |> Cmd.ofMsg + (suggestions,relatedUnitSearch) |> responseHandler |> Cmd.ofMsg + ] + + nextState, cmds + match resMsg with | TermSuggestionResponse suggestions -> //let finishedCall = { @@ -806,11 +837,13 @@ let handleApiResponseMsg (resMsg: ApiResponseMsg) (currentState: ApiState) : Api (NewSuggestions >> TermSearch) suggestions - | UnitTermSuggestionResponse suggestions -> + | UnitTermSuggestionResponse (suggestions,relUnit) -> - handleTermSuggestionResponse + handleUnitTermSuggestionResponse (NewUnitTermSuggestions >> AddBuildingBlock) suggestions + relUnit + | BuildingBlockNameSuggestionsResponse suggestions -> @@ -996,7 +1029,7 @@ let handleAddBuildingBlockMsg (addBuildingBlockMsg:AddBuildingBlockMsg) (current nextState,Cmd.none - | SearchUnitTermTextChange newTerm -> + | SearchUnitTermTextChange (newTerm,relUnit) -> let triggerNewSearch = newTerm.Length > 2 @@ -1006,42 +1039,65 @@ let handleAddBuildingBlockMsg (addBuildingBlockMsg:AddBuildingBlockMsg) (current "GetNewUnitTermSuggestions", ( if triggerNewSearch then - newTerm |> (GetNewUnitTermSuggestions >> Request >> Api) + (newTerm,relUnit) |> (GetNewUnitTermSuggestions >> Request >> Api) else DoNothing ) - let nextState = { - currentState with - UnitTermSearchText = newTerm - ShowUnitTermSuggestions = triggerNewSearch - HasUnitTermSuggestionsLoading = true - UnitTermSearchTextHasTermAccession = None - } + let nextState = + match relUnit with + | Unit1 -> + { currentState with + UnitTermSearchText = newTerm + ShowUnitTermSuggestions = triggerNewSearch + HasUnitTermSuggestionsLoading = true + } + | Unit2 -> + { currentState with + Unit2TermSearchText = newTerm + ShowUnit2TermSuggestions = triggerNewSearch + HasUnit2TermSuggestionsLoading = true + } nextState, ((delay, bounceId, msgToBounce) |> Bounce |> Cmd.ofMsg) - | NewUnitTermSuggestions suggestions -> - - let nextState = { - currentState with - UnitTermSuggestions = suggestions - ShowUnitTermSuggestions = true - HasUnitTermSuggestionsLoading = false - } + | NewUnitTermSuggestions (suggestions,relUnit) -> + + let nextState = + match relUnit with + | Unit1 -> + { currentState with + UnitTermSuggestions = suggestions + ShowUnitTermSuggestions = true + HasUnitTermSuggestionsLoading = false + } + | Unit2 -> + { currentState with + Unit2TermSuggestions = suggestions + ShowUnit2TermSuggestions = true + HasUnit2TermSuggestionsLoading = false + } nextState,Cmd.none - | UnitTermSuggestionUsed (suggestionName,suggestionAccession) -> + | UnitTermSuggestionUsed (suggestionName, relUnit) -> - let nextState = { - currentState with - UnitTermSearchText = suggestionName - //UnitTerm = Some suggestion - ShowUnitTermSuggestions = false - HasUnitTermSuggestionsLoading = false - UnitTermSearchTextHasTermAccession = Some suggestionAccession - } + let nextState = + match relUnit with + | Unit1 -> + { currentState with + UnitTermSearchText = suggestionName + //UnitTerm = Some suggestion + ShowUnitTermSuggestions = false + HasUnitTermSuggestionsLoading = false + } + | Unit2 -> + { currentState with + Unit2TermSearchText = suggestionName + //UnitTerm = Some suggestion + ShowUnit2TermSuggestions = false + HasUnit2TermSuggestionsLoading = false + } nextState, Cmd.none | BuildingBlockNameChange newName -> @@ -1067,8 +1123,8 @@ let handleAddBuildingBlockMsg (addBuildingBlockMsg:AddBuildingBlockMsg) (current let nextState = { currentState with CurrentBuildingBlock = nextBB - ShowBuildingBlockNameSuggestions = triggerNewSearch - HasBuildingBlockNameSuggestionsLoading = true + ShowBuildingBlockTermSuggestions = triggerNewSearch + HasBuildingBlockTermSuggestionsLoading = true } nextState, ((delay, bounceId, msgToBounce) |> Bounce |> Cmd.ofMsg) @@ -1078,8 +1134,8 @@ let handleAddBuildingBlockMsg (addBuildingBlockMsg:AddBuildingBlockMsg) (current let nextState = { currentState with BuildingBlockNameSuggestions = suggestions - ShowBuildingBlockNameSuggestions = true - HasBuildingBlockNameSuggestionsLoading = false + ShowBuildingBlockTermSuggestions = true + HasBuildingBlockTermSuggestionsLoading = false } nextState,Cmd.none @@ -1094,8 +1150,8 @@ let handleAddBuildingBlockMsg (addBuildingBlockMsg:AddBuildingBlockMsg) (current let nextState = { currentState with CurrentBuildingBlock = nextBB - ShowBuildingBlockNameSuggestions = false - HasBuildingBlockNameSuggestionsLoading = false + ShowBuildingBlockTermSuggestions = false + HasBuildingBlockTermSuggestionsLoading = false } nextState, Cmd.none diff --git a/src/Client/Views/AddBuildingBlockView.fs b/src/Client/Views/AddBuildingBlockView.fs index e6d516eb..721a4f2f 100644 --- a/src/Client/Views/AddBuildingBlockView.fs +++ b/src/Client/Views/AddBuildingBlockView.fs @@ -85,97 +85,136 @@ let addBuildingBlockFooterComponent (model:Model) (dispatch:Msg -> unit) = ] ] -let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = - form [ - OnSubmit (fun e -> e.preventDefault()) - // https://keycode.info/ - OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) - ] [ - Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Annotation building block selection"] - br [] - - Field.div [] [ - Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Select the type of annotation building block (column) to add to the annotation table."] - Field.div [Field.HasAddons] [ - Control.div [] [ - Dropdown.dropdown [Dropdown.IsActive model.AddBuildingBlockState.ShowBuildingBlockSelection] [ - Dropdown.trigger [] [ - Button.button [Button.OnClick (fun _ -> ToggleSelectionDropdown |> AddBuildingBlock |> dispatch)] [ - span [] [model.AddBuildingBlockState.CurrentBuildingBlock.Type |> AnnotationBuildingBlockType.toString |> str] - Fa.i [Fa.Solid.AngleDown] [] - ] - ] - Dropdown.menu [Props[colorControl model.SiteStyleState.ColorMode]] [ - Dropdown.content [] ([ - Parameter - Factor - Characteristics - Sample - Data - Source - ] |> List.map (createBuildingBlockDropdownItem model dispatch)) +let addBuildingBlockElements (model:Model) (dispatch:Msg -> unit) = + [ + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Select the type of annotation building block (column) to add to the annotation table."] + Field.div [Field.HasAddons] [ + Control.div [] [ + Dropdown.dropdown [Dropdown.IsActive model.AddBuildingBlockState.ShowBuildingBlockSelection] [ + Dropdown.trigger [] [ + Button.button [Button.OnClick (fun _ -> ToggleSelectionDropdown |> AddBuildingBlock |> dispatch)] [ + span [] [model.AddBuildingBlockState.CurrentBuildingBlock.Type |> AnnotationBuildingBlockType.toString |> str] + Fa.i [Fa.Solid.AngleDown] [] ] ] - ] - Control.div [Control.IsExpanded] [ - match model.AddBuildingBlockState.CurrentBuildingBlock.Type with - | Parameter | Characteristics | Factor -> - AutocompleteSearch.autocompleteTermSearchComponent - dispatch - model.SiteStyleState.ColorMode - model - "Start typing to search" - None - (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState) - false - | _ -> () - ] - ] - match model.AddBuildingBlockState.CurrentBuildingBlock.Type with - | Parameter | Characteristics | Factor -> - Field.div [Field.HasAddons] [ - Control.div [] [ - Button.a [ - Button.OnClick (fun _ -> - let inputId = (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState).InputId - if model.AddBuildingBlockState.BuildingBlockHasUnit = true then - let e = Browser.Dom.document.getElementById inputId - e?value <- null - ToggleBuildingBlockHasUnit |> AddBuildingBlock |> dispatch - ) - ] [ - Fa.stack [Fa.Stack.Size Fa.FaSmall; Fa.Stack.Props [Style [ Color "#666666"]]][ - Fa.i [Fa.Regular.Square; Fa.Stack2x][] - if model.AddBuildingBlockState.BuildingBlockHasUnit then - Fa.i [Fa.Solid.Check; Fa.Stack1x][] + Dropdown.menu [Props[colorControl model.SiteStyleState.ColorMode]] [ + Dropdown.content [] ([ + Parameter + Factor + Characteristics + Sample + Data + Source + ] |> List.map (createBuildingBlockDropdownItem model dispatch) + |> fun x -> + List.append x [ + Dropdown.Item.div [ + Dropdown.Item.Modifiers [Modifier.TextAlignment (Screen.All,TextAlignment.Right)] + Dropdown.Item.Props [ Href "https://nfdi4plants.github.io/AnnotationPrinciples/"; Target "_Blank" ] + ][ + a [][ + str "more" + ] + ] ] - ] - ] - Control.p [] [ - Button.button [Button.IsStatic true] [ - str (sprintf "This %s has a unit:" (model.AddBuildingBlockState.CurrentBuildingBlock.Type |> AnnotationBuildingBlockType.toString )) - ] + + ) ] + ] + ] + Control.div [Control.IsExpanded] [ + match model.AddBuildingBlockState.CurrentBuildingBlock.Type with + | Parameter | Characteristics | Factor -> AutocompleteSearch.autocompleteTermSearchComponent dispatch model.SiteStyleState.ColorMode model "Start typing to search" None - (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState) - // if BuildingBlockHasUnit = false then disabled = true - (model.AddBuildingBlockState.BuildingBlockHasUnit |> not) + (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState) + false + | _ -> () + ] + ] + match model.AddBuildingBlockState.CurrentBuildingBlock.Type with + | Parameter | Characteristics | Factor -> + Field.div [Field.HasAddons] [ + Control.div [] [ + Button.a [ + Button.OnClick (fun _ -> + let inputId = (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState).InputId + if model.AddBuildingBlockState.BuildingBlockHasUnit = true then + let e = Browser.Dom.document.getElementById inputId + e?value <- null + ToggleBuildingBlockHasUnit |> AddBuildingBlock |> dispatch + ) + ] [ + Fa.stack [Fa.Stack.Size Fa.FaSmall; Fa.Stack.Props [Style [ Color "#666666"]]][ + Fa.i [Fa.Regular.Square; Fa.Stack2x][] + if model.AddBuildingBlockState.BuildingBlockHasUnit then + Fa.i [Fa.Solid.Check; Fa.Stack1x][] + ] + ] ] - - a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ - str "Use Advanced Search" + Control.p [] [ + Button.button [Button.IsStatic true] [ + str (sprintf "This %s has a unit:" (model.AddBuildingBlockState.CurrentBuildingBlock.Type |> AnnotationBuildingBlockType.toString )) + ] ] + AutocompleteSearch.autocompleteTermSearchComponent + dispatch + model.SiteStyleState.ColorMode + model + "Start typing to search" + None + (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState) + // if BuildingBlockHasUnit = false then disabled = true + (model.AddBuildingBlockState.BuildingBlockHasUnit |> not) + ] + + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use Advanced Search" + ] - | _ -> () + | _ -> () + ] + +let addUnitToExistingBlockElements (model:Model) (dispatch:Msg -> unit) = + [ + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Add unit reference columns to existing building block."] + Field.div [Field.HasAddons] [ + Control.p [] [ + Button.button [Button.IsStatic true] [ + str ("Add unit") + ] + ] + AutocompleteSearch.autocompleteTermSearchComponent + dispatch + model.SiteStyleState.ColorMode + model + "Start typing to search" + None + (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnit2State model.AddBuildingBlockState) + // if BuildingBlockHasUnit = false then disabled = true + false + ] - + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnit2State model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use Advanced Search" ] + ] + +let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = + form [ + OnSubmit (fun e -> e.preventDefault()) + // https://keycode.info/ + OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) + ] [ + Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Annotation building block selection"] + br [] + // Input forms, etc related to add building block. Except submit button + yield! addBuildingBlockElements model dispatch // Fill selection confirmation Field.div [] [ @@ -191,18 +230,48 @@ let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = Button.IsFullWidth Button.OnClick ( let format = - match model.AddBuildingBlockState.BuildingBlockHasUnit, model.AddBuildingBlockState.UnitTermSearchText, model.AddBuildingBlockState.UnitTermSearchTextHasTermAccession with - | _,"", _ -> None //"0.00" - | false, _, _ -> None//"0.00" - | true, str, Some accession -> Some (str,Some accession) - | true, str, None -> Some (str,None) + match model.AddBuildingBlockState.BuildingBlockHasUnit, model.AddBuildingBlockState.UnitTermSearchText with + | _,"" -> None //"0.00" + | false, _ -> None//"0.00" + | true, str -> Some str //sprintf "0.00 \"%s\"" str let colName = model.AddBuildingBlockState.CurrentBuildingBlock |> AnnotationBuildingBlock.toAnnotationTableHeader - fun _ -> (colName,format) |> pipeNameTuple2 AddColumn |> ExcelInterop |> dispatch + fun _ -> (colName,format) |> pipeNameTuple2 AddAnnotationBlock |> ExcelInterop |> dispatch ) ] [ str "Insert this annotation building block" ] ] ] + + hr [] + + // Input forms, etc related to add unit to existing building block. Except submit button + + yield! addUnitToExistingBlockElements model dispatch + + Field.div [] [ + Control.div [] [ + Button.button [ + let isValid = model.AddBuildingBlockState.Unit2TermSearchText <> "" + if isValid then + Button.CustomClass "is-success" + Button.IsActive true + else + Button.CustomClass "is-danger" + Button.Props [Disabled true] + Button.IsFullWidth + Button.OnClick (fun e -> + match model.AddBuildingBlockState.Unit2TermSearchText with + | "" -> + GenericLog ("Error", "Cannot execute function with empty unit input") |> Dev |> dispatch + | str -> + pipeNameTuple AddUnitToAnnotationBlock (Some str) |> ExcelInterop |> dispatch + ) + ] [ + str "Add unit to existing building block" + ] + ] + ] + ] \ No newline at end of file diff --git a/src/Server/Docs/DocsAnnotationAPIvs1.fs b/src/Server/Docs/DocsAnnotationAPIvs1.fs index 4d5adba1..e60becbc 100644 --- a/src/Server/Docs/DocsAnnotationAPIvs1.fs +++ b/src/Server/Docs/DocsAnnotationAPIvs1.fs @@ -157,16 +157,18 @@ let annotatorApiDocsv1 = |> ParamArray createDocumentationDescription "This is a <code>getTermSuggestions</code> variant used specifically to find unit ontology terms." - "<code>getUnitTermSuggestions</code> is used to find a unit restriction during AddBuildingBlock." + "<code>getUnitTermSuggestions</code> is used to find a unit restriction during AddBuildingBlock and to add a unit to an already existing building block. + 'f# Union type' parameter is only passed to server to later determine the origin search request in client. This value will pass through server unused." (Some [| Parameter.create "n" ParamInteger "This parameter sets the number of returned results." Parameter.create "queryString" ParamString "This parameter is used to search the Term.Name Column for hits." + Parameter.create "f# Union type" ParamString "This parameter is used to define the position at which is search for a unit term." |]) "This function returns an array of matching Database.Term entries in the form of <code>DbDomain.Term []</code>. The matching results are restricted to Term.FK_OntologyID = 1 (Unit Ontology)." (Parameter.create "Term []" dbDomainTermArr "Array of database Term entries.") ) - |> annotatorDocsv1.example <@ fun api -> api.getUnitTermSuggestions (5,"light") @> - |> annotatorDocsv1.example <@ fun api -> api.getUnitTermSuggestions (5,"temp") @> + |> annotatorDocsv1.example <@ fun api -> api.getUnitTermSuggestions (5,"light", Unit1) @> + |> annotatorDocsv1.example <@ fun api -> api.getUnitTermSuggestions (5,"temp", Unit1) @> annotatorDocsv1.route <@ fun api -> api.getTermsByNames @> |> annotatorDocsv1.alias "Get Unit Terms (<code>getTermsByNames</code>)" diff --git a/src/Server/Server.fs b/src/Server/Server.fs index 87d4e377..ce53acb8 100644 --- a/src/Server/Server.fs +++ b/src/Server/Server.fs @@ -110,7 +110,7 @@ let annotatorApi cString = { return result } - getUnitTermSuggestions = fun (max:int,typedSoFar:string) -> + getUnitTermSuggestions = fun (max:int,typedSoFar:string, unit:UnitSearchRequest) -> async { let searchRes = match typedSoFar with @@ -126,7 +126,7 @@ let annotatorApi cString = { |> fun x -> x |> Array.take (if x.Length > max then max else x.Length) - return searchRes + return (searchRes, unit) } getTermsByNames = fun (queryArr) -> diff --git a/src/Shared/Shared.fs b/src/Shared/Shared.fs index 9572c592..91b6df86 100644 --- a/src/Shared/Shared.fs +++ b/src/Shared/Shared.fs @@ -130,6 +130,11 @@ type SearchTermI = { TermOpt = None } +/// This type is used to define target for unit term search. +type UnitSearchRequest = +| Unit1 +| Unit2 + type ITestAPI = { // Development getTestNumber : unit -> Async<int> @@ -143,6 +148,7 @@ type IServiceAPIv1 = { getAppVersion : unit -> Async<string> } + type IAnnotatorAPIv1 = { // Development getTestNumber : unit -> Async<int> @@ -159,9 +165,9 @@ type IAnnotatorAPIv1 = { /// (ontOpt,searchName,mustContainName,searchDefinition,mustContainDefinition,keepObsolete) getTermsForAdvancedSearch : (DbDomain.Ontology option*string*string*string*string*bool) -> Async<DbDomain.Term []> - getUnitTermSuggestions : (int*string) -> Async<DbDomain.Term []> + getUnitTermSuggestions : (int*string*UnitSearchRequest) -> Async<DbDomain.Term [] * UnitSearchRequest> - getTermsByNames : SearchTermI [] -> Async<SearchTermI []> + getTermsByNames : SearchTermI [] -> Async<SearchTermI []> } \ No newline at end of file From 05163533c6832023301e588ccc59b34af5b18f88 Mon Sep 17 00:00:00 2001 From: Kevin F <Freymaurer@gmx.de> Date: Tue, 2 Feb 2021 15:52:58 +0100 Subject: [PATCH 14/23] Add Logos and visually update Swate (Issue #59). --- .assets/assets/manifest.xml | 22 +- RELEASE_NOTES.md | 16 +- Swate.sln | 5 - build.fsx | 3 +- build.fsx.lock | 438 ------------------ manifest.xml | 22 +- paket.dependencies | 3 +- paket.lock | 14 +- src/Client/Client.fs | 16 +- src/Client/Client.fsproj | 1 + .../AnnotationTableMissingWarning.fs | 8 +- .../CustomComponents/AutocompleteSearch.fs | 8 +- src/Client/CustomComponents/ErrorModal.fs | 2 +- src/Client/CustomComponents/Navbar.fs | 41 +- src/Client/Messages.fs | 7 + src/Client/Model.fs | 8 +- src/Client/NFDIColors.fs | 218 +++++++++ src/Client/OfficeInterop/OfficeInterop.fs | 30 +- src/Client/OfficeInterop/Types.fs | 18 +- src/Client/Routing.fs | 34 +- src/Client/Update.fs | 38 +- src/Client/Views/ActivityLogView.fs | 2 +- src/Client/Views/AddBuildingBlockView.fs | 153 +++--- src/Client/Views/BaseView.fs | 42 +- src/Client/Views/FilePickerView.fs | 192 +++++--- src/Client/Views/InfoView.fs | 85 ++-- src/Client/Views/SettingsView.fs | 6 +- src/Client/Views/TermSearchView.fs | 138 +++--- src/Client/Views/ValidationView.fs | 208 ++++++--- src/Client/index.html | 7 +- src/Client/paket.references | 3 +- src/Client/public/assets/BioFSharpCore.svg | 163 ------- src/Client/public/assets/CSB_Logo.png | Bin 64068 -> 0 bytes .../public/assets/Swate_logo_for_excel.svg | 36 ++ src/Client/public/assets/icon-16.png | Bin 572 -> 0 bytes src/Client/public/assets/icon-20.png | Bin 579 -> 0 bytes src/Client/public/assets/icon-24.png | Bin 1166 -> 0 bytes src/Client/public/assets/icon-32.png | Bin 1435 -> 0 bytes src/Client/public/assets/icon-40.png | Bin 1814 -> 0 bytes src/Client/public/assets/icon-48.png | Bin 2021 -> 0 bytes src/Client/public/assets/icon-64.png | Bin 2528 -> 0 bytes src/Client/public/assets/icon-80.png | Bin 3017 -> 0 bytes src/Client/public/assets/icon-96.png | Bin 3592 -> 0 bytes src/Client/public/assets/logo-filled.png | Bin 11915 -> 0 bytes src/Client/public/assets/swate_16x16.png | Bin 0 -> 1079 bytes src/Client/public/assets/swate_20x20.png | Bin 0 -> 1243 bytes src/Client/public/assets/swate_24x24.png | Bin 0 -> 1294 bytes src/Client/public/assets/swate_32x32.png | Bin 0 -> 1653 bytes src/Client/public/assets/swate_40x40.png | Bin 0 -> 2025 bytes src/Client/public/assets/swate_48x48.png | Bin 0 -> 2594 bytes src/Client/public/assets/swate_64x64.png | Bin 0 -> 2692 bytes src/Client/public/assets/swate_80x80.png | Bin 0 -> 3463 bytes src/Client/public/assets/swate_96x96.png | Bin 0 -> 3336 bytes src/Client/style.scss | 72 ++- src/Server/Server.fs | 11 +- src/Server/Version.fs | 4 +- src/Shared/Shared.fs | 11 +- tests/manifest.xml | 126 ----- tests/manifest_old.xml | 126 ----- 59 files changed, 1084 insertions(+), 1253 deletions(-) delete mode 100644 build.fsx.lock create mode 100644 src/Client/NFDIColors.fs delete mode 100644 src/Client/public/assets/BioFSharpCore.svg delete mode 100644 src/Client/public/assets/CSB_Logo.png create mode 100644 src/Client/public/assets/Swate_logo_for_excel.svg delete mode 100644 src/Client/public/assets/icon-16.png delete mode 100644 src/Client/public/assets/icon-20.png delete mode 100644 src/Client/public/assets/icon-24.png delete mode 100644 src/Client/public/assets/icon-32.png delete mode 100644 src/Client/public/assets/icon-40.png delete mode 100644 src/Client/public/assets/icon-48.png delete mode 100644 src/Client/public/assets/icon-64.png delete mode 100644 src/Client/public/assets/icon-80.png delete mode 100644 src/Client/public/assets/icon-96.png delete mode 100644 src/Client/public/assets/logo-filled.png create mode 100644 src/Client/public/assets/swate_16x16.png create mode 100644 src/Client/public/assets/swate_20x20.png create mode 100644 src/Client/public/assets/swate_24x24.png create mode 100644 src/Client/public/assets/swate_32x32.png create mode 100644 src/Client/public/assets/swate_40x40.png create mode 100644 src/Client/public/assets/swate_48x48.png create mode 100644 src/Client/public/assets/swate_64x64.png create mode 100644 src/Client/public/assets/swate_80x80.png create mode 100644 src/Client/public/assets/swate_96x96.png delete mode 100644 tests/manifest.xml delete mode 100644 tests/manifest_old.xml diff --git a/.assets/assets/manifest.xml b/.assets/assets/manifest.xml index 35a02f8d..4e153495 100644 --- a/.assets/assets/manifest.xml +++ b/.assets/assets/manifest.xml @@ -6,8 +6,8 @@ <DefaultLocale>en-US</DefaultLocale> <DisplayName DefaultValue="Swate"/> <Description DefaultValue="Utility functions to annotate data in a fast and safe way."/> - <IconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-32.png"/> - <HighResolutionIconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-80.png"/> + <IconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_32x32.png"/> + <HighResolutionIconUrl DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_80x80.png"/> <SupportUrl DefaultValue="https://csb.bio.uni-kl.de/"/> <AppDomains> <AppDomain>bio.uni-kl.de</AppDomain> @@ -95,15 +95,15 @@ </Hosts> <Resources> <bt:Images> - <bt:Image id="Icon.16x16" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-16.png"/> - <bt:Image id="Icon.20x20" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-20.png"/> - <bt:Image id="Icon.24x24" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-24.png"/> - <bt:Image id="Icon.32x32" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-32.png"/> - <bt:Image id="Icon.40x40" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-40.png"/> - <bt:Image id="Icon.48x48" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-48.png"/> - <bt:Image id="Icon.64x64" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-64.png"/> - <bt:Image id="Icon.80x80" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-80.png"/> - <bt:Image id="Icon.96x96" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/icon-96.png"/> + <bt:Image id="Icon.16x16" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_16x16.png"/> + <bt:Image id="Icon.20x20" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_20x20.png"/> + <bt:Image id="Icon.24x24" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_24x24.png"/> + <bt:Image id="Icon.32x32" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_32x32.png"/> + <bt:Image id="Icon.40x40" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_40x40.png"/> + <bt:Image id="Icon.48x48" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_48x48.png"/> + <bt:Image id="Icon.64x64" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_64x64.png"/> + <bt:Image id="Icon.80x80" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_80x80.png"/> + <bt:Image id="Icon.96x96" DefaultValue="https://swate.denbi.uni-tuebingen.de/assets/swate_96x96.png"/> </bt:Images> <bt:Urls> <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e8926bab..437e7c8c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,17 @@ -### 0.2.1+67ad143 (Released 2021-1-22) +### 0.2.1+5c2e56a (Released 2021-2-2) * Additions: - * latest commit #67ad143 - * [[#67ad143](https://github.com/nfdi4plants/Swate/commit/67ad14381ad8ac8bdbbaefd0ebfa82193c8f94b9)] Update manifest.xml (Issue #86). + * latest commit #5c2e56a + * [[#5c2e56a](https://github.com/nfdi4plants/Swate/commit/5c2e56a46b57fa627c5b37b7e8307ab633a4e12b)] Add option to add unit cols to existing building block (Issue #94). + * [[#9987184](https://github.com/nfdi4plants/Swate/commit/99871849bc83cfa4bd4fe7760c2f43dae524d76b)] Add sorensen dice sorting to advanced term search (Issue #95). + * [[#9158bb7](https://github.com/nfdi4plants/Swate/commit/9158bb75696399492050109ebb0d04be59eeb9b6)] Update unit search to only search UO ontology (Issue #93). + * [[#4e0d0c9](https://github.com/nfdi4plants/Swate/commit/4e0d0c9e32c5be606542f9ca0f05b74be6626e1d)] Add easy to access navigation option to advanced search (Issue #91). + * [[#374e326](https://github.com/nfdi4plants/Swate/commit/374e326f2123a2f61825f281bc4886b109d5261d)] Add features from #68 to Update Reference Columns (Issue 87#). +* Deletions: + * [[#9da9c55](https://github.com/nfdi4plants/Swate/commit/9da9c55a23d737aa05ff7c12759446ce5387902f)] Remove event handlers (input assist, #87) +* Bugfixes: + * [[#cc26e81](https://github.com/nfdi4plants/Swate/commit/cc26e81e895d7ec7fc7abef885e5d7afb4c0a7c2)] Fix bug overloading computers when creating an annotation table for whole rows (Issue #63). + * [[#1e5eb3d](https://github.com/nfdi4plants/Swate/commit/1e5eb3d6c2b0f2f0527d4843c8bc0addabdb0b04)] Fix reset of unit search input when unchecking (Issue #92). + * [[#474cf73](https://github.com/nfdi4plants/Swate/commit/474cf73cb48227d58e88d239e6e9e50e8676c78a)] Fix bug creating wrong TAN with insertTerm. ### 0.2.0+899b535 (Released 2021-1-11) * Additions: diff --git a/Swate.sln b/Swate.sln index 915d6a36..939ac4bc 100644 --- a/Swate.sln +++ b/Swate.sln @@ -25,10 +25,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{A21844B3-2816-4F6F-B275-308DA4EC2B3E}" ProjectSection(SolutionItems) = preProject src\Client\public\favicon.png = src\Client\public\favicon.png - src\Client\public\assets\icon-16.png = src\Client\public\assets\icon-16.png - src\Client\public\assets\icon-32.png = src\Client\public\assets\icon-32.png - src\Client\public\assets\icon-80.png = src\Client\public\assets\icon-80.png - src\Client\public\assets\logo-filled.png = src\Client\public\assets\logo-filled.png EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{DB2C5A73-BF7F-45D5-AEC8-D36539C5C019}" @@ -63,7 +59,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{494903F3 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A7CCC606-3646-4F94-9F59-79C75E413344}" ProjectSection(SolutionItems) = preProject - tests\manifest.xml = tests\manifest.xml tests\test.cmd = tests\test.cmd tests\test.sh = tests\test.sh EndProjectSection diff --git a/build.fsx b/build.fsx index b83775ed..5d033345 100644 --- a/build.fsx +++ b/build.fsx @@ -533,9 +533,8 @@ Target.create "Release" (fun config -> newVer Encoding.UTF8 [ - (Path.combine __SOURCE_DIRECTORY__ ".assets\swate\manifest.xml") + (Path.combine __SOURCE_DIRECTORY__ @".assets\assets\manifest.xml") (Path.combine __SOURCE_DIRECTORY__ "manifest.xml") - (Path.combine __SOURCE_DIRECTORY__ "tests\manifest.xml") ] Trace.trace "Update manifest.xml done!" diff --git a/build.fsx.lock b/build.fsx.lock deleted file mode 100644 index 087f2999..00000000 --- a/build.fsx.lock +++ /dev/null @@ -1,438 +0,0 @@ -STORAGE: NONE -RESTRICTION: == netstandard2.0 -NUGET - remote: https://api.nuget.org/v3/index.json - BlackFox.Fake.BuildTask (0.1.3) - Fake.Core.Target (>= 5.1) - FSharp.Core (>= 4.3.4) - BlackFox.VsWhere (1.1) - FSharp.Core (>= 4.2.3) - Microsoft.Win32.Registry (>= 4.7) - Fake.Api.Github (5.20.3) - FSharp.Core (>= 4.7.2) - Octokit (>= 0.48) - Fake.Core.CommandLineParsing (5.20.3) - FParsec (>= 1.1.1) - FSharp.Core (>= 4.7.2) - Fake.Core.Context (5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.Environment (5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.FakeVar (5.20.3) - Fake.Core.Context (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.Process (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.FakeVar (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - System.Collections.Immutable (>= 1.7.1) - Fake.Core.ReleaseNotes (5.20.3) - Fake.Core.SemVer (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.SemVer (5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.String (5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.Target (5.20.3) - Fake.Core.CommandLineParsing (>= 5.20.3) - Fake.Core.Context (>= 5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.FakeVar (>= 5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - FSharp.Control.Reactive (>= 4.4.2) - FSharp.Core (>= 4.7.2) - Fake.Core.Tasks (5.20.3) - Fake.Core.Trace (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.Trace (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.FakeVar (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Core.Xml (5.20.3) - Fake.Core.String (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.DotNet.AssemblyInfoFile (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.DotNet.Cli (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.DotNet.MSBuild (>= 5.20.3) - Fake.DotNet.NuGet (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Mono.Posix.NETStandard (>= 1.0) - Newtonsoft.Json (>= 12.0.3) - Fake.DotNet.FSFormatting (5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.DotNet.Cli (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.DotNet.Fsi (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.DotNet.MSBuild (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - Fake.Tools.Git (>= 5.20.3) - FSharp.Compiler.Service (>= 36.0.3) - FSharp.Core (>= 4.7.2) - Fake.DotNet.MSBuild (5.20.3) - BlackFox.VsWhere (>= 1.1) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - MSBuild.StructuredLogger (>= 2.1.176) - Fake.DotNet.NuGet (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.SemVer (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Tasks (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.Core.Xml (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - Fake.Net.Http (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Newtonsoft.Json (>= 12.0.3) - NuGet.Protocol (>= 5.6) - Fake.DotNet.Paket (5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.DotNet.Cli (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.DotNet.Testing.Expecto (5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - Fake.Testing.Common (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.IO.FileSystem (5.20.3) - Fake.Core.String (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Net.Http (5.20.3) - Fake.Core.Trace (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Testing.Common (5.20.3) - Fake.Core.Trace (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Fake.Tools.Git (5.20.3) - Fake.Core.Environment (>= 5.20.3) - Fake.Core.Process (>= 5.20.3) - Fake.Core.SemVer (>= 5.20.3) - Fake.Core.String (>= 5.20.3) - Fake.Core.Trace (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - FSharp.Core (>= 4.7.2) - Farmer (1.1.1) - FSharp.Core (>= 4.7.1) - Newtonsoft.Json (>= 12.0.2) - FParsec (1.1.1) - FSharp.Core (>= 4.3.4) - FSharp.Compiler.Service (37.0) - FSharp.Core (>= 4.6.2) - Microsoft.Build.Framework (>= 16.6) - Microsoft.Build.Tasks.Core (>= 16.6) - Microsoft.Build.Utilities.Core (>= 16.6) - System.Buffers (>= 4.5) - System.Collections.Immutable (>= 1.5) - System.Memory (>= 4.5.3) - System.Reflection.Emit (>= 4.3) - System.Reflection.Metadata (>= 1.6) - System.Reflection.TypeExtensions (>= 4.3) - System.Runtime.Loader (>= 4.0) - FSharp.Control.Reactive (4.4.2) - FSharp.Core (>= 4.7.2) - System.Reactive (>= 4.4.1) - FSharp.Core (4.7.2) - Microsoft.Build (16.7) - Microsoft.Build.Framework (16.7) - System.Security.Permissions (>= 4.7) - Microsoft.Build.Tasks.Core (16.7) - Microsoft.Build.Framework (>= 16.7) - Microsoft.Build.Utilities.Core (>= 16.7) - Microsoft.Win32.Registry (>= 4.3) - System.CodeDom (>= 4.4) - System.Collections.Immutable (>= 1.5) - System.Reflection.Metadata (>= 1.6) - System.Reflection.TypeExtensions (>= 4.1) - System.Resources.Extensions (>= 4.6) - System.Security.Permissions (>= 4.7) - System.Threading.Tasks.Dataflow (>= 4.9) - Microsoft.Build.Tasks.Git (1.0) - Microsoft.Build.Utilities.Core (16.7) - Microsoft.Build.Framework (>= 16.7) - Microsoft.Win32.Registry (>= 4.3) - System.Collections.Immutable (>= 1.5) - System.Security.Permissions (>= 4.7) - System.Text.Encoding.CodePages (>= 4.0.1) - Microsoft.NETCore.Platforms (3.1.3) - Microsoft.NETCore.Targets (3.1) - Microsoft.SourceLink.Common (1.0) - Microsoft.SourceLink.GitHub (1.0) - Microsoft.Build.Tasks.Git (>= 1.0) - Microsoft.SourceLink.Common (>= 1.0) - Microsoft.Win32.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - Microsoft.Win32.Registry (4.7) - System.Buffers (>= 4.5) - System.Memory (>= 4.5.3) - System.Security.AccessControl (>= 4.7) - System.Security.Principal.Windows (>= 4.7) - Mono.Posix.NETStandard (1.0) - MSBuild.StructuredLogger (2.1.176) - Microsoft.Build (>= 16.4) - Microsoft.Build.Framework (>= 16.4) - Microsoft.Build.Tasks.Core (>= 16.4) - Microsoft.Build.Utilities.Core (>= 16.4) - Microsoft.SourceLink.GitHub (>= 1.0) - Newtonsoft.Json (12.0.3) - NuGet.Common (5.7) - NuGet.Frameworks (>= 5.7) - System.Diagnostics.Process (>= 4.3) - System.Threading.Thread (>= 4.3) - NuGet.Configuration (5.7) - NuGet.Common (>= 5.7) - System.Security.Cryptography.ProtectedData (>= 4.3) - NuGet.Frameworks (5.7) - NuGet.Packaging (5.7) - Newtonsoft.Json (>= 9.0.1) - NuGet.Configuration (>= 5.7) - NuGet.Versioning (>= 5.7) - System.Dynamic.Runtime (>= 4.3) - System.Security.Cryptography.Cng (>= 5.0.0-preview.3.20214.6) - System.Security.Cryptography.Pkcs (>= 5.0.0-preview.3.20214.6) - NuGet.Protocol (5.7) - NuGet.Packaging (>= 5.7) - System.Dynamic.Runtime (>= 4.3) - NuGet.Versioning (5.7) - Octokit (0.48) - runtime.native.System (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Buffers (4.5.1) - System.CodeDom (4.7) - System.Collections (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Collections.Immutable (1.7.1) - System.Memory (>= 4.5.4) - System.Diagnostics.Debug (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.Process (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - Microsoft.Win32.Registry (>= 4.3) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Encoding.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - System.Dynamic.Runtime (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Linq (>= 4.3) - System.Linq.Expressions (>= 4.3) - System.ObjectModel (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Emit (>= 4.3) - System.Reflection.Emit.ILGeneration (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Reflection.TypeExtensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Formats.Asn1 (5.0.0-preview.8.20407.11) - System.Buffers (>= 4.5.1) - System.Memory (>= 4.5.4) - System.Globalization (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.IO (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem.Primitives (4.3) - System.Runtime (>= 4.3) - System.Linq (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Linq.Expressions (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Linq (>= 4.3) - System.ObjectModel (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Emit (>= 4.3) - System.Reflection.Emit.ILGeneration (>= 4.3) - System.Reflection.Emit.Lightweight (>= 4.3) - System.Reflection.Extensions (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Reflection.TypeExtensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Memory (4.5.4) - System.Buffers (>= 4.5.1) - System.Numerics.Vectors (>= 4.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - System.Numerics.Vectors (4.5) - System.ObjectModel (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Reactive (4.4.1) - System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - System.Threading.Tasks.Extensions (>= 4.5.4) - System.Reflection (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Emit (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - System.Reflection.Emit.ILGeneration (4.7) - System.Reflection.Emit.Lightweight (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - System.Reflection.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Metadata (1.8.1) - System.Collections.Immutable (>= 1.7.1) - System.Reflection.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Reflection.TypeExtensions (4.7) - System.Resources.Extensions (4.7.1) - System.Memory (>= 4.5.4) - System.Resources.ResourceManager (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime.CompilerServices.Unsafe (4.7.1) - System.Runtime.Extensions (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices.WindowsRuntime (4.3) - System.Runtime (>= 4.3) - System.Runtime.Loader (4.3) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Security.AccessControl (4.7) - System.Security.Principal.Windows (>= 4.7) - System.Security.Cryptography.Cng (5.0.0-preview.8.20407.11) - System.Security.Cryptography.Pkcs (5.0.0-preview.8.20407.11) - System.Buffers (>= 4.5.1) - System.Formats.Asn1 (>= 5.0.0-preview.8.20407.11) - System.Memory (>= 4.5.4) - System.Security.Cryptography.Cng (>= 5.0.0-preview.8.20407.11) - System.Security.Cryptography.ProtectedData (4.7) - System.Memory (>= 4.5.3) - System.Security.Permissions (4.7) - System.Security.AccessControl (>= 4.7) - System.Security.Principal.Windows (4.7) - System.Text.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding.CodePages (4.7.1) - System.Runtime.CompilerServices.Unsafe (>= 4.7.1) - System.Text.Encoding.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Tasks (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Threading.Tasks.Dataflow (4.11.1) - System.Threading.Tasks.Extensions (4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - System.Threading.Thread (4.3) - System.Runtime (>= 4.3) - System.Threading.ThreadPool (4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) diff --git a/manifest.xml b/manifest.xml index 792dcd64..078da0d8 100644 --- a/manifest.xml +++ b/manifest.xml @@ -6,8 +6,8 @@ <DefaultLocale>en-US</DefaultLocale> <DisplayName DefaultValue="Swate"/> <Description DefaultValue="Utility functions to annotate data in a fast and safe way."/> - <IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png"/> - <HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-80.png"/> + <IconUrl DefaultValue="https://localhost:3000/assets/swate_32x32.png"/> + <HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/swate_80x80.png"/> <SupportUrl DefaultValue="https://csb.bio.uni-kl.de/"/> <AppDomains> <AppDomain>bio.uni-kl.de</AppDomain> @@ -95,15 +95,15 @@ </Hosts> <Resources> <bt:Images> - <bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/> - <bt:Image id="Icon.20x20" DefaultValue="https://localhost:3000/assets/icon-20.png"/> - <bt:Image id="Icon.24x24" DefaultValue="https://localhost:3000/assets/icon-24.png"/> - <bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/> - <bt:Image id="Icon.40x40" DefaultValue="https://localhost:3000/assets/icon-40.png"/> - <bt:Image id="Icon.48x48" DefaultValue="https://localhost:3000/assets/icon-48.png"/> - <bt:Image id="Icon.64x64" DefaultValue="https://localhost:3000/assets/icon-64.png"/> - <bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/> - <bt:Image id="Icon.96x96" DefaultValue="https://localhost:3000/assets/icon-96.png"/> + <bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/swate_16x16.png"/> + <bt:Image id="Icon.20x20" DefaultValue="https://localhost:3000/assets/swate_20x20.png"/> + <bt:Image id="Icon.24x24" DefaultValue="https://localhost:3000/assets/swate_24x24.png"/> + <bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/swate_32x32.png"/> + <bt:Image id="Icon.40x40" DefaultValue="https://localhost:3000/assets/swate_40x40.png"/> + <bt:Image id="Icon.48x48" DefaultValue="https://localhost:3000/assets/swate_48x48.png"/> + <bt:Image id="Icon.64x64" DefaultValue="https://localhost:3000/assets/swate_64x64.png"/> + <bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/swate_80x80.png"/> + <bt:Image id="Icon.96x96" DefaultValue="https://localhost:3000/assets/swate_96x96.png"/> </bt:Images> <bt:Urls> <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> diff --git a/paket.dependencies b/paket.dependencies index 78b7f28d..25bb6b6c 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -8,7 +8,8 @@ nuget Fable.SimpleXml nuget FSharp.Data nuget Fulma.Extensions.Wikiki.Checkradio nuget Fulma.Extensions.Wikiki.Slider -nuget ISADotNet +nuget ISADotNet 0.0.3 +nuget ISADotNet.XLSX 0.0.3 nuget Saturn nuget Expecto nuget MySql.Data 8.0.21 diff --git a/paket.lock b/paket.lock index 98919937..60911a4c 100644 --- a/paket.lock +++ b/paket.lock @@ -3,6 +3,8 @@ RESTRICTION: == netcoreapp3.1 NUGET remote: https://api.nuget.org/v3/index.json BouncyCastle.NetCore (1.8.8) + DocumentFormat.OpenXml (2.12.1) + System.IO.Packaging (>= 4.7) Expecto (9.0.2) FSharp.Core (>= 4.6) Mono.Cecil (>= 0.11.2) @@ -114,6 +116,9 @@ NUGET FSharp.Core (>= 4.3.4) FSharp.SystemTextJson (0.15.14) FSharp.Core (>= 4.7) + FSharpSpreadsheetML (0.0.2) + DocumentFormat.OpenXml + FSharp.Core (4.7.2) Fulma (2.10) Fable.Core (>= 3.0) Fable.React (>= 5.1) @@ -142,10 +147,14 @@ NUGET Google.Protobuf (3.14) System.Memory (>= 4.5.3) System.Runtime.CompilerServices.Unsafe (>= 4.5.2) - ISADotNet (0.0.2) + ISADotNet (0.0.3) FSharp.Core (4.7.2) FSharp.SystemTextJson (>= 0.15.14 < 0.16) System.Text.Json (>= 5.0.1 < 5.1) + ISADotNet.XLSX (0.0.3) + FSharp.Core (4.7.2) + FSharpSpreadsheetML (>= 0.0.2 < 0.1) + ISADotNet (>= 0.0.3) K4os.Compression.LZ4 (1.2.6) System.Memory (>= 4.5.4) K4os.Compression.LZ4.Streams (1.2.6) @@ -225,7 +234,7 @@ NUGET Giraffe (>= 4.1) Microsoft.AspNetCore.Authentication.JwtBearer (>= 3.0.3) System.Threading.Tasks.Dataflow (>= 4.11.1) - SSH.NET (2020.0) + SSH.NET (2020.0.1) SshNet.Security.Cryptography (1.3) SshNet.Security.Cryptography (1.3) System.Buffers (4.5.1) @@ -238,6 +247,7 @@ NUGET System.IdentityModel.Tokens.Jwt (6.8) Microsoft.IdentityModel.JsonWebTokens (>= 6.8) Microsoft.IdentityModel.Tokens (>= 6.8) + System.IO.Packaging (5.0) System.Memory (4.5.4) System.Reflection.Emit (4.7) System.Reflection.Emit.Lightweight (4.7) diff --git a/src/Client/Client.fs b/src/Client/Client.fs index a44247df..f67eb59e 100644 --- a/src/Client/Client.fs +++ b/src/Client/Client.fs @@ -63,56 +63,56 @@ let view (model : Model) (dispatch : Msg -> unit) = BaseView.baseViewComponent model dispatch [ TermSearchView.termSearchComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.Validation -> BaseView.baseViewComponent model dispatch [ ValidationView.validationComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.FilePicker -> BaseView.baseViewComponent model dispatch [ FilePickerView.filePickerComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.FileUploadJson -> BaseView.baseViewComponent model dispatch [ FileUploadJsonView.fileUploadViewComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.ActivityLog -> BaseView.baseViewComponent model dispatch [ ActivityLogView.activityLogComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.Settings -> BaseView.baseViewComponent model dispatch [ SettingsView.settingsViewComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.Info -> BaseView.baseViewComponent model dispatch [ InfoView.infoComponent model dispatch ][ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.NotFound -> BaseView.baseViewComponent model dispatch [ NotFoundView.notFoundComponent model dispatch ] [ - Text.p [] [str ""] + //Text.p [] [str ""] ] | Routing.Route.Home -> diff --git a/src/Client/Client.fsproj b/src/Client/Client.fsproj index 10759268..92555259 100644 --- a/src/Client/Client.fsproj +++ b/src/Client/Client.fsproj @@ -5,6 +5,7 @@ <DefineConstants>FABLE_COMPILER</DefineConstants> </PropertyGroup> <ItemGroup> + <Compile Include="NFDIColors.fs" /> <None Include="index.html" /> <None Include="paket.references" /> <None Include="style.scss" /> diff --git a/src/Client/CustomComponents/AnnotationTableMissingWarning.fs b/src/Client/CustomComponents/AnnotationTableMissingWarning.fs index 52898ea0..028f79bc 100644 --- a/src/Client/CustomComponents/AnnotationTableMissingWarning.fs +++ b/src/Client/CustomComponents/AnnotationTableMissingWarning.fs @@ -8,14 +8,18 @@ open ExcelColors open Model open Messages + let annotationTableMissingWarningComponent (model:Model) (dispatch: Msg-> unit) = Notification.notification [ Notification.Color IsWarning Notification.Props [ - ] ] [ - Notification.delete [] [] + Notification.delete [ Props [ + OnClick (fun e -> + AnnotationTableExists (OfficeInterop.Types.TryFindAnnoTableResult.Success "Remove Warning Notification") |> ExcelInterop |> dispatch + ) + ]] [ ] Heading.h5 [] [str "Warning: No Annotation table found in worksheet"] Text.p [] [ str "Your worksheet seems to contain no annotation table. You can create one by pressing the button below" diff --git a/src/Client/CustomComponents/AutocompleteSearch.fs b/src/Client/CustomComponents/AutocompleteSearch.fs index 67179958..adc3b581 100644 --- a/src/Client/CustomComponents/AutocompleteSearch.fs +++ b/src/Client/CustomComponents/AutocompleteSearch.fs @@ -201,13 +201,17 @@ let createAutocompleteSuggestions let autocompleteDropdownComponent (dispatch:Msg -> unit) (colorMode:ColorMode) (isVisible: bool) (isLoading:bool) (suggestions: ReactElement list) = - Container.container[] [ + Container.container[ ] [ Dropdown.content [Props [ Style [ if isVisible then Display DisplayOptions.Block else Display DisplayOptions.None //if model.ShowFillSuggestions then Display DisplayOptions.Block else Display DisplayOptions.None + ZIndex "20" + Width "100%" + Position PositionOptions.Absolute BackgroundColor colorMode.ControlBackground BorderColor colorMode.ControlForeground + MarginTop "-0.5rem" ]] ] [ Table.table [Table.IsFullWidth] [ @@ -244,6 +248,7 @@ let autocompleteTermSearchComponent Input.input [ Input.Disabled isDisabled Input.Placeholder inputPlaceholderText + Input.ValueOrDefault autocompleteParams.StateBinding match inputSize with | Some size -> Input.Size size | _ -> () @@ -295,6 +300,7 @@ let autocompleteTermSearchComponentOfParentOntology | Some size -> Input.Size size | _ -> () Input.Props [ + ExcelColors.colorControl colorMode //OnFocus (fun e -> alert "focusout") //OnBlur (fun e -> alert "focusin") diff --git a/src/Client/CustomComponents/ErrorModal.fs b/src/Client/CustomComponents/ErrorModal.fs index 23609566..3c70815e 100644 --- a/src/Client/CustomComponents/ErrorModal.fs +++ b/src/Client/CustomComponents/ErrorModal.fs @@ -19,7 +19,7 @@ let errorModal (model:Model) dispatch = ] [ ] Notification.notification [ Notification.Color IsDanger - Notification.Props [Style [MaxWidth "80%"]] + Notification.Props [Style [MaxWidth "80%"; MaxHeight "80%"; OverflowX OverflowOptions.Auto (*CSSProp.Custom ("overflow", "scroll")*)]] ] [ Notification.delete [Props [OnClick closeMsg]][] str model.DevState.LastFullError.Value.Message diff --git a/src/Client/CustomComponents/Navbar.fs b/src/Client/CustomComponents/Navbar.fs index d850c9c7..049358ee 100644 --- a/src/Client/CustomComponents/Navbar.fs +++ b/src/Client/CustomComponents/Navbar.fs @@ -3,22 +3,24 @@ module CustomComponents.Navbar open Fable.React open Fable.React.Props open Fulma +open Fable.FontAwesome +open Fulma.Extensions.Wikiki open ExcelColors open Model open Messages -open Fable.FontAwesome let navbarComponent (model : Model) (dispatch : Msg -> unit) = Navbar.navbar [Navbar.Props [Props.Role "navigation"; AriaLabel "main navigation" ; ExcelColors.colorElement model.SiteStyleState.ColorMode]] [ Navbar.Brand.a [] [ Navbar.Item.a [Navbar.Item.Props [Props.Href "https://csb.bio.uni-kl.de/"]] [ - img [Props.Src "../assets/CSB_Logo.png"] + img [Props.Src "../assets/Swate_logo_for_excel.svg"] ] - Navbar.Item.a [Navbar.Item.Props [Title "Add New Annotation Table"; Style [ Color model.SiteStyleState.ColorMode.Text]]] [ + Navbar.Item.a [Navbar.Item.Props [Style [ Color model.SiteStyleState.ColorMode.Text]]] [ Button.a [ - Button.Props [Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]] + Button.CustomClass (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) + Button.Props [ Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]; Tooltip.dataTooltip ("Add Annotation Table") ] Button.OnClick (fun _ -> (fun (allNames) -> CreateAnnotationTable (allNames,model.SiteStyleState.IsDarkMode)) @@ -33,9 +35,10 @@ let navbarComponent (model : Model) (dispatch : Msg -> unit) = Fa.span [Fa.Solid.Table][] ] ] - Navbar.Item.a [Navbar.Item.Props [Title "Autoformat Table"; Style [ Color model.SiteStyleState.ColorMode.Text]]] [ + Navbar.Item.a [Navbar.Item.Props [Style [ Color model.SiteStyleState.ColorMode.Text]]] [ Button.a [ - Button.Props [Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]] + Button.CustomClass (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) + Button.Props [Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]; Tooltip.dataTooltip ("Autoformat Table")] Button.OnClick (fun e -> PipeActiveAnnotationTable AutoFitTable |> ExcelInterop |> dispatch ) Button.Color Color.IsWhite Button.IsInverted @@ -43,9 +46,10 @@ let navbarComponent (model : Model) (dispatch : Msg -> unit) = Fa.i [Fa.Solid.SyncAlt][] ] ] - Navbar.Item.a [Navbar.Item.Props [Title "Update Reference Columns"; Style [ Color model.SiteStyleState.ColorMode.Text]]] [ + Navbar.Item.a [Navbar.Item.Props [Style [ Color model.SiteStyleState.ColorMode.Text]]] [ Button.a [ - Button.Props [Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]] + Button.CustomClass (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) + Button.Props [Style [BackgroundColor model.SiteStyleState.ColorMode.ElementBackground]; Tooltip.dataTooltip ("Update Reference Columns")] Button.OnClick (fun _ -> PipeActiveAnnotationTable FillHiddenColsRequest |> ExcelInterop |> dispatch ) @@ -57,13 +61,16 @@ let navbarComponent (model : Model) (dispatch : Msg -> unit) = Fa.span [Fa.Solid.Pen][] ] ] - Navbar.burger [ Navbar.Burger.IsActive model.SiteStyleState.BurgerVisible - Navbar.Burger.OnClick (fun e -> ToggleBurger |> StyleChange |> dispatch) - Navbar.Burger.Props[ - Role "button" - AriaLabel "menu" - Props.AriaExpanded false - ] + Navbar.burger [ + Navbar.Burger.IsActive model.SiteStyleState.BurgerVisible + Navbar.Burger.OnClick (fun e -> ToggleBurger |> StyleChange |> dispatch) + Navbar.Burger.Modifiers [Modifier.TextColor IsWhite] + Navbar.Burger.Props[ + Role "button" + AriaLabel "menu" + Props.AriaExpanded false + + ] ] [ span [AriaHidden true] [] span [AriaHidden true] [] @@ -73,10 +80,10 @@ let navbarComponent (model : Model) (dispatch : Msg -> unit) = Navbar.menu [Navbar.Menu.Props [Id "navbarMenu"; Class (if model.SiteStyleState.BurgerVisible then "navbar-menu is-active" else "navbar-menu") ; ExcelColors.colorControl model.SiteStyleState.ColorMode]] [ Navbar.Dropdown.div [ ] [ Navbar.Item.a [Navbar.Item.Props [Style [ Color model.SiteStyleState.ColorMode.Text]]] [ - str "How to use" + str "How to use (WIP)" ] Navbar.Item.a [Navbar.Item.Props [Style [ Color model.SiteStyleState.ColorMode.Text]]] [ - str "Contact" + str "Contact (WIP)" ] Navbar.Item.a [Navbar.Item.Props [ OnClick (fun e -> diff --git a/src/Client/Messages.fs b/src/Client/Messages.fs index 3813006c..56cce781 100644 --- a/src/Client/Messages.fs +++ b/src/Client/Messages.fs @@ -12,6 +12,8 @@ open OfficeInterop open OfficeInterop.Types open Model +open ISADotNet + type ExcelInteropMsg = | PipeActiveAnnotationTable of (TryFindAnnoTableResult -> ExcelInteropMsg) /// This is used to pipe (all table names []) to a ExcelInteropMsg. @@ -115,6 +117,7 @@ type PersistentStorageMsg = type FilePickerMsg = | LoadNewFiles of string list | UpdateFileNames of newFileNames:(int*string) list + /// | UpdateDNDDropped of isDropped:bool type AddBuildingBlockMsg = @@ -143,6 +146,9 @@ type FileUploadJsonMsg = | ParseJsonToProcessRequest of string | ParseJsonToProcessResult of Result<Process,exn> +type TopLevelMsg = + | CloseSuggestions + type Msg = | Bounce of (System.TimeSpan*string*Msg) | Api of ApiMsg @@ -157,6 +163,7 @@ type Msg = | AddBuildingBlock of AddBuildingBlockMsg | Validation of ValidationMsg | FileUploadJson of FileUploadJsonMsg + | TopLevelMsg of TopLevelMsg | UpdatePageState of Routing.Route option | Batch of seq<Msg> | DoNothing diff --git a/src/Client/Model.fs b/src/Client/Model.fs index 75afcaa1..27e1adf2 100644 --- a/src/Client/Model.fs +++ b/src/Client/Model.fs @@ -208,10 +208,10 @@ type PageState = { } type FilePickerState = { - FileNames : (int*string) list + FileNames : (int*string) list /// Used for drag and drop, to determine if something is currently dragged or not. /// Necessary to deactivate pointer events on children during drag. - DNDDropped : bool + DNDDropped : bool } with static member init () = { FileNames = [] @@ -316,7 +316,7 @@ type AddBuildingBlockState = { static member init () = { ShowBuildingBlockSelection = false - CurrentBuildingBlock = AnnotationBuildingBlock.init NoneSelected + CurrentBuildingBlock = AnnotationBuildingBlock.init AnnotationBuildingBlockType.Parameter BuildingBlockNameSuggestions = [||] ShowBuildingBlockTermSuggestions = false @@ -351,7 +351,7 @@ type ValidationState = { type FileUploadJsonState = { UploadData: string - ProcessModel: ISADotNet.Process option + ProcessModel: ISADotNet.OntologyAnnotation option } with static member init () = { UploadData = "" diff --git a/src/Client/NFDIColors.fs b/src/Client/NFDIColors.fs new file mode 100644 index 00000000..40d4f714 --- /dev/null +++ b/src/Client/NFDIColors.fs @@ -0,0 +1,218 @@ +/// Colors used from nfdi4plants Branding repository on GitHub +// https://github.com/nfdi4plants/Branding#dataplant +module NFDIColors + +module Mint = + + [<Literal>] + let Base = "#1FC2A7" + + [<Literal>] + let Lighter10 = "#35c8b0" + [<Literal>] + let Lighter20 = "#4cceb9" + [<Literal>] + let Lighter30 = "#62d4c1" + [<Literal>] + let Lighter40 = "#79daca" + [<Literal>] + let Lighter50 = "#8fe1d3" + [<Literal>] + let Lighter60 = "#a5e7dc" + [<Literal>] + let Lighter70 = "#bcede5" + [<Literal>] + let Lighter80 = "#d2f3ed" + [<Literal>] + let Lighter90 = "#e9f9f6" + + [<Literal>] + let Darker10 = "#1caf96" + [<Literal>] + let Darker20 = "#199b86" + [<Literal>] + let Darker30 = "#168875" + [<Literal>] + let Darker40 = "#137464" + [<Literal>] + let Darker50 = "#106154" + [<Literal>] + let Darker60 = "#0c4e43" + [<Literal>] + let Darker70 = "#093a32" + [<Literal>] + let Darker80 = "#062721" + [<Literal>] + let Darker90 = "#031311" + +module LightBlue = + + [<Literal>] + let Base = "#4FB3D9" + + [<Literal>] + let Lighter10 = "#61bbdd" + [<Literal>] + let Lighter20 = "#72c2e1" + [<Literal>] + let Lighter30 = "#84cae4" + [<Literal>] + let Lighter40 = "#95d1e8" + [<Literal>] + let Lighter50 = "#a7d9ec" + [<Literal>] + let Lighter60 = "#b9e1f0" + [<Literal>] + let Lighter70 = "#cae8f4" + [<Literal>] + let Lighter80 = "#dcf0f7" + [<Literal>] + let Lighter90 = "#edf7fb" + + [<Literal>] + let Darker10 = "#47a1c3" + [<Literal>] + let Darker20 = "#3f8fae" + [<Literal>] + let Darker30 = "#377d98" + [<Literal>] + let Darker40 = "#2f6b82" + [<Literal>] + let Darker50 = "#285a6d" + [<Literal>] + let Darker60 = "#204857" + [<Literal>] + let Darker70 = "#183641" + [<Literal>] + let Darker80 = "#10242b" + [<Literal>] + let Darker90 = "#081216" + +module DarkBlue = + + [<Literal>] + let Base = "#2D3E50" + + [<Literal>] + let Lighter10 = "#425162" + [<Literal>] + let Lighter20 = "#576573" + [<Literal>] + let Lighter30 = "#6c7885" + [<Literal>] + let Lighter40 = "#818b96" + [<Literal>] + let Lighter50 = "#969fa8" + [<Literal>] + let Lighter60 = "#abb2b9" + [<Literal>] + let Lighter70 = "#c0c5cb" + [<Literal>] + let Lighter80 = "#d5d8dc" + [<Literal>] + let Lighter90 = "#eaecee" + + [<Literal>] + let Darker10 = "#293848" + [<Literal>] + let Darker20 = "#243240" + [<Literal>] + let Darker30 = "#1f2b38" + [<Literal>] + let Darker40 = "#1b2530" + [<Literal>] + let Darker50 = "#171f28" + [<Literal>] + let Darker60 = "#121920" + [<Literal>] + let Darker70 = "#0d1318" + [<Literal>] + let Darker80 = "#090c10" + [<Literal>] + let Darker90 = "#040608" + +module Yellow = + + [<Literal>] + let Base = "#FFC000" + + [<Literal>] + let Lighter10 = "#ffc61a" + [<Literal>] + let Lighter20 = "#ffcd33" + [<Literal>] + let Lighter30 = "#ffd34d" + [<Literal>] + let Lighter40 = "#ffd966" + [<Literal>] + let Lighter50 = "#ffe080" + [<Literal>] + let Lighter60 = "#ffe699" + [<Literal>] + let Lighter70 = "#ffecb3" + [<Literal>] + let Lighter80 = "#fff2cc" + [<Literal>] + let Lighter90 = "#fff9e6" + + [<Literal>] + let Darker10 = "#e6ad00" + [<Literal>] + let Darker20 = "#cc9a00" + [<Literal>] + let Darker30 = "#b38600" + [<Literal>] + let Darker40 = "#997300" + [<Literal>] + let Darker50 = "#806000" + [<Literal>] + let Darker60 = "#664d00" + [<Literal>] + let Darker70 = "#4c3a00" + [<Literal>] + let Darker80 = "#332600" + [<Literal>] + let Darker90 = "#191300" + +module Red = + + [<Literal>] + let Base = "#c21f3a" + + [<Literal>] + let Lighter10 = "#C8354D" + [<Literal>] + let Lighter20 = "#CE4B61" + [<Literal>] + let Lighter30 = "#D46275" + [<Literal>] + let Lighter40 = "#DA7888" + [<Literal>] + let Lighter50 = "#E08F9C" + [<Literal>] + let Lighter60 = "#E6A5B0" + [<Literal>] + let Lighter70 = "#ECBBC3" + [<Literal>] + let Lighter80 = "#F2D2D7" + [<Literal>] + let Lighter90 = "#F8E8EB" + + [<Literal>] + let Darker10 = "#AE1B34" + [<Literal>] + let Darker20 = "#9B182E" + [<Literal>] + let Darker30 = "#871528" + [<Literal>] + let Darker40 = "#741222" + [<Literal>] + let Darker50 = "#600F1D" + [<Literal>] + let Darker60 = "#4D0C17" + [<Literal>] + let Darker70 = "#3A0911" + [<Literal>] + let Darker80 = "#26060B" + [<Literal>] + let Darker90 = "#130305" \ No newline at end of file diff --git a/src/Client/OfficeInterop/OfficeInterop.fs b/src/Client/OfficeInterop/OfficeInterop.fs index 6038a83d..57baa626 100644 --- a/src/Client/OfficeInterop/OfficeInterop.fs +++ b/src/Client/OfficeInterop/OfficeInterop.fs @@ -354,6 +354,7 @@ let getTableRepresentation(annotationTable) = else /// Should no current TableValidation xml exist, create a new one TableValidation.create + "" worksheetName annotationTable System.DateTime.Now @@ -965,9 +966,27 @@ let getSwateValidationXml() = promise { - let! xmlParsed, currentSwateValidationXml = getCurrentValidationXml customXmlParts context + //let! xmlParsed, currentSwateValidationXml = getCurrentValidationXml customXmlParts context + + let! getXml = + context.sync().``then``(fun e -> + let items = customXmlParts.items + let xmls = items |> Seq.map (fun x -> x.getXml() ) + + xmls |> Array.ofSeq + ) + + let! xml = + context.sync().``then``(fun e -> + + //let nOfItems = customXmlParts.items.Count + let vals = getXml |> Array.map (fun x -> x.value) + //sprintf "N = %A; items: %A" nOfItems vals + let xml = vals |> String.concat Environment.NewLine + xml + ) - return "Info",sprintf "%A" currentSwateValidationXml + return "Info",sprintf "%A" xml } ) @@ -975,7 +994,12 @@ let writeTableValidationToXml(tableValidation:TableValidation,currentSwateVersio Excel.run(fun context -> // Update DateTime - let newTableValidation = {tableValidation with DateTime = System.DateTime.Now} + let newTableValidation = { + tableValidation with + // This line is used to give freshly created TableValidations the current Swate Version + SwateVersion = if tableValidation.SwateVersion = "" then currentSwateVersion else tableValidation.SwateVersion + DateTime = System.DateTime.Now + } // The first part accesses current CustomXml let workbook = context.workbook.load(propertyNames = U2.Case2 (ResizeArray[|"customXmlParts"|])) diff --git a/src/Client/OfficeInterop/Types.fs b/src/Client/OfficeInterop/Types.fs index ede38043..7564a72a 100644 --- a/src/Client/OfficeInterop/Types.fs +++ b/src/Client/OfficeInterop/Types.fs @@ -111,6 +111,7 @@ module XmlValidationTypes = /// User can define what kind of input a column should have type ContentType = | OntologyTerm of string + | UnitTerm of string | Text | Url | Boolean @@ -122,6 +123,8 @@ module XmlValidationTypes = match this with | OntologyTerm po -> sprintf "Ontology [%s]" po + | UnitTerm ut -> + sprintf "Unit [%s]" ut | _ -> string this @@ -130,6 +133,9 @@ module XmlValidationTypes = | ontology when str.StartsWith "OntologyTerm " -> let s = ontology.Replace("OntologyTerm ","").Replace("\"","") OntologyTerm s + | unit when str.StartsWith "UnitTerm " -> + let s = unit.Replace("UnitTerm ", "").Replace("\"","") + UnitTerm s | "Text" -> Text | "Url" -> Url | "Boolean" -> Boolean @@ -163,6 +169,7 @@ module XmlValidationTypes = } type TableValidation = { + SwateVersion : string WorksheetName : string TableName : string DateTime : DateTime @@ -170,14 +177,16 @@ module XmlValidationTypes = Userlist : string list ColumnValidations: ColumnValidation list } with - static member create worksheetName tableName dateTime userlist colValidations = { + static member create swateVersion worksheetName tableName dateTime userlist colValidations = { + SwateVersion = swateVersion WorksheetName = worksheetName TableName = tableName DateTime = dateTime Userlist = userlist ColumnValidations = colValidations } - static member init (?worksheetName,?tableName, (?dateTime:DateTime), ?userList) = { + static member init (?swateVersion, ?worksheetName,?tableName, (?dateTime:DateTime), ?userList) = { + SwateVersion = if swateVersion.IsSome then swateVersion.Value else "" WorksheetName = if worksheetName.IsSome then worksheetName.Value else "" TableName = if tableName.IsSome then tableName.Value else "" DateTime = if dateTime.IsSome then dateTime.Value else DateTime.Now @@ -187,6 +196,7 @@ module XmlValidationTypes = /// This type is used to work on the CustomXml 'Validation' tag, which is used to store information on how to validate a specifc Swate table as correct. type SwateValidation = { + /// Used to show the last used Swate version to edit SwateValidation CustomXml SwateVersion : string TableValidations : TableValidation list } with @@ -202,6 +212,7 @@ module XmlValidationTypes = for table in this.TableValidations do yield node "TableValidation" [ + attr.value( "SwateVersion", table.SwateVersion ) attr.value( "WorksheetName", table.WorksheetName ) attr.value( "TableName", table.TableName ) attr.value( "DateTime", table.DateTime.ToString("yyyy-MM-dd HH:mm") ) @@ -230,6 +241,7 @@ module XmlValidationTypes = let tableValidationTypes = tableValidations |> List.map (fun table -> + let swateVersion = table.Attributes.["SwateVersion"] let worksheetName = table.Attributes.["WorksheetName"] let tableName = table.Attributes.["TableName"] let dateTime = @@ -248,7 +260,7 @@ module XmlValidationTypes = let unit = column.Attributes.["Unit"] |> fun x -> if x = "None" then None else Some x ColumnValidation.create columnHeader columnAdress importance validationFormat unit ) - TableValidation.create worksheetName tableName dateTime userlist columnValidationTypes + TableValidation.create swateVersion worksheetName tableName dateTime userlist columnValidationTypes ) { validationType with TableValidations = tableValidationTypes } diff --git a/src/Client/Routing.fs b/src/Client/Routing.fs index 3ac96505..0529c4a7 100644 --- a/src/Client/Routing.fs +++ b/src/Client/Routing.fs @@ -44,10 +44,24 @@ type Route = | Route.Settings -> "Settings" | Route.NotFound -> "NotFound" + member this.toStringRdbl = + match this with + | Route.Home -> "" + | Route.AddBuildingBlock -> "Manage Building Blocks" + | Route.TermSearch -> "Manage Terms" + | Route.Validation -> "Validation" + | Route.FilePicker -> "File Picker" + | Route.FileUploadJson -> "File Upload" + | Route.Info -> "Info" + | Route.ActivityLog -> "Activity Log" + | Route.Settings -> "Settings" + | Route.NotFound -> "NotFound" + + static member toIcon (p: Route)= let createElem icons name = Fable.React.Standard.span [ - Fable.React.Props.Class (Tooltip.ClassName + " " + Tooltip.IsTooltipRight + " " + Tooltip.IsMultiline) + Fable.React.Props.Class (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) Tooltip.dataTooltip (name) ] ( icons @@ -58,15 +72,15 @@ type Route = ) match p with - | Route.Home -> createElem [Fa.Solid.Home ] (p |> Route.toString) - | Route.TermSearch -> createElem [Fa.Solid.SearchPlus ] (p |> Route.toString) - | Route.Validation -> createElem [Fa.Solid.ClipboardCheck ] (p |> Route.toString) - | Route.AddBuildingBlock -> createElem [Fa.Solid.Columns; Fa.Solid.PlusCircle ] (p |> Route.toString) - | Route.FilePicker -> createElem [Fa.Solid.FileUpload ] (p |> Route.toString) - | Route.FileUploadJson -> createElem [Fa.Solid.Upload ] (p |> Route.toString) - | Route.ActivityLog -> createElem [Fa.Solid.History ] (p |> Route.toString) - | Route.Info -> createElem [Fa.Solid.Question ] (p |> Route.toString) - | _ -> Fa.i [Fa.Solid.QuestionCircle] [] + | Route.Home -> createElem [Fa.Solid.Home ] (p.toStringRdbl) + | Route.TermSearch -> createElem [Fa.Solid.SearchPlus ] (p.toStringRdbl) + | Route.Validation -> createElem [Fa.Solid.ClipboardCheck ] (p.toStringRdbl) + | Route.AddBuildingBlock -> createElem [Fa.Solid.Columns; Fa.Solid.PlusCircle ] (p.toStringRdbl) + | Route.FilePicker -> createElem [Fa.Solid.FileUpload ] (p.toStringRdbl) + | Route.FileUploadJson -> createElem [Fa.Solid.Upload ] (p.toStringRdbl) + | Route.ActivityLog -> createElem [Fa.Solid.History ] (p.toStringRdbl) + | Route.Info -> createElem [Fa.Solid.Question ] (p.toStringRdbl) + | _ -> Fa.i [Fa.Solid.QuestionCircle] [] ///explained here: https://elmish.github.io/browser/routing.html //let curry f x y = f (x,y) diff --git a/src/Client/Update.fs b/src/Client/Update.fs index 9af60bcf..cb037530 100644 --- a/src/Client/Update.fs +++ b/src/Client/Update.fs @@ -1187,6 +1187,7 @@ let handleValidationMsg (validationMsg:ValidationMsg) (currentState: ValidationS let nextCmd = GenericLog ("Info", msg) |> Dev |> Cmd.ofMsg + let nextState = { currentState with ActiveTableBuildingBlocks = buildingBlocks @@ -1225,15 +1226,44 @@ let handleFileUploadJsonMsg (fujMsg:FileUploadJsonMsg) (currentState: FileUpload (Result.Error >> ParseJsonToProcessResult) currentState, Cmd.map FileUploadJson cmd | ParseJsonToProcessResult (Ok isaProcess) -> + printfn "THIS WAS DEPRECATED CHECK IN UPDATE.fs IN ParseJsonToProcessResult" let nextState = { currentState with - ProcessModel = Some isaProcess + // TODO + ProcessModel = None } nextState, Cmd.none | ParseJsonToProcessResult (Result.Error e) -> let cmd = GenericError e |> Dev |> Cmd.ofMsg currentState, cmd + //| SendJson -> + // let cmd = + // Cmd.OfAsync.perform + // Api.isaDotNetApi.tryTestProcess + // ISADotNet.Process.empty + // (fun x -> GenericLog ("info", "sent process")) + // currentState, Cmd.map Dev cmd + + +let handleTopLevelMsg (topLevelMsg:TopLevelMsg) (currentModel: Model) : Model * Cmd<Msg> = + match topLevelMsg with + // Client + | CloseSuggestions -> + let nextModel = { + currentModel with + TermSearchState = { + currentModel.TermSearchState with + ShowSuggestions = false + } + AddBuildingBlockState = { + currentModel.AddBuildingBlockState with + ShowBuildingBlockTermSuggestions = false + ShowUnitTermSuggestions = false + ShowUnit2TermSuggestions = false + } + } + nextModel, Cmd.none let update (msg : Msg) (currentModel : Model) : Model * Cmd<Msg> = match msg with @@ -1415,4 +1445,10 @@ let update (msg : Msg) (currentModel : Model) : Model * Cmd<Msg> = currentModel with FileUploadJsonState = nextFileUploadJsonState } + nextModel, nextCmd + + | TopLevelMsg topLevelMsg -> + let nextModel, nextCmd = + handleTopLevelMsg topLevelMsg currentModel + nextModel, nextCmd \ No newline at end of file diff --git a/src/Client/Views/ActivityLogView.fs b/src/Client/Views/ActivityLogView.fs index bbdee40d..95425c7e 100644 --- a/src/Client/Views/ActivityLogView.fs +++ b/src/Client/Views/ActivityLogView.fs @@ -45,7 +45,7 @@ let activityLogComponent (model:Model) dispatch = Container.container [ Container.Props [Style [ Padding "1rem" - Border "2.5px solid #f14668" + Border (sprintf "2.5px solid %s" NFDIColors.Red.Base) BorderRadius "10px" ]] ][ diff --git a/src/Client/Views/AddBuildingBlockView.fs b/src/Client/Views/AddBuildingBlockView.fs index 721a4f2f..ff0cc49b 100644 --- a/src/Client/Views/AddBuildingBlockView.fs +++ b/src/Client/Views/AddBuildingBlockView.fs @@ -38,7 +38,7 @@ let isValidBuildingBlock (block : AnnotationBuildingBlock) = // td [] [ // b [] [str sugg.Name] // ] -// td [Style [Color "red"]] [if sugg.IsObsolete then str "obsolete"] +// td [Style [Color ""]] [if sugg.IsObsolete then str "obsolete"] // td [Style [FontWeight "light"]] [small [] [str sugg.Accession]] // ]) // |> List.ofArray @@ -86,14 +86,22 @@ let addBuildingBlockFooterComponent (model:Model) (dispatch:Msg -> unit) = ] let addBuildingBlockElements (model:Model) (dispatch:Msg -> unit) = - [ - Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Select the type of annotation building block (column) to add to the annotation table."] - Field.div [Field.HasAddons] [ + div [ + Style [ + BorderLeft (sprintf "5px solid %s" NFDIColors.Mint.Base) + //BorderRadius "15px 15px 0 0" + Padding "0.25rem 1rem" + MarginBottom "1rem" + ] + ] [ + Field.div [ + Field.HasAddons + ] [ Control.div [] [ Dropdown.dropdown [Dropdown.IsActive model.AddBuildingBlockState.ShowBuildingBlockSelection] [ Dropdown.trigger [] [ Button.button [Button.OnClick (fun _ -> ToggleSelectionDropdown |> AddBuildingBlock |> dispatch)] [ - span [] [model.AddBuildingBlockState.CurrentBuildingBlock.Type |> AnnotationBuildingBlockType.toString |> str] + span [Style [MarginRight "5px"]] [model.AddBuildingBlockState.CurrentBuildingBlock.Type |> AnnotationBuildingBlockType.toString |> str] Fa.i [Fa.Solid.AngleDown] [] ] ] @@ -141,6 +149,9 @@ let addBuildingBlockElements (model:Model) (dispatch:Msg -> unit) = Field.div [Field.HasAddons] [ Control.div [] [ Button.a [ + Button.Props [Style [ + if model.AddBuildingBlockState.BuildingBlockHasUnit then Color NFDIColors.Mint.Base else Color NFDIColors.Red.Base + ]] Button.OnClick (fun _ -> let inputId = (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState).InputId if model.AddBuildingBlockState.BuildingBlockHasUnit = true then @@ -148,12 +159,16 @@ let addBuildingBlockElements (model:Model) (dispatch:Msg -> unit) = e?value <- null ToggleBuildingBlockHasUnit |> AddBuildingBlock |> dispatch ) - ] [ - Fa.stack [Fa.Stack.Size Fa.FaSmall; Fa.Stack.Props [Style [ Color "#666666"]]][ - Fa.i [Fa.Regular.Square; Fa.Stack2x][] - if model.AddBuildingBlockState.BuildingBlockHasUnit then - Fa.i [Fa.Solid.Check; Fa.Stack1x][] - ] + ] [ + if model.AddBuildingBlockState.BuildingBlockHasUnit then + Fa.i [ Fa.Size Fa.FaLarge; Fa.Solid.Check ][ ] + else + Fa.i [ Fa.Size Fa.FaLarge ; Fa.Solid.Ban ][ ] + //Fa.stack [Fa.Stack.Size Fa.FaSmall; Fa.Stack.Props [Style [ Color "#666666"]]][ + // Fa.i [Fa.Regular.Square; Fa.Stack2x][] + // if model.AddBuildingBlockState.BuildingBlockHasUnit then + // Fa.i [Fa.Solid.Check; Fa.Stack1x][] + //] ] ] Control.p [] [ @@ -172,60 +187,35 @@ let addBuildingBlockElements (model:Model) (dispatch:Msg -> unit) = (model.AddBuildingBlockState.BuildingBlockHasUnit |> not) ] - a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ - str "Use Advanced Search" - ] - - | _ -> () - ] - -let addUnitToExistingBlockElements (model:Model) (dispatch:Msg -> unit) = - [ - Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Add unit reference columns to existing building block."] - Field.div [Field.HasAddons] [ - Control.p [] [ - Button.button [Button.IsStatic true] [ - str ("Add unit") + div [][ + Help.help [Help.Props [Style [Display DisplayOptions.Inline]]] [ + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockState model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use advanced search building block" + ] ] - ] - AutocompleteSearch.autocompleteTermSearchComponent - dispatch - model.SiteStyleState.ColorMode - model - "Start typing to search" - None - (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnit2State model.AddBuildingBlockState) - // if BuildingBlockHasUnit = false then disabled = true - false - ] - - a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnit2State model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ - str "Use Advanced Search" - ] - ] + match model.AddBuildingBlockState.CurrentBuildingBlock.Type with + | Parameter | Characteristics | Factor -> + str " " -let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = - form [ - OnSubmit (fun e -> e.preventDefault()) - // https://keycode.info/ - OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) - ] [ - Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Annotation building block selection"] - br [] + Help.help [Help.Props [Style [Display DisplayOptions.Inline; Float FloatOptions.Right]]] [ + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnitState model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use advanced search unit" + ] + ] + | _ -> () + ] - // Input forms, etc related to add building block. Except submit button - yield! addBuildingBlockElements model dispatch + | _ -> () - // Fill selection confirmation Field.div [] [ Control.div [] [ Button.button [ let isValid = model.AddBuildingBlockState.CurrentBuildingBlock |> isValidBuildingBlock + Button.Color Color.IsSuccess if isValid then - Button.CustomClass "is-success" Button.IsActive true else - Button.CustomClass "is-danger" + Button.Color Color.IsDanger Button.Props [Disabled true] Button.IsFullWidth Button.OnClick ( @@ -243,22 +233,46 @@ let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = ] ] ] + ] - hr [] - - // Input forms, etc related to add unit to existing building block. Except submit button - - yield! addUnitToExistingBlockElements model dispatch +let addUnitToExistingBlockElements (model:Model) (dispatch:Msg -> unit) = + div [ + Style [ + BorderLeft (sprintf "5px solid %s" NFDIColors.Mint.Base) + //BorderRadius "0 0 15px 15px" + Padding "0.25rem 1rem" + ]] [ + Field.div [Field.HasAddons] [ + Control.p [] [ + Button.button [Button.IsStatic true] [ + str ("Add unit") + ] + ] + AutocompleteSearch.autocompleteTermSearchComponent + dispatch + model.SiteStyleState.ColorMode + model + "Start typing to search" + None + (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnit2State model.AddBuildingBlockState) + // if BuildingBlockHasUnit = false then disabled = true + false + ] + Help.help [Help.Props [Style [Display DisplayOptions.Inline]]] [ + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofAddBuildingBlockUnit2State model.AddBuildingBlockState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use advanced search" + ] + ] Field.div [] [ Control.div [] [ Button.button [ let isValid = model.AddBuildingBlockState.Unit2TermSearchText <> "" + Button.Color Color.IsSuccess if isValid then - Button.CustomClass "is-success" Button.IsActive true else - Button.CustomClass "is-danger" + Button.Color Color.IsDanger Button.Props [Disabled true] Button.IsFullWidth Button.OnClick (fun e -> @@ -274,4 +288,21 @@ let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = ] ] + ] + +let addBuildingBlockComponent (model:Model) (dispatch:Msg -> unit) = + form [ + OnSubmit (fun e -> e.preventDefault()) + // https://keycode.info/ + OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) + ] [ + Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Annotation building block selection"] + + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Select the type of annotation building block (column) to add to the annotation table."] + // Input forms, etc related to add building block. + addBuildingBlockElements model dispatch + + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Add unit reference columns to existing building block."] + // Input forms, etc related to add unit to existing building block. + addUnitToExistingBlockElements model dispatch ] \ No newline at end of file diff --git a/src/Client/Views/BaseView.fs b/src/Client/Views/BaseView.fs index 7c9454e7..33b6bb7e 100644 --- a/src/Client/Views/BaseView.fs +++ b/src/Client/Views/BaseView.fs @@ -34,7 +34,7 @@ let createNavigationTab (pageLink: Routing.Route) (model:Model) (dispatch:Msg-> // str (pageLink |> Routing.Route.toString) //else // pageLink |> Routing.Route.toIcon - span [Class "hideUnder775px"][str (pageLink |> Routing.Route.toString)] + span [Class "hideUnder775px"][str pageLink.toStringRdbl] span [Class "hideOver775px"][pageLink |> Routing.Route.toIcon] ] @@ -47,7 +47,7 @@ let tabRow (model:Model) dispatch (tabs: seq<ReactElement>)= Tabs.Props [ Style [ BackgroundColor model.SiteStyleState.ColorMode.BodyBackground - OverflowX OverflowOptions.Hidden + CSSProp.Custom ("overflow","visible") ] ] ] [ @@ -79,7 +79,17 @@ open Fable.Core.JsInterop /// The base react component for all views in the app. contains the navbar and takes body and footer components to create the full view. let baseViewComponent (model: Model) (dispatch: Msg -> unit) (bodyChildren: ReactElement list) (footerChildren: ReactElement list) = - div [ Style [MinHeight "100vh"; BackgroundColor model.SiteStyleState.ColorMode.BodyBackground; Color model.SiteStyleState.ColorMode.Text;] + div [ + OnClick (fun e -> + if model.TermSearchState.ShowSuggestions + || model.AddBuildingBlockState.ShowUnitTermSuggestions + || model.AddBuildingBlockState.ShowUnit2TermSuggestions + || model.AddBuildingBlockState.ShowBuildingBlockTermSuggestions + then + TopLevelMsg.CloseSuggestions |> TopLevelMsg |> dispatch + ) + Style [MinHeight "100vh"; BackgroundColor model.SiteStyleState.ColorMode.BodyBackground; Color model.SiteStyleState.ColorMode.Text; + ] ] [ Navbar.navbarComponent model dispatch Container.container [ @@ -87,7 +97,7 @@ let baseViewComponent (model: Model) (dispatch: Msg -> unit) (bodyChildren: Reac ] [ br [] firstRowTabs model dispatch - sndRowTabs model dispatch + //sndRowTabs model dispatch if (not model.ExcelState.HasAnnotationTable) then CustomComponents.AnnotationTableMissingWarning.annotationTableMissingWarningComponent model dispatch @@ -100,23 +110,15 @@ let baseViewComponent (model: Model) (dispatch: Msg -> unit) (bodyChildren: Reac br [] - Footer.footer [ Props [ExcelColors.colorControl model.SiteStyleState.ColorMode]] [ - Content.content [ - Content.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Left)] - Content.Props [ExcelColors.colorControl model.SiteStyleState.ColorMode] - ] [ - yield! footerChildren - //Button.button [ - // Button.OnClick (fun e -> - // let e = Browser.Dom.document.getElementById("BlockNameSearch") - // let content = e.innerHTML - // e.innerHTML <- content - // ) - //][ - // str "Test" - //] + if footerChildren.IsEmpty |> not then + Footer.footer [ Props [ExcelColors.colorControl model.SiteStyleState.ColorMode]] [ + Content.content [ + Content.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Left)] + Content.Props [ExcelColors.colorControl model.SiteStyleState.ColorMode] + ] [ + yield! footerChildren + ] ] - ] ] div [Style [Position PositionOptions.Fixed; Bottom "0"; Width "100%"; TextAlign TextAlignOptions.Center; Color "grey"]][ diff --git a/src/Client/Views/FilePickerView.fs b/src/Client/Views/FilePickerView.fs index 4e16106e..e5e2800a 100644 --- a/src/Client/Views/FilePickerView.fs +++ b/src/Client/Views/FilePickerView.fs @@ -414,69 +414,153 @@ let fileElementContainer (model:Model) dispatch = dragAndDropClone model dispatch (ele) ] -let filePickerComponent (model:Model) (dispatch:Msg -> unit) = - let inputId = "filePicker_OnFilePickerMainFunc" - Content.content [ Content.Props [colorControl model.SiteStyleState.ColorMode ]] [ - Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "File Picker"] - File.file [] [ - File.label [] [ - File.input [ - Props [ - Id inputId - Multiple true - OnChange (fun ev -> - - let files : FileList = ev.target?files - - let fileNames = - [ for i=0 to (files.length - 1) do yield files.item i ] - |> List.map (fun f -> f.name) - - fileNames |> LoadNewFiles |> FilePicker |> dispatch - - let picker = Browser.Dom.document.getElementById(inputId) - // https://stackoverflow.com/questions/3528359/html-input-type-file-file-selection-event/3528376 - picker?value <- null - ) - ] - ] - File.cta [] [ - File.icon [] [ - Fa.i [ - Fa.Solid.Upload - ] [] - ] - File.name [Props [Style [BorderRight "none"]]] [ - str "Chose one or multiple files" - ] +let uploadButton (model:Model) dispatch inputId = + File.file [ + File.Color IsInfo + File.IsCentered + File.Props [Style [Margin "1rem 0"]] + ] [ + File.label [ Props [Style [Width "100%"]] ] [ + File.input [ + Props [ + Id inputId + Multiple true + OnChange (fun ev -> + + let files : FileList = ev.target?files + + let fileNames = + [ for i=0 to (files.length - 1) do yield files.item i ] + |> List.map (fun f -> f.name) + + fileNames |> LoadNewFiles |> FilePicker |> dispatch + + let picker = Browser.Dom.document.getElementById(inputId) + // https://stackoverflow.com/questions/3528359/html-input-type-file-file-selection-event/3528376 + picker?value <- null + ) ] ] + File.cta [ Props [Style [Width "100%"; JustifyContent "center" ]] ] [ + File.icon [] [ Fa.i [ Fa.Solid.Upload ] [] ] + File.label [ ] [ str "Pick file names" ] + ] ] + ] - div [ - Style [Margin "1rem auto"] - ][ - if model.FilePickerState.FileNames = [] then - str "Here you can select files from your computer to insert their names into a Swate column." - else - fileElementContainer model dispatch - ] +let fileNameElements (model:Model) dispatch = + div [ ][ + if model.FilePickerState.FileNames <> [] then + fileElementContainer model dispatch + + Button.a [ + Button.IsFullWidth + if model.FilePickerState.FileNames |> List.isEmpty then + yield! [ + Button.Disabled true + Button.IsActive false + Button.Color Color.IsDanger + ] + else + Button.Color Color.IsSuccess + Button.OnClick (fun e -> + (fun tableName -> InsertFileNames (tableName, model.FilePickerState.FileNames |> List.map snd)) |> PipeActiveAnnotationTable |> ExcelInterop |> dispatch + ) + + ][ + str "Insert File Names" + ] + else + div [][ + str "All names from your selected files will be displayed here." + ] + ] + +let sortButton icon msg = + Button.a [ + Button.IsOutlined + Button.Color IsPrimary + Button.OnClick msg + ][ + Fa.i [ Fa.Size Fa.FaLarge; icon ] [ ] + ] + +let fileSortElements (model:Model) dispatch = + div [Style [MarginBottom "1rem"; Display DisplayOptions.Flex]][ Button.a [ - Button.IsFullWidth - if model.FilePickerState.FileNames |> List.isEmpty then - yield! [ - Button.Disabled true - Button.IsActive false - Button.Color Color.IsDanger - ] - else - Button.Color Color.IsSuccess + Button.IsOutlined + Button.Color IsPrimary Button.OnClick (fun e -> - (fun tableName -> InsertFileNames (tableName, model.FilePickerState.FileNames |> List.map snd)) |> PipeActiveAnnotationTable |> ExcelInterop |> dispatch + let txt = model.FilePickerState.FileNames |> List.map snd |> String.concat System.Environment.NewLine + let textArea = Browser.Dom.document.createElement "textarea" + textArea?value <- txt + textArea?style?top <- "0" + textArea?style?left <- "0" + textArea?style?position <- "fixed" + + Browser.Dom.document.body.appendChild textArea |> ignore + + textArea.focus() + /// Can't belive this actually worked + textArea?select() + + let t = Browser.Dom.document.execCommand("copy") + Browser.Dom.document.body.removeChild(textArea) |> ignore + () ) + ][ + Fa.i [Fa.Props [Title "Copy to Clipboard"]; Fa.Regular.Clipboard ] [] + ] + Button.list [ + Button.List.HasAddons + Button.List.Props [Style [MarginLeft "auto"]] ][ - str "Insert File Names" + sortButton Fa.Solid.SortAlphaDown (fun e -> + let sortedList = model.FilePickerState.FileNames |> List.sortBy snd |> List.mapi (fun i x -> i,snd x) + UpdateFileNames sortedList |> FilePicker |> dispatch + ) + sortButton Fa.Solid.SortAlphaDownAlt (fun e -> + let sortedList = model.FilePickerState.FileNames |> List.sortByDescending snd |> List.mapi (fun i x -> i,snd x) + UpdateFileNames sortedList |> FilePicker |> dispatch + ) + ] + ] + +let fileContainer (model:Model) dispatch inputId= + div [ + Style [ + BorderLeft (sprintf "5px solid %s" NFDIColors.Mint.Base) + //BorderRadius "15px 15px 0 0" + Padding "0.25rem 1rem" + MarginBottom "1rem" ] + ][ + fileSortElements model dispatch + + fileNameElements model dispatch + ] + +let filePickerComponent (model:Model) (dispatch:Msg -> unit) = + let inputId = "filePicker_OnFilePickerMainFunc" + Content.content [ ] [ + Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "File Picker"] + + Help.help [][ + b [] [ str "Choose one or multiple files, rearrange them and add their names to the Excel sheet."] + str " You can use " + u [][str "drag'n'drop"] + str " to change the file order or remove files selected by accident." + ] + + uploadButton model dispatch inputId + + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [ + str "Select files from your computer and insert their names into Excel." + ] + + /// COlored container element for all uploaded file names and sort elements + fileContainer model dispatch inputId + ] \ No newline at end of file diff --git a/src/Client/Views/InfoView.fs b/src/Client/Views/InfoView.fs index 4d627451..e10b3e1e 100644 --- a/src/Client/Views/InfoView.fs +++ b/src/Client/Views/InfoView.fs @@ -47,55 +47,80 @@ let introductionElement model dispatch = ] ] + + let getInContactElement (model:Model) dispatch = [ Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent; MarginLeft "7%"]]] [str "Get In Contact With Us"] - + Columns.columns [Columns.Props [Style [MaxWidth "80%"; Margin "0 auto"]]][ Column.column [][ Heading.h5 [Heading.IsSubtitle; Heading.Props [Style [Color model.SiteStyleState.ColorMode.Text]]][ - str "Got a good idea or just want to get in touch? Reach out to us! " - div [] [a [Href Shared.URLs.CSBTwitterUrl; Target "_Blank"][str "#Twitter @cs_biology"]] + str "Swate is part of the dataPLANT organisation." ] - ] - Column.column [Column.Width (Screen.All, Column.IsOneFifth); Column.CustomClass "flexToCentered"][ - a [Href Shared.URLs.CSBTwitterUrl; Target "_Blank"][ - Fa.i [ - Fa.Size Fa.Fa4x - Fa.Brand.Twitter - Fa.CustomClass "myFaBrand myFaTwitter" - ][] + Content.content [][ + blockquote [][ + str "Services and infrastructures to support " + a [Href "https://twitter.com/search?q=%23FAIRData&src=hashtag_click"][ str "#FAIRData" ] + str " science and good data management practices within the plant basic research community. " + a [Href "https://twitter.com/search?q=%23NFDI&src=hashtag_click"] [ str "#NFDI" ] + str "." + ] ] ] - ] - - Columns.columns [Columns.Props [Style [MaxWidth "80%"; Margin "0 auto"]]][ - Column.column [Column.Width (Screen.All, Column.IsOneFifth); Column.CustomClass "hideUnder775px"][ - a [Href Shared.URLs.CSBWebsiteUrl; Target "_Blank"][ - Fa.i [ - Fa.CustomClass "myFaBrand myFaCSB" - ][ - str "CSB" + Column.column [Column.Width (Screen.All, Column.IsNarrow); Column.CustomClass "flexToCentered"][ + a [Href "https://nfdi4plants.de/"; Target "_Blank"; Class "nfdiIcon" ] [ + Fulma.Image.image [][ + img [Src "https://raw.githubusercontent.com/nfdi4plants/Branding/138420e3b6f9ec9e125c1ca8840874b2be2a1262/logos/DataPLANT_logo_minimal_square_bg_darkblue.svg"] ] ] ] + ] + + Columns.columns [Columns.Props [Style [MaxWidth "80%"; Margin "0 auto"]]][ Column.column [][ Heading.h5 [Heading.IsSubtitle; Heading.Props [Style [Color model.SiteStyleState.ColorMode.Text]]][ - str "If you are interested in our other work, check out our " - b [][str "website"] - str "!" + str "Got a good idea or just want to get in touch? Reach out to us! " + div [] [a [Href Shared.URLs.NFDITwitterUrl; Target "_Blank"][str "#Twitter @nfdi4plants"]] ] ] - Column.column [Column.Width (Screen.All, Column.IsOneFifth); Column.CustomClass "flexToCentered hideOver775px"][ - a [Href Shared.URLs.CSBWebsiteUrl; Target "_Blank"][ + Column.column [Column.Width (Screen.All, Column.IsNarrow); Column.CustomClass "flexToCentered"][ + a [Href Shared.URLs.NFDITwitterUrl; Target "_Blank"][ Fa.i [ - Fa.CustomClass "myFaBrand myFaCSB" - ][ - str "CSB" - ] + Fa.Size Fa.Fa4x + Fa.Brand.Twitter + Fa.CustomClass "myFaBrand myFaTwitter" + ][] ] ] ] + + //Columns.columns [ + // Columns.Props [Style [MaxWidth "80%"; Margin "0 auto"]] + // Columns.CustomClass "reverseCols" + //][ + // Column.column [ + // Column.Width (Screen.All, Column.IsNarrow) + // Column.CustomClass "flexToCentered" + // ][ + // a [ + // Href Shared.URLs.CSBWebsiteUrl; Target "_Blank" + // ][ + // Fa.i [ + // Fa.CustomClass "myFaBrand myFaCSB" + // ][ + // str "CSB" + // ] + // ] + // ] + // Column.column [][ + // Heading.h5 [Heading.IsSubtitle; Heading.Props [Style [Color model.SiteStyleState.ColorMode.Text]]][ + // str "If you are interested in our other work, check out our " + // b [][str "website"] + // str "!" + // ] + // ] + //] Columns.columns [Columns.Props [Style [MaxWidth "80%"; Margin "0 auto"]]][ Column.column [][ @@ -106,7 +131,7 @@ let getInContactElement (model:Model) dispatch = ] ] - Column.column [Column.Width (Screen.All, Column.IsOneFifth); Column.CustomClass "flexToCentered"][ + Column.column [Column.Width (Screen.All, Column.IsNarrow); Column.CustomClass "flexToCentered"][ a [Href "https://github.com/nfdi4plants/Swate/issues"; Target "_Blank"][ Fa.i [ Fa.Brand.Github diff --git a/src/Client/Views/SettingsView.fs b/src/Client/Views/SettingsView.fs index 0e1c4651..6781f304 100644 --- a/src/Client/Views/SettingsView.fs +++ b/src/Client/Views/SettingsView.fs @@ -19,18 +19,18 @@ let toggleDarkModeElement (model:Model) dispatch = str "Darkmode" ] Level.right [ Props [ Style [if model.SiteStyleState.IsDarkMode then Color model.SiteStyleState.ColorMode.Text else Color model.SiteStyleState.ColorMode.Fade]]] [ - Switch.switchInline [ + Switch.switch [ Switch.Id "DarkModeSwitch" Switch.IsOutlined Switch.Color IsSuccess Switch.OnChange (fun _ -> ToggleColorMode |> StyleChange |> dispatch) - ] [span [Class "nonSelectText"][str "DarkMode"]] + ] [] ] ] let settingsViewComponent (model:Model) dispatch = div [ - + Style [MaxWidth "500px"] ][ Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Swate Settings"] Label.label [][str "Customize Swate"] diff --git a/src/Client/Views/TermSearchView.fs b/src/Client/Views/TermSearchView.fs index d71a377a..a850b9aa 100644 --- a/src/Client/Views/TermSearchView.fs +++ b/src/Client/Views/TermSearchView.fs @@ -27,7 +27,7 @@ open CustomComponents // td [] [ // b [] [str sugg.Name] // ] -// td [Style [Color "red"]] [if sugg.IsObsolete then str "obsolete"] +// td [Style [Color ""]] [if sugg.IsObsolete then str "obsolete"] // td [Style [FontWeight "light"]] [small [] [str sugg.Accession]] // ]) // |> List.ofArray @@ -43,82 +43,104 @@ open Fable.Core open Fable.Core.JsInterop let simpleSearchComponent (model:Model) (dispatch: Msg -> unit) = - Field.div [] [ - - Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Ontology term search"] - br [] - - Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Search for an ontology term to fill into the selected field(s)"] - AutocompleteSearch.autocompleteTermSearchComponentOfParentOntology - dispatch - model.SiteStyleState.ColorMode - model - "Start typing to search for terms" - (Some Size.IsLarge) - (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState) - - Field.div [][ - Switch.switch [ - Switch.Color IsSuccess - Switch.IsOutlined - Switch.Id "switch-1" - Switch.Checked model.TermSearchState.SearchByParentOntology - Switch.OnChange (fun e -> - ToggleSearchByParentOntology |> TermSearch |> dispatch - // this one is ugly, what it does is: Do the related search after toggling directed search (by parent ontology) of/on. - ((AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState).OnInputChangeMsg model.TermSearchState.TermSearchText) |> dispatch - ) - ] [ str "Use related term directed search." ] + div [ + Style [ + BorderLeft (sprintf "5px solid %s" NFDIColors.Mint.Base) + //BorderRadius "15px 15px 0 0" + Padding "0.25rem 1rem" + MarginBottom "1rem" ] - a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState).ModalId |> AdvancedSearch |> dispatch)] [ - str "Use Advanced Search" - ] - - //Control.div [] [ - - //Input.input [ Input.Placeholder "Start typing to start search" - // Input.Size Size.IsLarge - // Input.Props [ExcelColors.colorControl model.SiteStyleState.ColorMode] - // Input.OnChange (fun e -> e.Value |> SearchTermTextChange |> Simple |> TermSearch |> dispatch) - // Input.Value model.TermSearchState.Simple.TermSearchText - // ] - //AutocompleteDropdown.autocompleteDropdownComponent - // model - // dispatch - // model.TermSearchState.Simple.ShowSuggestions - // model.TermSearchState.Simple.HasSuggestionsLoading - // (createTermSuggestions model dispatch) - //] - ] - + ] [ + Field.div [] [ + AutocompleteSearch.autocompleteTermSearchComponentOfParentOntology + dispatch + model.SiteStyleState.ColorMode + model + "Start typing to search for terms" + (Some Size.IsLarge) + (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState) + + div [][ + Switch.switchInline [ + Switch.Color IsPrimary + Switch.Id "switch-1" + Switch.Checked model.TermSearchState.SearchByParentOntology + Switch.OnChange (fun e -> + ToggleSearchByParentOntology |> TermSearch |> dispatch + let _ = + let inpId = (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState).InputId + let e = Browser.Dom.document.getElementById inpId + e.focus() + () + // this one is ugly, what it does is: Do the related search after toggling directed search (by parent ontology) of/on. + //((AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState).OnInputChangeMsg model.TermSearchState.TermSearchText) |> dispatch + ) + ] [ str "Use related term directed search." ] + + Help.help [ Help.Props [Style [Display DisplayOptions.Inline; Float FloatOptions.Right]] ][ + a [OnClick (fun _ -> ToggleModal (AutocompleteSearch.AutocompleteParameters<DbDomain.Term>.ofTermSearchState model.TermSearchState).ModalId |> AdvancedSearch |> dispatch)] [ + str "Use advanced search" + ] + ] + ] -let termSearchComponent (model : Model) (dispatch : Msg -> unit) = - form [ - OnSubmit (fun e -> e.preventDefault()) - OnKeyDown (fun k -> if (int k.which) = 13 then k.preventDefault()) - ] [ - simpleSearchComponent model dispatch + //Control.div [] [ + + //Input.input [ Input.Placeholder "Start typing to start search" + // Input.Size Size.IsLarge + // Input.Props [ExcelColors.colorControl model.SiteStyleState.ColorMode] + // Input.OnChange (fun e -> e.Value |> SearchTermTextChange |> Simple |> TermSearch |> dispatch) + // Input.Value model.TermSearchState.Simple.TermSearchText + // ] + //AutocompleteDropdown.autocompleteDropdownComponent + // model + // dispatch + // model.TermSearchState.Simple.ShowSuggestions + // model.TermSearchState.Simple.HasSuggestionsLoading + // (createTermSuggestions model dispatch) + //] + ] // Fill selection confirmation Field.div [] [ Control.div [] [ - Button.button [ + Button.a [ let hasText = model.TermSearchState.TermSearchText.Length > 0 if hasText then Button.CustomClass "is-success" Button.IsActive true else Button.CustomClass "is-danger" - Button.Props [Disabled true] + Button.Props [ + Disabled (not hasText) + //Style [Flex "1"] + ] Button.IsFullWidth - Button.OnClick (fun _ -> (model.TermSearchState.TermSearchText,model.TermSearchState.SelectedTerm) |> pipeNameTuple2 FillSelection |> ExcelInterop |> dispatch) + Button.OnClick (fun _ -> + if hasText then + (model.TermSearchState.TermSearchText,model.TermSearchState.SelectedTerm) |> pipeNameTuple2 FillSelection |> ExcelInterop |> dispatch + ) ] [ str "Fill selected cells with this term" - ] ] ] + ] + + + +let termSearchComponent (model : Model) (dispatch : Msg -> unit) = + form [ + OnSubmit (fun e -> e.preventDefault()) + OnKeyDown (fun k -> if (int k.which) = 13 then k.preventDefault()) + ] [ + + Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]][ str "Ontology term search"] + + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [str "Search for an ontology term to fill into the selected field(s)"] + + simpleSearchComponent model dispatch //if model.TermSearchState.SelectedTerm.IsNone then // str "No Term Selected" diff --git a/src/Client/Views/ValidationView.fs b/src/Client/Views/ValidationView.fs index 2bcf9eea..e7f4e464 100644 --- a/src/Client/Views/ValidationView.fs +++ b/src/Client/Views/ValidationView.fs @@ -25,11 +25,15 @@ let columnListElement ind (columnValidation:ColumnValidation) (model:Model) disp | _ -> false tr [ - Class "nonSelectText" + /// Remove validationTableEle when active to remove on-hover color change to really light grey. + if isActive then + Class "nonSelectText" + else + Class "nonSelectText validationTableEle" Style [ Cursor "pointer" UserSelect UserSelectOptions.None - if model.ValidationState.DisplayedOptionsId.IsSome && model.ValidationState.DisplayedOptionsId.Value = ind then + if isActive then BackgroundColor model.SiteStyleState.ColorMode.ElementBackground Color "white" ] @@ -46,13 +50,13 @@ let columnListElement ind (columnValidation:ColumnValidation) (model:Model) disp if columnValidation.Importance.IsSome then str (string columnValidation.Importance) else - str "X" + str "-" ] td [][ if columnValidation.ValidationFormat.IsSome then str columnValidation.ValidationFormat.Value.toReadableString else - str "X" + str "-" ] td [][ Icon.icon [][ @@ -92,7 +96,7 @@ let checkradioElement (id:int) (contentTypeOpt:ContentType option) (columnValida //][ // str contentType //] - let isDisabled = (contentType = "Ontology [None]") + let isDisabled = (contentType = "Ontology [None]" || contentType = "Unit [None]") div [Style [Position PositionOptions.Relative]] [ input [ Type "checkbox"; @@ -122,8 +126,21 @@ let checkradioElement (id:int) (contentTypeOpt:ContentType option) (columnValida ][] ] -let checkradioList (ind:int) (hasOntology:string option) colVal model dispatch = - let ontologyContent = if hasOntology.IsSome then ContentType.OntologyTerm hasOntology.Value |> Some else ContentType.OntologyTerm "None" |> Some +let findOntology (columnValidation:ColumnValidation) (buildingBlocks:OfficeInterop.Types.BuildingBlockTypes.BuildingBlock []) = + buildingBlocks + |> Array.find (fun x -> x.MainColumn.Header.Value.Header = columnValidation.ColumnHeader) + |> fun x -> x.MainColumn.Header.Value.Ontology + +let checkradioList (ind:int) colVal model dispatch = + let hasOntology = findOntology colVal model.ValidationState.ActiveTableBuildingBlocks + + let unitContent = + if colVal.Unit.IsSome then ContentType.UnitTerm colVal.Unit.Value |> Some else ContentType.UnitTerm "None" |> Some + + let ontologyContent = + if hasOntology.IsSome then ContentType.OntologyTerm hasOntology.Value |> Some else ContentType.OntologyTerm "None" |> Some + + [ checkradioElement ind None colVal model dispatch @@ -134,15 +151,12 @@ let checkradioList (ind:int) (hasOntology:string option) colVal model dispatch = checkradioElement ind (Some ContentType.Url) colVal model dispatch checkradioElement ind ontologyContent colVal model dispatch + checkradioElement ind unitContent colVal model dispatch ] -let findOntology (columnValidation:ColumnValidation) (buildingBlocks:OfficeInterop.Types.BuildingBlockTypes.BuildingBlock []) = - buildingBlocks - |> Array.find (fun x -> x.MainColumn.Header.Value.Header = columnValidation.ColumnHeader) - |> fun x -> x.MainColumn.Header.Value.Ontology -let sliderElements id format dispatch = - let defaultSliderVal = string (if format.Importance.IsSome then format.Importance.Value else 0) +let sliderElements id columnValidation model dispatch = + let defaultSliderVal = string (if columnValidation.Importance.IsSome then columnValidation.Importance.Value else 0) let sliderId = sprintf "importanceSlider%i" id let outputSliderId = sprintf "outputForImportanceSlider%i" id [ @@ -158,9 +172,17 @@ let sliderElements id format dispatch = // this is used to quickly update the label element to the right of the slider with t he new value let sliderEle = Browser.Dom.document.getElementById(outputSliderId) let _ = sliderEle.textContent <- (if e.Value = "0" then "None" else e.Value) - () + /// Previously this appeared rather laggy, but now it seems to work fine. + let nextColumnValidation = { + columnValidation with + Importance = if e.Value = "0" then None else int e.Value |> Some + } + let nextTableValidation = + updateTableValidationByColValidation model nextColumnValidation + UpdateTableValidationScheme nextTableValidation |> Validation |> dispatch + //() ) - Slider.Color IsSuccess + Slider.Color IsPrimary Slider.ValueOrDefault defaultSliderVal ] output [Props.HtmlFor sliderId; Id outputSliderId; Style [TextOverflow "unset"]] [ @@ -170,46 +192,50 @@ let sliderElements id format dispatch = open Fable.Core.JsInterop -/// Submit button to apply slider changes to model. If slider.OnChange would dispatch message the app would suffer from lag spikes. -let submitButton ind columnValidation (model:Model) dispatch = - Button.span [ - Button.Color IsSuccess - Button.IsOutlined - Button.OnClick ( - fun e -> - let sliderId = sprintf "importanceSlider%i" ind - let sliderEle = Browser.Dom.document.getElementById(sliderId) - let impoValue = sliderEle?value - printfn "%s" impoValue - let nextColumnValidation = { - columnValidation with - Importance = if impoValue = "0" then None else int impoValue |> Some - } - let nextTableValidation = - updateTableValidationByColValidation model nextColumnValidation - UpdateTableValidationScheme nextTableValidation |> Validation |> dispatch - ) - ][ - str "Submit Importance" - ] + +///// Submit button to apply slider changes to model. If slider.OnChange would dispatch message the app would suffer from lag spikes. +///// EDIT: This problem appearently disappeared. For now we will test it with only slider +//let submitButton ind (columnValidation:ColumnValidation) (model:Model) dispatch = +// Button.span [ +// Button.IsFullWidth +// Button.Color IsPrimary +// //Button.IsStatic isSame +// Button.OnClick ( +// fun e -> +// let sliderId = sprintf "importanceSlider%i" ind +// let sliderEle = Browser.Dom.document.getElementById(sliderId) +// let impoValue = sliderEle?value +// let nextColumnValidation = { +// columnValidation with +// Importance = if impoValue = "0" then None else int impoValue |> Some +// } +// let nextTableValidation = +// updateTableValidationByColValidation model nextColumnValidation +// UpdateTableValidationScheme nextTableValidation |> Validation |> dispatch +// ) +// ][ +// str "Submit Importance" +// ] let optionsElement ind (columnValidation:ColumnValidation) (model:Model) dispatch = - let hasOntology = findOntology columnValidation model.ValidationState.ActiveTableBuildingBlocks let isVisible = match model.ValidationState.DisplayedOptionsId with | Some id when id = ind -> - DisplayOptions.Block + true | _ -> - DisplayOptions.None + false tr [][ td [ ColSpan 4 - Style [Padding "0"] + Style [ + Padding "0"; + if isVisible then BorderBottom (sprintf "2px solid %s" ExcelColors.colorfullMode.Accent) + ] ][ Box.box' [ Props [ Style [ - Display isVisible + Display (if isVisible then DisplayOptions.Block else DisplayOptions.None) Width "100%" ] ] @@ -220,7 +246,7 @@ let optionsElement ind (columnValidation:ColumnValidation) (model:Model) dispatc Help.help [Help.Props [Style [MarginBottom "1rem"]]][str "Select the specific type of content for the selected column."] - yield! checkradioList ind hasOntology columnValidation model dispatch + yield! checkradioList ind columnValidation model dispatch ] Column.column [][ @@ -228,41 +254,27 @@ let optionsElement ind (columnValidation:ColumnValidation) (model:Model) dispatc Help.help [][str "Define how important it is to fill in the column correctly."] - yield! sliderElements ind columnValidation dispatch + yield! sliderElements ind columnValidation model dispatch - submitButton ind columnValidation model dispatch + //submitButton ind columnValidation model dispatch ] ] ] ] ] - -let validationComponent model dispatch = - form [ - OnSubmit (fun e -> e.preventDefault()) - // https://keycode.info/ - OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) - ] [ - Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [ str "Table Validation"] - - //Help.help [Help.Color IsDanger] [ - // str "This is currently a preview feature and is still missing a lot of features. See " - // a [Href "https://github.com/nfdi4plants/Swate/issues/45"; Target "_Blank"][str "here"] - // str " for the newst updates on this feature." - //] - +let validationElements (model:Model) dispatch = + div [ + Style [ + BorderLeft (sprintf "5px solid %s" NFDIColors.Mint.Base) + //BorderRadius "15px 15px 0 0" + Padding "0.25rem 1rem" + MarginBottom "1rem" + ] + ][ Field.div [Field.Props [Style [ Width "100%" ]]] [ - Button.a [ - Button.Color Color.IsInfo - Button.IsFullWidth - Button.OnClick (fun e -> PipeActiveAnnotationTable GetTableValidationXml |> ExcelInterop |> dispatch ) - Button.Props [Style [MarginBottom "1rem"]] - ] [ - str "Update Table Representation" - ] // Worksheet - annotationTable name - DateTime of saving div [ Id "TableRepresentationInfoHeader" @@ -272,13 +284,20 @@ let validationComponent model dispatch = header?style?transition <- "unset" ) ][ - b [][ - str model.ValidationState.TableValidationScheme.WorksheetName - ] + b [][ str model.ValidationState.TableValidationScheme.WorksheetName ] str " - " str model.ValidationState.TableValidationScheme.TableName str " - " str ( model.ValidationState.TableValidationScheme.DateTime.ToString("yyyy-MM-dd HH:mm") ) + str " - " + str ( + sprintf "Swate %s" ( + if model.ValidationState.TableValidationScheme.SwateVersion = "" then + model.PersistentStorageState.AppVersion + else + model.ValidationState.TableValidationScheme.SwateVersion + ) + ) ] Table.table [ Table.IsHoverable; Table.IsFullWidth ] [ thead [ ] [ @@ -298,6 +317,13 @@ let validationComponent model dispatch = ] ] ] + + /// Show warning if no validation format was found + if model.ValidationState.TableValidationScheme.SwateVersion = "" then + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color NFDIColors.Red.Lighter10]]][ + str """No validation format for this table found! Hit "Add validation to workbook" to add a validation format for the active annotation table.""" + ] + // Submit new validation scheme. This will write custom xml into the workbook. Button.a [ Button.Color Color.IsSuccess @@ -308,9 +334,47 @@ let validationComponent model dispatch = header?style?opacity <- 0 WriteTableValidationToXml (model.ValidationState.TableValidationScheme, model.PersistentStorageState.AppVersion) |> ExcelInterop |> dispatch ) - Button.Props [Style [MarginBottom "1rem"]] + Button.Props [Tooltip.dataTooltip "Write validation info to excel worksheet."] + Button.CustomClass (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) ] [ str "Add validation to workbook" ] ] + ] + +let validationComponent model dispatch = + form [ + OnSubmit (fun e -> e.preventDefault()) + // https://keycode.info/ + OnKeyDown (fun k -> if k.key = "Enter" then k.preventDefault()) + ] [ + Label.label [Label.Size Size.IsLarge; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [ str "Table Validation"] + + Help.help [][ + str "Display a table representation and add information to later validate values in the table according to their respective column." + ] + + Button.a [ + Button.Color Color.IsInfo + Button.IsFullWidth + Button.OnClick (fun e -> PipeActiveAnnotationTable GetTableValidationXml |> ExcelInterop |> dispatch ) + Button.CustomClass (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) + Button.Props [Style [Margin "1rem 0"]; Tooltip.dataTooltip "Get validation info for currently shown annotation table."] + ] [ + str "Update table representation" + ] + + Label.label [Label.Size Size.IsSmall; Label.Props [Style [Color model.SiteStyleState.ColorMode.Accent]]] [ + str """Adjust current Swate table validation. """ + span [ + Class (Tooltip.ClassName + " " + Tooltip.IsTooltipBottom + " " + Tooltip.IsMultiline) + Tooltip.dataTooltip """When hitting "Add validation to workbook" this information will be saved as part of the workbook.""" + Style [Color NFDIColors.LightBlue.Base; MarginLeft ".5rem"] + ][ + Fa.i [ Fa.Solid.InfoCircle ][] + ] + ] + + validationElements model dispatch + ] \ No newline at end of file diff --git a/src/Client/index.html b/src/Client/index.html index c815a066..bad6701e 100644 --- a/src/Client/index.html +++ b/src/Client/index.html @@ -1,16 +1,17 @@ <!doctype html> <html> <head> - <title>SAFE Template + Swate - - + +