From b962c516ef34fc2a22e6465985a9014f647f66b0 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Thu, 24 Oct 2024 15:35:47 -0700 Subject: [PATCH 01/23] fix #154 navbar changes - add logo in upper left - black navbar - click proof to get to landing page - resources tab name change and placement --- app/buttons.R | 2 ++ app/server.R | 4 ++-- app/tab-welcome.R | 4 ++-- app/ui.R | 23 ++++++++++++++++------- app/www/fred-hutch.png | Bin 0 -> 15175 bytes 5 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 app/www/fred-hutch.png diff --git a/app/buttons.R b/app/buttons.R index 1f2fc9f..30d3665 100644 --- a/app/buttons.R +++ b/app/buttons.R @@ -3,6 +3,7 @@ logInButton <- inputId = "proofAuth", label = "PROOF Login", class = "btn-sm", + style = "color: white;", icon = icon("truck-fast") ) @@ -20,6 +21,7 @@ logInCromwellButton <- inputId = "ownCrom", label = "DIY Cromwell", class = "btn-sm", + style = "color: white;", icon = icon("plug-circle-xmark") ) logOutCromwellButton <- diff --git a/app/server.R b/app/server.R index 2167472..a4d0604 100644 --- a/app/server.R +++ b/app/server.R @@ -633,8 +633,8 @@ server <- function(input, output, session) { observeEvent(input$linkToTroubleshootingTab, { nav_select("proof", "Troubleshoot") }) - observeEvent(input$linkToResourcesTab, { - nav_select("proof", "Resources") + observeEvent(input$linkToHelpTab, { + nav_select("proof", "Help") }) ### go back to tracking tab from details tab diff --git a/app/tab-welcome.R b/app/tab-welcome.R index dae26d1..d53b619 100644 --- a/app/tab-welcome.R +++ b/app/tab-welcome.R @@ -3,7 +3,7 @@ ablank <- function(...) { } tab_welcome <- nav_panel( - title = "Welcome", + title = "PROOF", card( card_body( div( @@ -46,7 +46,7 @@ tab_welcome <- nav_panel( ) ), h4("To learn more about PROOF and WDL head over to the ", - actionLink("linkToResourcesTab", "Resources page") + actionLink("linkToHelpTab", "Help page") ) ) ) diff --git a/app/ui.R b/app/ui.R index 666aaf3..f7f9ca7 100644 --- a/app/ui.R +++ b/app/ui.R @@ -30,15 +30,19 @@ source("tab-details.R") ui <- cookies::add_cookie_handlers( page_navbar( id = "proof", - title = "PROOF", - bg = "#0062cc", + title = tags$span( + tags$img( + src = "fred-hutch.png", + width = "96px", + height = "auto", + class = "me-3", + alt = "Fred Hutch logo" + ), + "" + ), + bg = "#000000", underline = TRUE, tab_welcome, - nav_panel(title = "Resources", - card( - shiny::includeMarkdown("about.md") - ) - ), nav_panel(title = "Server", tab_servers), nav_panel(title = "Validate", tab_validate, shinyjs::useShinyjs()), nav_panel(title = "Submit", tab_submission, shinyjs::useShinyjs()), @@ -49,6 +53,11 @@ ui <- cookies::add_cookie_handlers( ) ), nav_panel(title = "Troubleshoot", tab_troublehsoot, shinyjs::useShinyjs()), + nav_panel(title = "Help", + card( + shiny::includeMarkdown("about.md") + ) + ), nav_spacer(), nav_item( uiOutput("userName") diff --git a/app/www/fred-hutch.png b/app/www/fred-hutch.png new file mode 100644 index 0000000000000000000000000000000000000000..70a53bb8257598217703ab505f93a705f0554578 GIT binary patch literal 15175 zcmc(`^T}#IjOQ=XlcL_*$cOxv_-QC??ck%tX z-~Zsg?*8!XzUIuCGiPSboQY=xKFfnKUy{58005ZMQsPPg0Ln7r_YT@~#Irv}yaw?_ z>?on(sBB~62-UYY27ENKF)*f*w$e8>Rx;K%a<%I=761VFwxz{Cs<_PTCEcse_DuNs z72J7wF!FqQ#)dDhf}@O-h5QFu_F34=JrzJMKp9E?*_Dd7&9jD?lIYb~ONeC?C#~S1 zmev|dZ+fAi`-P2AFcM*dnQZv@0*V+)>*J-$AEj=YuK=n?p7MsMX)=;rKLzY1XpazdmCb-X@l>Zv%U_$pO z692K2pfWky>zsUc`8*)1zMyE9+}N|A$WFA1!ZN<dIdcL?)3gKHHt>;UbLhQH{;Rq{<90mK0;YHT=+sd<*+V(rpK46b|ED<`GWOR?KVKj0bbuD`Mmd35BT?s1mG@c57gE?~2EIpOOf25Lmc8XGj3 zNelm31`x~Le^BRu^mE_DZ^Xc1&4+&kX~<5NwXrUPsZ4(A`x>*@>HmX@^Q^T|o!?60 zmg_yUg0o}W{vTK@{=|d!m!=Jzg`++LDCN0#=(w+D`yV z5#-^C`}$GDN6eZ@Hg4FKL4PVDPIrCE{4p!5sZI{oFA1FY(_k-2C+a3w7gv_%!v8a0#3CiyWUhxi@c(#e!1(W|`MK;{!C~ z(QSv%*?$n4_)fog!t+LZfla158JV7=v+ZGzR}Oyh;zfQ?52T_`W)8&nsN$Sr_;lC- zX0Ni+p{V$&ejT2Ew%2p|z6KX*-BAbPJ+K~5$0q~;LX52N*bOVX+pJ~q`Xy;_A3dFk zsV)o0zfr1IYAb3M{={CbRaV9#VcZFs`$yK3TjCIJ+LnKNq2kxTThL`=p}7@h1*Wdg zJoZ~11_Hp||HKZUA#)BqsofRCSwee~r8g$V2c(vV59H+k0{{qpK29+2dX88wWkz-aIT;ceCQO zn^I3J16AF?rWrKA1B0~`Ov2m78rpQw1%BiEkSzsoJ z67y-Rf)`*a1_EAmWtYyqoyfcS5UP>oHr)puz4QOAfRk2`J(6{2f=#we*8x_T$WN8xk46kW2Q%nIwtOJF_ph(WDUPSaG7bGX*vnUCRVwrq`-Ee(VhA=_ags*Fd#}NPaQ`Ly~YC3eqbS*+{gpp_#Jzi+)j;d zHNQG<;IY*HMLtz=lVwq@E5U_#4ZTF4i5ux8g&Z9eIeH4NTB&2f5EWQTwTchB@ht$b=b!4tV3N3UE4azX z0w$ieO9L@!UERp+F0_ZAX7Ema0!Bw|;Ghq6GRAwfvHzrWgf(5Ei7&-5 z2royQ61`^^-VaR{wW*hXjDf}_Y$aLjJqJiNG7E6;2hV}@f0xyaRq;nxnZ=d;n@st1 zJ{L7Mks&C>c^y`1hUX0CXBQ$0)n&U8j{k&`iIv1;+~n za`Y$fqCCpZ@k;xe{wE&*=>D7)<>Dyf{Rmv)D`fL+RGRX}1W?IvszLP!f3=G50S11X zfBJddck3zBrc z)ui`KPrFb`@bz3MHOe6ncbHdit8S#HPb#;hPF=&r1MK08852yozMzzo-@Q_;YYE`u@WcZO!Pn#80i_gXq!aquNVI|haD!nP@G|vTGtbJvhM8P+f&(e(AYV0pg zR&cF7h$I)ScO5u!jbj?HU{0n5iweu3#NY~vPF|I7B%Urcb&t-vFIPtb*jqWgjGT%x z8tf_!^OHM0OjeZAP7pP1-y~r4rUNo;SP8CtZF?-{{B{%n$wofJIE1R>FsRc3?ts6v zLuzVrdNU()PrjXT{dda^H%M+Ky{HVhk^w$koiR+Z;k=bJtkmJ22>`L*_Mc40Dth}0 zt+A};R}KVbI)5!#Xx}m@9Q_`y4(O84cs{`K#)O44WWuZH-T5Xro;4^EzI6&e^^dM< z#5OtY7#yjBsgmM<>##bY}d*vahL}nguwuQ^uy2L$R^gcv$!P{7-Oy|&G zOBt|O?<`0mYq;e><3yuky==sA?y-1Se2!-zBw-7iR2%!QcZ_Z_zc0HFW`oWdgOgZsbBsgEsbNTr&li~gYB7!0B=V5oI6@BDjTwbOS+N%r+ ziXgj*V`OzFQkk@~k;Dg3f$4k+l4r#OQVEM_2S~(1D?HBIHAPMRQtD=;XY<4qtnB-% zt1$5#`EF($t<}LfhYoS!AA;0OP+ioJ8|bGFx&g^Ji&0z?(E7Wx`PU8C6#K35**ByR zb3Zx^Rn0eSZuSMIWuS(V!d;4eWBf~!Da)+eFBRmINC44}&jBffP1)}1my!3<8x&k! zT@}r*YN{_x3gtXGJ^566sysN(q-qAaAY!xI_{=ZcmW(C6P2aWb0$hW+MZOns{=K4+ z{^%W&7VhWfSZRq_UM#tIHN6ZQD{K7z@`%fQoC6I2Q2J|%k)&$JGS#GzY`Aq9v+ucD z->6uBo8UBl16lt{BOo#ui34$y5YdktiNZm3Awj-VX#0~$ij*NL*nU921g)VceN*qO zU_dOM{kQhz170kMZrsOA2G{kYDzdlukyAl>-^*7`dmV-tMRx1M>@?8W~0kl7boF# zT_dq(&ZF|bc~xHmaJ%?lVOK{uv&}RSCL3(^`0%e-5~_cLnqIy+(k7?FeAn8%Zo4Se zT5{h0h;~HxtcLA(MgP{44}#B;4g}d=9Cd#p-6KNx z-7WZ&!aUP`UT?)`=mGcBBqbHufez&80fuOVOwtCl_U`7neOXj00*{13N=og@9wI&ui~NqPkD1^6diCtth2Gk6Voz z{@O_aS<(s8MK1g0h=k&jy#Y2D>Ec5PJiq25_Za^Sp7+GZ(FmY_q!&_apDMt61K5H! z%uh)gw07Jb)NBn(`UIlYVSU}}h)y#OuiTN5ko3k|;}G%b7F$^lY!`!1eO_`azRUi5 zh-L5E?2ZWjz2mOU;+09!@9E;uCKqggVuqpB_rs2B^hn|7>92MPaF#yCWmct1V!MO| z%YG1Z{2PkqWyngs^X{9hIctQM%Q+y7c+C_iYN$TFm(Mr4v&S|v{sTk@;V5iSuRiU* z5P82Grp$q1mn3O-DqfmLWGE#E>K2 zRJ}D|v^T<)p$c#U;NZ#Ee)9~pl|!YQ=65#pQD@Y+kSDG=v9i zqVG^=tlK2V@qLP(kja(|W8(e*M_BX>o&&tq-m)S2Y$zXKdm~6A>=kEuO5gBK=I3{H zYyjYhHN}BN0GaG52id|r#S&-}gCBk}2fHC+VmO?aHC7-Z5&}S+7_c`t-VzGJIF*=m zZKz0{B1AxGoZF5%u*{bLku|dU=+=^ecc^r|+gk`0uCR&_3~qlOe_;yLYfn!DBfN@8 z79GrQ3>o0>A9{C3YJw_`;1g+~V9pRhb2B0h*?pY>R(YDya*sqsFcZE#6R&9?E#mXE z(_05$1alcVOr`3yzr;bNq{}w|y|*7ejuG+68b4P{G5Jp23iL%gf@M2|A~IMJ%B%gW z>%*yhHU@NoPV^#da(WXmp=bfI5U7=m;e@GL)$>6`cQPOehNMfljCN$^OmMrf!Prun zZ5yT>kK_iQN;Q!&uer45eHosl7`gk-1c3-UN7Hq&|%l9F|VrWQhJirN*;9|!Vx zOK-Sq2Z*V`2u|zUYR#*&$5s0Xh+~NV5Sn2)>83*`E*$)?KsM>LBl_1m_qvjAJDQ%= zGPrj~o!JF$@U@*%>&H+WC`vNfbicQJEw)MSpGw)TI4oI)eyp4WLUUtj1uiLCF@u`= zG`y8fyw7SK?qDwiI&OWW#IIGJT{mtH2h{qxSKv;LKR48&z$Gvj5_gFr=1ahasu?{C z+J#aa*v+femz$Cm&i=`Eiy^2aMd)%c5ES_aA$H-b^($9%>>_PQ?5A=M&OFY?5c#V( zmaAT|Qe!&Pk?*xxHT-8jL}}T(<)1{EwU2>fvk+(&X79V&hM*wfa!;}+T7Fd^!IO6; zv1qp5j=4MiNp>j|JZfxn&*dbeC$nEQS?3rYdkF2FYaPUO$2kfSWetc@^eGc|@xAQb z%JN8DrR65;OpZAq0=JtEXzvMllS%L(H*n2tF`qJ;I9W`yXS1W6;ZUA$f-ZbHL(moV zPc;R1F9t?w=Q`q)a;(p6K*VG%>K&(uYi&F7B%_G(X7i>M$`K53YHD+r&`$vg*L5m?qh@pHXzM9*Q> zvK@ z`yP??Q!Wxcj`8%rFBRAv|J?e{xxqHo$7~Ti3Sb)ucrmfLuOGW2@)LdBFJI2{l4*F( zxnAN^QPMpY0(tt%J&_+juEj1X*O)wqnUx)kNr}+-E$r4 z7Nqa?`gb9+L0s2P(*8TE4KRA~rifIWbdpT^#^TZUm!*j_QXzWoBNvIZwp370x2BY} z3S~ij{Y5t}rQ>^}6CIR?rDHuOCa;l@*6tauaj(d@^N|d^(qCsozbME+A~|%QUewOTc8-_7b1H&=}Ei|CO+s<@$T#h~cBW2JUYwXDOB0$&l`vUv(?HI95Y!x0FZGEy*MP)i|vF+eK3r+cUFXZz_Ho#S~_8>Z- z+$Sp-+BgLCdUBQ=Vp)DSd(^T9eAO}fS)@s@*)VUJ2qxv+108s^Jn#Djk4v&@+^XIG!~>{@$ejtu9YX>kKNV7vk=urk4VB48Z{WI3kCYIEGZ2kKjq~| z+osu;+^Lg%nxX8vaJ0rf0I5$V+;kP1UIpTPSxc_~o-%d8@}6{ivvT%ahG*I)Sz1$l zX2Veeua9W!N@W7ergdSd&P}^z9*(9miH5E_r>>nY#4VE4p2Oe30qi7-9-Zcr zqGb9gwN$%5W8?lNKnz^`e6D0?QJw_JAAu7X_K=1-!ot=x20ty?b)J}y(hXgYr-37Z zI>>?1e)NmL`+}gP<8Q&zQ2KAL(z_0 z{+iRoCbw%?mmD^jUNnL{CvdtoI~+p70auH3MR}wVue*nhCFt8@G+c%|97UvC&NNC- z#rN$Cb{}*P+Sn=l$$!8oQ??{*^pG4LeG1hD*J(r5u+wnXtv^4Y6IFB z1ZcL+A1$oeHFxn|?)wwD*XhoGbn<~BL1e#Ub4dTvva!rNY|7a?pKWl$#lkJ`ReBVH zO7-w2k{L|q@`sX+-+WCaw=Oy^@mE=JEAQ8*KfJAM`+Rv*+xMp{y8vl0FAn_ql|M8ofv#EsF^JYp> zBfg>MoV$i{Am!5NpqPNdnZ25t+dr7jjG@kZDB{J+BwjPPk=&}pAxghEy;_=fSNOe(YtWGKo`{B{i^d?`Fgr14=vluXh_mY$2 zHIp9>*4dhIJV@=;`s<|7r8G_*9kRfz{(9mCgHQVw+;tB$dnMw{6FE{rG_9AJBHm(t zZ~2rI0QT~}n+X_{lJY?@mMiWNZ8=dPqT|wQKhe1xl@8wT;z6Bc3y!{a2|U2J=Cq0x zPUXmvLoO*RjOy!X#rB}9-JY-TTxM!I6sJj-Sn)2e>c$hUgpBbPLpq{9b9>s&y~Ibt zdZ$=hz867a@#Ae4;r=DoOY9_qUKUOhx3g6Me}lYYjN7%K$bFQvg!p=K6u6Q3E~{$t zLzdN+(qMNIzxILL;)ig#@H^syq2HjSIDtB{pQgoNYMlT@R^=eQl zfgBv`eMjPXvSMoo7}TQS=Gz@4U1&2#doB5u)6=n{mXv7bUd{@kZAH2p8&%rfR+rmL zr0aB$JMc_QCTq;O$cv2AmFe19gMMs4o_gEWY~eBU1|!BzI!Vi{K|f0>`Ox#KsNXz- zfn}kR*MVtp7|#=v5Sh&2*-QYsBSd1o`Gp1%mDzWJIi*J_7=S86Dw3#zMty(W zeUZL{(6P=N=j8X1@mECL;TKoHUe5}M69%tSRUrKdz7h+W8N8HFMBzuTWt&Ao=p3$V za{25jK=u}*Rt9`&Jt`P=2N>L*83MdmN|~Mp09Uxo%7|)XR|+`!{u-E%`~*7-{6i|b z?aQOkF-Y*xnE1WPJSxhGzOWfDr9Ol5SmqdR)}=RojDOFrmvducA(W}y zykSC0mCUTQx#=Wbgm2Bl4?ty_5kNCdDA( zeAt&YD!wp|w)>B|i0m=@f>@C7g>hX`Isoin{rGU9DMU3o$xsLWHx+Oe_oJ#wBU`ao zwdnq|p^gC2C3)|6+atAFz2nCE$ylt~Z)c(VcW*(fCg|pbdLU-pY0H4$)-4w0ymoo! z_H~N3eX`&`E*%w7}pTWEwXKm4dAy_*3MQvC;EU!jWq-hos80w2*&u^+ghF2ejb z5JsUH9o%jFNplWr%DL39g)`?r5_>Z9f5gB|> z0E*;kYg^L#f3tW4rpbDlR&J4FpC9Q}zbO0Sa|b5@0N^G7fO^C%d7~VgWj((eP118e z)nmdMPLWgbq8nPr!k?+;-mPwDD0e?12uM-d?hrS>^q$TDd zqOLl8?E$=;?D{NGf`)eprtlJx05|k4ow}?XB7-ZRQl(X}1UOER5t}qXG{O)G7*?32 z4)GhI))OG!0tEmkF`yqXM46U?m)sRUlZ`N|a+cWISL9rWdyOk(j#DeFo8zIoL6rJx z*O%{X5S^<2CutqF{sP)cwp35mjRjXESIYt;A6awdN;bGhW34}|TOk8Vzv#6TP};-Ty6(=y8QOAnwKZ?-Z$hwax=PQ?9DIU|Hou zn+WxLq8ASdnR;9+*=;S0u8P-Zm^MU+^`+Z4@)sts4k!%Y@ zBr%ND=)qrqX*w-9HplrBl$kvMo}fY&VJWTMQiL?E2h+A9`V(b8u(Sv&(2gF^Y~8YN z@zfjqXNj6ta`7TMNdL)E#0O<>{|`d{$O2_aonsC1w}WsoaQ|D5l;+KT6hJ9&?bKaY zA|lUhrB;2BMAHHc4d3rOn?JY--Bs!AtO6aKF5S{1-fr;k?{428a8}1fNMz?W$|I!P+Xt*q^6IB@1M-@;+T8KzeSJ@uW=kKwNwH1s6#%3j=^@N9J zhD^b8nh$pm%5Dzc9K^x)$RTFXaxW;&RUTz~y_a4Fd&DQmfd_;_bmjklv}BJ?Jp6Y8-Lnq2ES;J1^|xph|(RJlG=KfA6V(-`5A z#r3!GL8pyHAl46cI^zryQ>u9-3aQH5O@D6ZR^*fxGThq-^Ex_k75;@3SXoE8$IC^p zt2Q}xLIAd!)V12RbdSNDx#lY}nP0yC2)5o$!g}%Ty<(0z-&19U{=vW~L-~O&xTCNg z{DWRRIa!Y6)I(Ay<69UoCZ$P|w<0;&JYqGyXrK~SF5+xa_F!$uTOr6d>5fkz5ngkW zUS~ZM#Fij6c35QFFmKUcy%8`L5GjZYr%TRfJghVa%^n(PlTU0uW(__r*B2hxg|*bv zfL{3blkVJ1QJXZf?hfuG{KO$|+WGD*ki_G!n_VR}+j05B@8^qK);>=TuEwf#%Zsz& ziNNB=mzjn_CHHEHYR0uwie78A&4*^n5uws7l1XLHe{(H`*MLOsTnxkhmSZ~ak-+xd zCv^+csY63x6U3i|dIiiie7k+!f4c|CEu`2j`Ure>zcCdKu9{%pA?eMYOYTi$iKc{q zlg4|b13_6q;G$h+{I}g>&nmAAJ54M2+!yR(VU)50jiKycwI2)EESIMJ5@sG2M$4hf z-o>g+DXka?U-bC)Z3&0lezJa|m?~w7^JVI1=hzDmUevsKfsftEtHqbnyOz3)V z$q|1U%gQ*PMqmqQ%x87jHM$@7Jvj%U&@up)6+6uMGJQ2R7({WZ?$kf#Wt_D3^Uyrl z@|>$g4q{bgW29Y? zYaeOloKwX?THr@oFz3IFvmr={H>}Fo$yTJMa6hvnDg8)sBTuKAkr~G6MlPYXOJ?rQ zc~e$6%qADp8SfWc3^yqjt=Q+e*J7o8bxach_(J$AJ>+JHvy55T;>DriE4%w9Cezmv z_{)rNV}^RMQxId5Oc1NeS8@>Xx;PO{ODe}}f)v*l$fLqu#>fXbT6tFi^N(x6u;438 z(dY;%(p#4*|8l$p0rkDyK&2OTA81TZu>$%NPjggI#Ua$5^Q{gF^;OW%2Ky3)uMF(X z*~yWLugPv-sq*x5zH|3_Se(;Ho{cI00E2oi-VXTt5h&Ovc|}uav`V z`#J+F*%|KFfnG&eCVhHdmEI;$eQtbkch#z|(F7v}!rMang4>K11sF~hi zj@2y_qG2z7!ttIOf8}lz!;1T4>O+5J(JhVwyOz#I15&JqEF8oFR^jz!}_}l++AbGmoUXnvu^x`d;gun?58Oz5IAI* z1z8jx9JE0}UXXhJ(cmoDm2}A-sA%lBFFc@gI+ny!#WW6vt7A>xZL*%HzB*@%4e7QF z!8}0XO-4CL?Herp$+KA~X5>}Qn}14C-xy^0J5`4=+wfZVhwmWg@oVAa^SiO(Ths9? z(1l~xRo6=6ygOg{xmHRs>=KeWGu#T-f;Mj8YpApzy7bS>Yeci{Af516BVu??Zb zO3zaOM%YstIIZE#`nlh9luL|&&OQ@DW((7dfqH`zQ!yn9{{7P(W{L5i^aj3E-5uOY zIsMIx{L3bs#52R8;V0?sY(BFBP2sNbLIXbJBz<1RUfI6NoRwk4@%`4TV_+)c6S<`s zlp|CfH76+fdU-Qs&?Hd<3wfFaztoLhd*t3P<9GlVq#}knZ8~nnm_`#&DCvc7T#?E z3UG2lF;yZb|;06SJD#g zpy1-*u79Sp4rlNz^c&vkbp4vf%JG+(a1NUz$cc``k3-$(6hLdYL!w>6Vs?RbM#$s8Mlldt1kJX>idz9i=DeD6HTO7y&mPiL=Foc%}`o>XNKw@^`8Qd?e zkvY5aQDNt%UlW=0FWvO#vVFNds*HU$KfMd-v)3+{f;eYwzcn%YIDGctl^s)k@!5wv zPwd+To^2}HRfy->ok8Slgc5nsX^_d3#7V+@1Inp7O)>0~BBH)x6oD=MNGO}O75Mn) z-ZAgMb$#464I@j^a+&p*7~Q`vvLe4+|H8}9Qp)>@0giY-Fb&Oi&`aQUosli^ItZNE zZmNe{fI>Y}B5~ku36mdM##zEl!a>yijEt8PGqqLPF{Kwxl0N&_>Ur_4?I z)RyC{jlsNw>`0phOuWUnsmCz{F1uC|zQeU}=PqjsAGw5@PZik4i_d%QHX*mxc_VRVNNTk${(rtSsHE0Vz#^%v>pfOQ>)G#Dmgjp!JjX3(Zj1CnU}Vs4R) z-Z(m<*5HraIt)AUixrn*7BSFAnx~W@shk@&TwG?lCYD`~I+X(p50%^ep@bR+$W)+e zf<#u24ikWPf*Kf6F_$;ibDSO+vT-a%Ni;Go;CJ6_nXYe^Sz%Car_48X$t$ulvf;rcu!6gaZr+aV3WrDC~rZX*BG3dpGf2+JNbRoS2K!# z-Zbs`A0Z2W_%wwL87Mq-f;``1laUPzLjylG3k6Hg6U#9qbp}Ysdil2N7ie7@us^E- zryV>f)yJK5bp2k~z&^S>+Z2wYVsvEO?{LmOE$Y}X_wz6hssBOy`1O0g_!qp8xXeDx zo@TuZe9O`siSwq|Xv!{r8@?VYPg>G&-Ha=p1fOJ0nB!!hcdntwm%Kj@g5cw3{xcR(C>JQ(#k%Hls({V;(7h+i7H;6ODJ-}2Ix5H?L{82o6JH&r z8KP7-ZXa45)u@;6#M+!POwamtFsU?U1e#wzM=z$DT$-t&w>Sj$ck1Vixl!v z;n*PXjO^v@mAl`1e-Oqn(=m$>*7s7^*Ka}G~!nGIic z9}1UJf7&Gd1lJIZXq>rg^%)lFC6S^CY1{y@>0>)<8-N#XshEJnx;qRHu1oo|Dqzgq*?I7nYujSzxcO{Nu(v;r4obkT$;Z;4`p(8`H(DDv z9v`bEdZXKzwd5`Y9K-JCR<9F&-PC4xzCRv%D;;f1JOl=Bc=3zv#*->wK7))_HZgqL zO%YHR9M_onwOP4I?Mer#hi_22Pvw|<5E0dzAIlLXK6;HMj0KoW_Uhe8j!wTW<+GZc z^#}7g;ikJ0N5(o6D{m}Bxrzqw!US9$&%#Z~xk3`wwl8N+UjJd4cZW4;2bwaXbOhW2 z4v!X~Oe5hrv0+t~M=%s}{Ml+Ox#~As5nY{TVk82Kj-62L;0>RnR|XDxrLKzuD1kiJ zWO;_7ySJwlPO!P9Ypvo}Y=-8fcC)SOHe${*2a4Pz==PP$;zuv&R}ek5Waw-_G(R13Ip=OAfwlq zJ7H)WhybsAT6Wl&{AL0!-&-GiK1^n!s=0yW5!8y`GoZB)j|royzEpfUE64Xgx2?w3b6G+~4Ah~i zl8Y7K%kCNl%H$V(9i8g)_3-yeSNhin4RVXB!_yTM1s76iUK#?ilUTl$nZ|Ng!P;8w z8xoSG*KE#^iA7y4{~XJ~L18t!F`s7?2SK4+Gobx;&X%(y`lPCk)NXyhm5}K z*lSYNy3_6jxU$k`GnDf+OG98%6T@h#E{IfzkT3gNpGMs;a&mIsPTC}xt4aJHDW&r@ zK2hU$EkEl8B>|=}gX@_;^sUMZv(9aOP5Ih4YB#3@&~XxVB?7D{3JHTUe<>5LI2@fJDO`=WS zsRz-fJH2S@8WyHxhEHJpUG6JA=015-dd+@1b@zDJI|4G)bKAEg z^vk^mu~jA;8#RuJT>@(=%{bITv{FxDST2X`C*{B0T&8(rT&3c*%b!(v)AgwSpc0+C z42Ov|vQ#c#Z@tZJ_1QnFwcx>=r>CwdNIsNzpG@TJI5&HF%X)RZUf+}D;8$f@AYBJv z`?6t`uxHWcj^`B(g{}}Wm|~*(lYMbAS$^*{!ZTU-VR4k(a+sjN0qNpbe#z14GEq&sY@^<25@MLU^ljp(l>);~&(Rd~3?+MzOM~}UnUE=V*%G)`zQG$y4VIifbD-<+p zo+Jlho6M-lC8wjt33n(58|qll>aBP@tmfG*(pl&P4q_s=Px43J>Tw>)0LimEJSTjj zv?YaN6DoutQl78m^kg~*evE79lmjU zb^Rzk+#|IPP`!0@`W6DX3p{h?XtHOP8@&s4#VmP zt+Dk1DRqxP_NT}_;~+ZMs@;}Driky~Kpmzx*M3m+q_N@VbJK5~&rVk}L&C0SFnOay zc&+$!wIw?HsPzl+I!jjttLOuL6>SY1YNqZe;@=&unZ@ca-Q8quGvy}RnYQlhHRoH` zI$KXz!KI2nlNKbe(AT5a(!=88KX7&|@+tSs$;WFBPPQ2hUg^>%TSjcM@5_kGH<}!I z?&oD+(6qGOmcl0!;rFA?*`C{9rFc_?O_+H~c_RSaJCPi>5eOsFI!h$=Gv_25L*;CaE)W7M(i>ImZkQ zVFlu2T2LqM(&1jjid5>@xS;@))w4pUnm(Y45bC&+LES3G2hOSN=8d@yVF#B!%ShVm zX8G+$zdsC@Lm$lTq&sY_;MfuWu{#*5fG1P1Gc3D#6aNQC*mzUVz#(I*p_`=~?sH{H zZfxVzxVV^Rl_Fo!_?5)%C5^z6WAIl@(+=aN)V|`;FL6pzZ7!+Zo;v|>QM}~%O*ee^ z*M?Pt9o9oUrJwZkmUTQF*N26bfh%YTX;(}&i1||{US#i0BLCK;?ys@nPd0ZC7bV@R zY!vai{d?IZ8|2H;$^PZMq3?ZL2j7uRIvqG4hW?qg;W{q}3 zA2%fNyuo7}+YX}`J!IK^DxOzTT^UhF{hZVBsGbL!KF_b|*Hq-LB7X-ycIcRttAx7& zucl{+@RQUhQ`??9h(NH6Lw`EUw^xDZw?!V-l6wctS*hLui$bVFTz7CZ(k^w1tr9-Q zx5ZvhmG(gjP_#+ADt!)H;VCaQ2S=`C#4QVqz@%$!fPimPhh}2wvuo~6EAhd1mpq~o z>bK^c;dLNJk~+PK0GeH0MBNGYAk#P10N#YBqBjpzkIVao+?<4OEcM3p4tHOql{ew- z2I}eQt;vefS{a3CJd=K~(Dfc~4Q&#+a*EXBCf%gV@Mcn;4dt=*F4E*{(pO-2eHkJrEUP~A1UhqOIM&M5M0uApE! z#x*Fvfgh^eH-6mHD?Yp}%h}~;YZ!-eUoACu*K7W~=*`18zx0}nn~A?b1|AT6UF84K zuq2Te%zkkI2*O~nP?%BBhh)M*&>@}Aq TE=@OhT1Q$!Uc5;3>-YZ$x!e7~ literal 0 HcmV?d00001 From 8f69367a42d0a08d61f0b0e80e365f315d021a07 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Thu, 24 Oct 2024 15:39:58 -0700 Subject: [PATCH 02/23] fix #155 change "this" to proof and what the acronym means --- app/tab-welcome.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/tab-welcome.R b/app/tab-welcome.R index d53b619..59e8bab 100644 --- a/app/tab-welcome.R +++ b/app/tab-welcome.R @@ -10,7 +10,7 @@ tab_welcome <- nav_panel( h1("PROOF"), h4("Run WDL workflows on the Fred Hutch cluster") ), - p("This is a", + p("PROOF (Production Onramp for Optimization and Feasibility) is a", ablank("Shiny", href="https://shiny.posit.co/"), "app being developed by the", ablank("Fred Hutch Data Science Lab, DaSL", href="https://hutchdatascience.org/"), From 17421993a8268e1f6ecaddf7e830b24059985f62 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Thu, 24 Oct 2024 16:03:08 -0700 Subject: [PATCH 03/23] #156 changed headings on help page and added email and open an issue lines --- app/about.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/about.md b/app/about.md index 53a2814..dad4112 100644 --- a/app/about.md +++ b/app/about.md @@ -1,5 +1,7 @@ -### Resources +### Getting Help with PROOF and WDL at Fred Hutch - Get started with PROOF [How-To documentation](https://sciwiki.fredhutch.org/dasldemos/proof-how-to/) and [troubleshooting tips](https://sciwiki.fredhutch.org/dasldemos/proof-troubleshooting/) +- Ask a question about or report a problem with PROOF in our [GitHub repository](https://github.com/getwilds/proof/issues/new?template=Blank+issue) +- Email us at [wilds@fredhutch.org](mailto:wilds@fredhutch.org) - Find curated WDL workflow repositories and containers in Fred Hutch [DaSL's getWILDS GitHub organization](https://github.com/orgs/getwilds/repositories?q=wdl). - Find Cromwell and WDL Resources in [Fred Hutch's GitHub organization](https://github.com/FredHutch?utf8=%E2%9C%93&q=wdl+OR+cromwell&type=&language=). - Learn about Cromwell and WDL on the [Fred Hutch Biomedical Data Science Wiki](https://sciwiki.fredhutch.org/compdemos/Cromwell/). @@ -10,7 +12,7 @@ ## Users Elsewhere This Shiny app and the R packages it relies on are all open source. Thus, if you are at a different institution and want to use this application to support your work or your users, we encourage you to look through our resources and fork our repositories. Feel free to contact DaSL developers by filing issues or emailing `wilds@fredhutch.org`. For this use case, we have provided the more general "DIY Cromwell" login button at the top. -### Resources +### Some Resources for Using Cromwell - DIY: Get a Cromwell server running by yourself (does not require logging in). To learn more about how to get your Cromwell server running, read through the instructions in the GitHub repo [FredHutch/diy-cromwell-server](https://github.com/FredHutch/diy-cromwell-server) - `rcromwell`: An [R package](https://github.com/getwilds/rcromwell) that makes interacting with the Cromwell API easier. - `shiny-cromwell`: This app's [GitHub repo](https://github.com/FredHutch/shiny-cromwell) contains information on how to set started with this application. From 127263c3de7175de90d0196084840d4a113f24c5 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 09:01:28 -0700 Subject: [PATCH 04/23] fix #156 - add back code last date change, commit sha and link to repo --- app/server.R | 37 +++++++++++++++++++++++++++++-------- app/ui.R | 6 +++++- app/utils.R | 26 ++++++++++++-------------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/app/server.R b/app/server.R index a4d0604..3e888d2 100644 --- a/app/server.R +++ b/app/server.R @@ -57,14 +57,35 @@ server <- function(input, output, session) { session$allowReconnect(TRUE) - # Upper right github icon for source code - output$gitHtml <- renderText({ - glue('Code: FredHutch/shiny-cromwell -
- Built from: {substring(COMMIT_SHORT_SHA, 1, 7)} -
- Last built on: {stamp("Mar 1, 1999", quiet = TRUE)(ymd_hms(COMMIT_TIMESTAMP))} - ') + # For the Help page + output$gitHtml <- renderUI({ + div( + tags$span( + tags$b("Code:"), + tags$a( + "FredHutch/shiny-cromwell", + href = glue("https://github.com/FredHutch/shiny-cromwell/tree/{COMMIT_BRANCH}"), + target="_blank" + ) + ), + tags$br(), + tags$span( + tags$b("Built from:"), + tags$a( + glue("{substring(COMMIT_SHORT_SHA, 1, 7)}"), + href = glue("https://github.com/FredHutch/shiny-cromwell/tree/{COMMIT_SHA}"), + target="_blank" + ) + ), + tags$br(), + tags$span( + tags$b('Last built on:', style = "display:inline;"), + tags$p( + glue('Last built on: {stamp("Mar 1, 1999", quiet = TRUE)(ymd_hms(COMMIT_TIMESTAMP))}'), + style = "display:inline;" + ) + ) + ) }) rv <- reactiveValues(token = "", url = "", validateFilepath="", own = FALSE, user = "") diff --git a/app/ui.R b/app/ui.R index f7f9ca7..16ee59e 100644 --- a/app/ui.R +++ b/app/ui.R @@ -55,7 +55,11 @@ ui <- cookies::add_cookie_handlers( nav_panel(title = "Troubleshoot", tab_troublehsoot, shinyjs::useShinyjs()), nav_panel(title = "Help", card( - shiny::includeMarkdown("about.md") + shiny::includeMarkdown("about.md"), + card_body( + h1("App details"), + htmlOutput("gitHtml") + ) ) ), nav_spacer(), diff --git a/app/utils.R b/app/utils.R index 3d634e3..b629420 100644 --- a/app/utils.R +++ b/app/utils.R @@ -21,20 +21,18 @@ validate_workflowid <- function(x) { # get lastet commit - memoised so after first call its cached git_last <- memoise( function(branch = "dev", fallback = "") { - ## FIXME: remove below comments and dummy list when internet back - # last <- tryCatch( - # { - # resp <- httr::GET( - # url = "https://api.github.com", - # path = glue("repos/FredHutch/shiny-cromwell/commits/{branch}"), - # query = list(per_page = 1) - # ) - # httr::content(resp) - # }, - # error = function(e) e - # ) - # if (rlang::is_error(last)) fallback else last - list(sha = "adsfadf", commit = list(commmitter = list(date = "asdafd"))) + last <- tryCatch( + { + resp <- httr::GET( + url = "https://api.github.com", + path = glue("repos/FredHutch/shiny-cromwell/commits/{branch}"), + query = list(per_page = 1) + ) + httr::content(resp) + }, + error = function(e) e + ) + if (rlang::is_error(last)) fallback else last } ) From 833ba35bc2bdf455929dff0d452b7a7939580651 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 09:29:14 -0700 Subject: [PATCH 05/23] #157 server page: make Notes consistent, use bootstrap alerts for them all --- app/tab-servers.R | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/tab-servers.R b/app/tab-servers.R index b59d84f..81df152 100644 --- a/app/tab-servers.R +++ b/app/tab-servers.R @@ -1,8 +1,17 @@ +alert_light <- function(...) { + div( + strong("Note:"), + ..., + class = "alert alert-light", + role = "alert" + ) +} + card1 <- card( id = "cromwell_start_stop", class = "border border-warning", card_header(h2("Manage your PROOF Server")), - p("Note: Hover over the ", icon("question-circle"), " icons to get more information about each item."), + alert_light("Hover over the ", icon("question-circle"), " icons to get more information about each item."), h4("Get a PROOF Server Running"), p("If you have a PROOF server running, 'Job Status' should indicate 'RUNNING'. If not, click the 'Start a PROOF server' button."), uiOutput("proofStatusJobStatus"), @@ -20,7 +29,10 @@ card1 <- card( uiOutput("proofStatusServerTime"), uiOutput("proofStatusSlurmJobAccount"), h4("Stop your PROOF Server"), - p(strong("Note"), " stopping your server cannot be undone, but you can always make another one!"), + alert_light( + "Stopping your server cannot be undone, but you can always make another one!", + "Also, stopping your server does not stop your running jobs." + ), actionButton( inputId = "cromwellDelete", label = "Stop a PROOF Server", @@ -34,7 +46,7 @@ card2 <- card( id = "cromwell_troubleshoot", class = "border border-warning", card_header(h2("Troubleshoot Your PROOF Server")), - p(strong("Note"), "If you're having trouble using your PROOF server, this information can be useful in getting help."), + alert_light("If you're having trouble using your PROOF server, this information can be useful in getting help."), uiOutput("proofStatusSlurmJobId"), uiOutput("proofStatusCromwellDir"), uiOutput("proofStatusServerLogDir"), From 108b116b6cadd73f0ed107c504c4dcc82d4794c4 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 11:06:28 -0700 Subject: [PATCH 06/23] fix #157 add spinner for loading server details on server page --- Dockerfile | 2 +- app/server.R | 38 ++++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8284d59..e9e0390 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN apt-get update -y && apt-get install -y libssh-dev python3-pip git libmariad RUN R -q -e 'install.packages(c("ellipsis"), repos="https://cran.rstudio.com/")' RUN R -q -e 'install.packages(c("shiny"), repos="https://cran.rstudio.com/")' -RUN R -q -e 'install.packages(c("shinyFeedback", "shinyWidgets", "shinydashboard", "shinydashboardPlus", "ssh", "remotes", "markdown", "lubridate", "jsonlite", "dplyr", "DT", "glue", "httr", "purrr", "RColorBrewer", "rlang", "shinyBS", "shinyjs", "tidyverse", "uuid", "memoise", "rclipboard", "shinyvalidate", "shinylogs", "testhat", "bsicons", "listviewer", "htmltools", "cookies", "RMariaDB", "DBI", "parsedate", "testthat", "shinylogs", "ids"), repos="https://cran.r-project.org")' +RUN R -q -e 'install.packages(c("shinyFeedback", "shinyWidgets", "shinydashboard", "shinydashboardPlus", "ssh", "remotes", "markdown", "lubridate", "jsonlite", "dplyr", "DT", "glue", "httr", "purrr", "RColorBrewer", "rlang", "shinyBS", "shinyjs", "tidyverse", "uuid", "memoise", "rclipboard", "shinyvalidate", "shinylogs", "testhat", "bsicons", "listviewer", "htmltools", "cookies", "RMariaDB", "DBI", "parsedate", "testthat", "shinylogs", "ids", "shinycssloaders"), repos="https://cran.r-project.org")' RUN R -q -e "remotes::install_github('getwilds/proofr@v0.3.0')" diff --git a/app/server.R b/app/server.R index 3e888d2..6b841e3 100644 --- a/app/server.R +++ b/app/server.R @@ -28,6 +28,7 @@ library(cookies) library(listviewer) library(ids) +library(shinycssloaders) source("modals.R") source("proof.R") @@ -355,7 +356,7 @@ server <- function(input, output, session) { cromwellProofStatusData <- reactivePoll(2000, session, checkFunc = function() { if (!is.null(input$tabs)) { - if (input$tabs != "cromwell") return(NULL) + if (input$proof != "Server") return(NULL) } if (proof_loggedin(rv$token)) { tmp <- proof_status(token = rv$token) @@ -369,7 +370,7 @@ server <- function(input, output, session) { } ) - proofStatusTextGenerator <- function(name, list_index, tip = "", value_if_null = NULL) { + proofStatusTextGenerator <- function(dat, name, list_index, tip = "", value_if_null = NULL) { renderUI({ if (proof_loggedin(rv$token)) { if (nzchar(tip)) { @@ -381,7 +382,7 @@ server <- function(input, output, session) { ), HTML(paste0( strong(glue("{name}: ")), - purrr::flatten(cromwellProofStatusData())[[list_index]] %||% value_if_null + purrr::flatten(dat)[[list_index]] %||% value_if_null )) ) } else { @@ -389,7 +390,7 @@ server <- function(input, output, session) { icon("question-circle"), HTML(paste0( strong(glue("{name}: ")), - purrr::flatten(cromwellProofStatusData())[[list_index]] %||% value_if_null + purrr::flatten(dat)[[list_index]] %||% value_if_null )) ) } @@ -397,18 +398,23 @@ server <- function(input, output, session) { }) } - output$proofStatusJobStatus <- proofStatusTextGenerator("Job status", "jobStatus", "PROOF server job status", value_if_null = "Stopped") - output$proofStatusUrlStr <- proofStatusTextGenerator("Cromwell URL", "cromwellUrl") - output$proofStatusWorkflowLogDir <- proofStatusTextGenerator("Workflow log directory", "WORKFLOWLOGDIR") - output$proofStatusScratchDir <- proofStatusTextGenerator("Scratch directory", "SCRATCHDIR", "Working directory on Scratch") - output$proofStatusSlurmJobId <- proofStatusTextGenerator("Slurm job ID", "SLURM_JOB_ID", "PROOF server SLURM job id") - output$proofStatusCromwellDir <- proofStatusTextGenerator("Cromwell directory", "CROMWELL_DIR") - output$proofStatusServerLogDir <- proofStatusTextGenerator("Server log directory", "SERVERLOGDIR", "PROOF server log directory") - output$proofStatusSingularityCacheDir <- proofStatusTextGenerator("Singlarity cache directory", "SINGULARITYCACHEDIR") - output$proofStatusServerTime <- proofStatusTextGenerator("Server time", "SERVERTIME", "PROOF server job lifetime") - output$proofStatusUseAWS <- proofStatusTextGenerator("Use AWS?", "USE_AWS", "AWS credentials found?") - output$proofStatusSlurmJobAccount <- proofStatusTextGenerator("Slurm job account", "SLURM_JOB_ACCOUNT", "Designated Gizmo PI account") - output$proofStatusServerStartTime <- proofStatusTextGenerator("PROOF Server Start Time", "jobStartTime") + observe({ + showPageSpinner(type = 5, caption = "Loading changed server details ...") + dat <- cromwellProofStatusData() + output$proofStatusJobStatus <- proofStatusTextGenerator(dat, "Job status", "jobStatus", "PROOF server job status", value_if_null = "Stopped") + output$proofStatusUrlStr <- proofStatusTextGenerator(dat, "Cromwell URL", "cromwellUrl") + output$proofStatusWorkflowLogDir <- proofStatusTextGenerator(dat, "Workflow log directory", "WORKFLOWLOGDIR") + output$proofStatusScratchDir <- proofStatusTextGenerator(dat, "Scratch directory", "SCRATCHDIR", "Working directory on Scratch") + output$proofStatusSlurmJobId <- proofStatusTextGenerator(dat, "Slurm job ID", "SLURM_JOB_ID", "PROOF server SLURM job id") + output$proofStatusCromwellDir <- proofStatusTextGenerator(dat, "Cromwell directory", "CROMWELL_DIR") + output$proofStatusServerLogDir <- proofStatusTextGenerator(dat, "Server log directory", "SERVERLOGDIR", "PROOF server log directory") + output$proofStatusSingularityCacheDir <- proofStatusTextGenerator(dat, "Singlarity cache directory", "SINGULARITYCACHEDIR") + output$proofStatusServerTime <- proofStatusTextGenerator(dat, "Server time", "SERVERTIME", "PROOF server job lifetime") + output$proofStatusUseAWS <- proofStatusTextGenerator(dat, "Use AWS?", "USE_AWS", "AWS credentials found?") + output$proofStatusSlurmJobAccount <- proofStatusTextGenerator(dat, "Slurm job account", "SLURM_JOB_ACCOUNT", "Designated Gizmo PI account") + output$proofStatusServerStartTime <- proofStatusTextGenerator(dat, "PROOF Server Start Time", "jobStartTime") + hidePageSpinner() + }) ###### Cromwell Validate tab ###### ## Validate a possible workflow From 50e8ae347e5f7d54e2666795b154c6218e222c0d Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 12:16:35 -0700 Subject: [PATCH 07/23] #158 submit pages changes: - make submit button green when enabled - disbale submit button until a wdl is uploaded (other files are optional so arent related to disabled state) - move submission result under submit button - unrelated: disable start server button on server page when status is running --- app/server.R | 13 +++++++++++++ app/tab-submission.R | 9 +++++---- app/ui.R | 9 ++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/server.R b/app/server.R index 6b841e3..a4c3e68 100644 --- a/app/server.R +++ b/app/server.R @@ -308,6 +308,12 @@ server <- function(input, output, session) { } }) + observe({ + shinyjs::toggleState("cromwellStart", + cromwellProofStatusData()$jobStatus != "RUNNING" + ) + }) + # Disable or enable the Delete button for deleting proof server observeEvent(input$cromwellDelete, { showModal(verifyCromwellDeleteModal()) @@ -515,6 +521,12 @@ server <- function(input, output, session) { }) }) + observe({ + shinyjs::toggleState("submitWorkflow", + !rlang::is_empty(input$wdlFile$datapath) + ) + }) + # reset observeEvent(input$resetSubmission, { reset_inputs(c( @@ -526,6 +538,7 @@ server <- function(input, output, session) { rv_file$input2JSON_state <- 'reset' rv_file$workOptions_state <- 'reset' output$submissionResult <- renderText({}) + shinyjs::disable("submitWorkflow") }) ###### Troubleshoot tab ###### diff --git a/app/tab-submission.R b/app/tab-submission.R index d9d0996..457376c 100644 --- a/app/tab-submission.R +++ b/app/tab-submission.R @@ -29,7 +29,11 @@ tab_submission <- card( inputId = "submitWorkflow", label = "Submit Workflow", icon = icon("paper-plane"), - width = "250px" + width = "250px", + class = "btn-success" + ), + card( + uiOutput(outputId = "submissionResult") ), actionButton( inputId = "resetSubmission", @@ -53,9 +57,6 @@ tab_submission <- card( inputId = "workOptions", "Workflow Options JSON (optional):", accept = ".json" ) - ), - card( - uiOutput(outputId = "submissionResult") ) ) ) diff --git a/app/ui.R b/app/ui.R index 16ee59e..8dac724 100644 --- a/app/ui.R +++ b/app/ui.R @@ -45,7 +45,14 @@ ui <- cookies::add_cookie_handlers( tab_welcome, nav_panel(title = "Server", tab_servers), nav_panel(title = "Validate", tab_validate, shinyjs::useShinyjs()), - nav_panel(title = "Submit", tab_submission, shinyjs::useShinyjs()), + nav_panel(title = "Submit", tab_submission, shinyjs::useShinyjs(), + tags$style(" + .btn.btn-success:disabled { + background-color: #d0d0d0; + opacity: 1.0; + }" + ), + ), nav_panel(title = "Track workflows", tab_tracking, rclipboard::rclipboardSetup()), nav_panel(title = "Workflow Details", tab_workflow_details, tags$head( From 95cb8bde6c497b9062224538cd7ea563af9487af Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 12:30:59 -0700 Subject: [PATCH 08/23] undo addition of server spinner in 108b116b6cadd73f0ed107c504c4dcc82d4794c4 for now, need to refine it more --- app/server.R | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/app/server.R b/app/server.R index a4c3e68..216bb57 100644 --- a/app/server.R +++ b/app/server.R @@ -28,7 +28,6 @@ library(cookies) library(listviewer) library(ids) -library(shinycssloaders) source("modals.R") source("proof.R") @@ -376,8 +375,9 @@ server <- function(input, output, session) { } ) - proofStatusTextGenerator <- function(dat, name, list_index, tip = "", value_if_null = NULL) { + proofStatusTextGenerator <- function(name, list_index, tip = "", value_if_null = NULL) { renderUI({ + dat <- cromwellProofStatusData() if (proof_loggedin(rv$token)) { if (nzchar(tip)) { tags$span( @@ -404,23 +404,18 @@ server <- function(input, output, session) { }) } - observe({ - showPageSpinner(type = 5, caption = "Loading changed server details ...") - dat <- cromwellProofStatusData() - output$proofStatusJobStatus <- proofStatusTextGenerator(dat, "Job status", "jobStatus", "PROOF server job status", value_if_null = "Stopped") - output$proofStatusUrlStr <- proofStatusTextGenerator(dat, "Cromwell URL", "cromwellUrl") - output$proofStatusWorkflowLogDir <- proofStatusTextGenerator(dat, "Workflow log directory", "WORKFLOWLOGDIR") - output$proofStatusScratchDir <- proofStatusTextGenerator(dat, "Scratch directory", "SCRATCHDIR", "Working directory on Scratch") - output$proofStatusSlurmJobId <- proofStatusTextGenerator(dat, "Slurm job ID", "SLURM_JOB_ID", "PROOF server SLURM job id") - output$proofStatusCromwellDir <- proofStatusTextGenerator(dat, "Cromwell directory", "CROMWELL_DIR") - output$proofStatusServerLogDir <- proofStatusTextGenerator(dat, "Server log directory", "SERVERLOGDIR", "PROOF server log directory") - output$proofStatusSingularityCacheDir <- proofStatusTextGenerator(dat, "Singlarity cache directory", "SINGULARITYCACHEDIR") - output$proofStatusServerTime <- proofStatusTextGenerator(dat, "Server time", "SERVERTIME", "PROOF server job lifetime") - output$proofStatusUseAWS <- proofStatusTextGenerator(dat, "Use AWS?", "USE_AWS", "AWS credentials found?") - output$proofStatusSlurmJobAccount <- proofStatusTextGenerator(dat, "Slurm job account", "SLURM_JOB_ACCOUNT", "Designated Gizmo PI account") - output$proofStatusServerStartTime <- proofStatusTextGenerator(dat, "PROOF Server Start Time", "jobStartTime") - hidePageSpinner() - }) + output$proofStatusJobStatus <- proofStatusTextGenerator("Job status", "jobStatus", "PROOF server job status", value_if_null = "Stopped") + output$proofStatusUrlStr <- proofStatusTextGenerator("Cromwell URL", "cromwellUrl") + output$proofStatusWorkflowLogDir <- proofStatusTextGenerator("Workflow log directory", "WORKFLOWLOGDIR") + output$proofStatusScratchDir <- proofStatusTextGenerator("Scratch directory", "SCRATCHDIR", "Working directory on Scratch") + output$proofStatusSlurmJobId <- proofStatusTextGenerator("Slurm job ID", "SLURM_JOB_ID", "PROOF server SLURM job id") + output$proofStatusCromwellDir <- proofStatusTextGenerator("Cromwell directory", "CROMWELL_DIR") + output$proofStatusServerLogDir <- proofStatusTextGenerator("Server log directory", "SERVERLOGDIR", "PROOF server log directory") + output$proofStatusSingularityCacheDir <- proofStatusTextGenerator("Singlarity cache directory", "SINGULARITYCACHEDIR") + output$proofStatusServerTime <- proofStatusTextGenerator("Server time", "SERVERTIME", "PROOF server job lifetime") + output$proofStatusUseAWS <- proofStatusTextGenerator("Use AWS?", "USE_AWS", "AWS credentials found?") + output$proofStatusSlurmJobAccount <- proofStatusTextGenerator("Slurm job account", "SLURM_JOB_ACCOUNT", "Designated Gizmo PI account") + output$proofStatusServerStartTime <- proofStatusTextGenerator("PROOF Server Start Time", "jobStartTime") ###### Cromwell Validate tab ###### ## Validate a possible workflow From 0278065ff2daa5973b769971c2b89261b4f27912 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 12:40:21 -0700 Subject: [PATCH 09/23] #159 track workflow page: each card - move workflow id to bottom left of card - move name and labels to top left of card --- app/server.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/server.R b/app/server.R index 216bb57..324c0a1 100644 --- a/app/server.R +++ b/app/server.R @@ -750,7 +750,11 @@ server <- function(input, output, session) { id = glue("job_card_{w$workflow_id}"), class = "border border-secondary", card_header( - w$workflow_id, + div( + span(bsicons::bs_icon("person-badge"), w$workflow_name), + span("(", bsicons::bs_icon("tag-fill"), w$Label), + span(bsicons::bs_icon("tag"), w$secondaryLabel, ")") + ), actionButton( "goToWorkflowDetails", label = "Workflow Details", @@ -776,11 +780,7 @@ server <- function(input, output, session) { card_body( class = "d-flex justify-content-between gap-1", fillable = FALSE, - div( - span(bsicons::bs_icon("person-badge"), w$workflow_name), - span(bsicons::bs_icon("tag-fill"), w$Label), - span(bsicons::bs_icon("tag"), w$secondaryLabel) - ), + w$workflow_id, actionButton( inputId = "abortWorkflow", label = "Abort Workflow", From 57064c2b64f7dfed256d6ce7c2422fd405123b9c Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Fri, 25 Oct 2024 22:08:16 -0700 Subject: [PATCH 10/23] #159 added spinner for workflow details buttons on each click, and reset after loading details page is done, removed icon --- app/server.R | 28 ++++++++++++++++++++-------- app/utils.R | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/app/server.R b/app/server.R index 324c0a1..6200f80 100644 --- a/app/server.R +++ b/app/server.R @@ -741,6 +741,10 @@ server <- function(input, output, session) { }) # Data for cards out of workflowUpdate data + workflowDetailsId <- function(workflow_id) { + paste0("goToWorkflowDetails-", workflow_id) + } + output$workflows_cards <- renderUI({ dflst <- apply(workflowUpdate(), 1, as.list) dat <- lapply(dflst, function(w) { @@ -755,17 +759,15 @@ server <- function(input, output, session) { span("(", bsicons::bs_icon("tag-fill"), w$Label), span(bsicons::bs_icon("tag"), w$secondaryLabel, ")") ), - actionButton( - "goToWorkflowDetails", + proofLoadingButton( + inputId = workflowDetailsId(w$workflow_id), label = "Workflow Details", - icon = icon("rectangle-list"), - class = "btn-secondary btn-sm", + class = "btn btn-secondary btn-sm", onclick = glue('Shiny.setInputValue(\"selectedWorkflowId\", \"{w$workflow_id}\"); Shiny.setInputValue(\"selectedWorkflowLabel\", \"{w$Label}\"); Shiny.setInputValue(\"selectedWorkflowSecLabel\", \"{w$secondaryLabel}\")') ), class = "d-flex justify-content-between gap-1", - # class = "bg-secondary" ), card_body( class = "d-flex align-items-left justify-content-between gap-1", @@ -847,9 +849,19 @@ server <- function(input, output, session) { ) }) - observeEvent(input$goToWorkflowDetails, { - print(input$goToWorkflowDetails) - nav_select("proof", "Workflow Details") + reactive_buttons <- reactive({ + button_ids <- names(input) + button_ids[grepl("goToWorkflowDetails", button_ids)] + }) + + observe({ + matching_ids <- reactive_buttons() + lapply(matching_ids, function(id) { + observeEvent(input[[id]], { + nav_select("proof", "Workflow Details") + shinyFeedback::resetLoadingButton(id) + }) + }) }) ## reset trouble diff --git a/app/utils.R b/app/utils.R index b629420..e57bb12 100644 --- a/app/utils.R +++ b/app/utils.R @@ -3,6 +3,58 @@ library(bsicons) library(parsedate) library(uuid) library(rclipboard) +library(shinyFeedback) + +# exact copy from shiny:::validateIcon +proofValidateIcon <- function (icon) { + if (is.null(icon) || identical(icon, character(0))) { + return(icon) + } else if (inherits(icon, "shiny.tag") && icon$name == "i") { + return(icon) + } else { + stop("Invalid icon. Use Shiny's 'icon()' function to generate a valid icon") + } +} + +# copy from shinyFeedback::loadingButton adding ability to pass in: +# - onclick (most importantly) +# - icon (less important) +proofLoadingButton <- function(inputId, label, + class = "btn btn-primary", style = "width: 150px;", + loadingLabel = "Loading...", loadingSpinner = "spinner", + loadingClass = NULL, loadingStyle = NULL, icon = NULL, ...) { + + shiny::addResourcePath("shinyfeedback", system.file("assets", + package = "shinyFeedback")) + if (is.null(loadingClass)) { + loadingClass <- class + } + if (is.null(loadingStyle)) { + loadingStyle <- style + } + rOptions <- list(label = label, class = class, style = style, + loadingLabel = loadingLabel, loadingSpinner = loadingSpinner, + loadingClass = loadingClass, loadingStyle = loadingStyle) + jsonOptions <- jsonlite::toJSON(rOptions, auto_unbox = TRUE) + htmltools::span( + class = "sf-loading-button", + id = paste0("sf-loading-button-", inputId), + tags$button( + id = inputId, + class = class, + style = style, + list(proofValidateIcon(icon), label), + ... + ), + tags$head( + htmltools::singleton(fontawesome::fa_html_dependency()), + htmltools::singleton( + tags$script(src = "shinyfeedback/js/loadingbutton.js?version=1"), + ), + tags$script(sprintf("loadingButtons.create('%s', %s)", inputId, jsonOptions)) + ) + ) +} # coerce dates to PT from UTC as_pt <- function(x) { From 0e1a4d07335d99ebe66eafb5eb631ca2026ebab8 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 10:41:11 -0700 Subject: [PATCH 11/23] possible fix for 401 error --- app/server.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/server.R b/app/server.R index 6200f80..b46a058 100644 --- a/app/server.R +++ b/app/server.R @@ -309,7 +309,7 @@ server <- function(input, output, session) { observe({ shinyjs::toggleState("cromwellStart", - cromwellProofStatusData()$jobStatus != "RUNNING" + proof_status(token = rv$token)$jobStatus != "RUNNING" ) }) From 1392c9c7d1b557bd5e88dc629600c9657f260284 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 11:00:35 -0700 Subject: [PATCH 12/23] change server start disable toggle - run toggle only if logged in and server up --- app/server.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/server.R b/app/server.R index b46a058..abe4a05 100644 --- a/app/server.R +++ b/app/server.R @@ -308,9 +308,11 @@ server <- function(input, output, session) { }) observe({ - shinyjs::toggleState("cromwellStart", - proof_status(token = rv$token)$jobStatus != "RUNNING" - ) + if (proof_loggedin_serverup(rv$url, rv$token)) { + shinyjs::toggleState("cromwellStart", + proof_status(token = rv$token)$jobStatus != "RUNNING" + ) + } }) # Disable or enable the Delete button for deleting proof server From c3f54399c196d90289a3566dae84d85b0251a53a Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 11:09:39 -0700 Subject: [PATCH 13/23] move cromwellProofStatusData call in proofStatusTextGenerator within if logged in block --- app/server.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/server.R b/app/server.R index abe4a05..10d47dd 100644 --- a/app/server.R +++ b/app/server.R @@ -379,8 +379,8 @@ server <- function(input, output, session) { proofStatusTextGenerator <- function(name, list_index, tip = "", value_if_null = NULL) { renderUI({ - dat <- cromwellProofStatusData() if (proof_loggedin(rv$token)) { + dat <- cromwellProofStatusData() if (nzchar(tip)) { tags$span( bslib::tooltip( From 1e5af3673ef072f02764c70224c18561168aeee2 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 13:47:03 -0700 Subject: [PATCH 14/23] fix #159 add spinner loading to cards on tracking page --- app/tab-tracking.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/tab-tracking.R b/app/tab-tracking.R index 53e1b87..6e76b0d 100644 --- a/app/tab-tracking.R +++ b/app/tab-tracking.R @@ -3,6 +3,7 @@ library(bsicons) library(htmltools) library(glue) library(bslib) +library(shinycssloaders) sidebar_tracking <- sidebar( actionButton( @@ -85,7 +86,9 @@ card_workflow_runs <- card( workflow_cards <- layout_column_wrap( width = 1/1, fillable = FALSE, - uiOutput("workflows_cards") + shinycssloaders::withSpinner( + uiOutput("workflows_cards") + ) ) tab_tracking <- page_sidebar( From 37ac9a65a805a06c5b2811358246b760414ccb3e Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 14:02:23 -0700 Subject: [PATCH 15/23] #158 submit page, disable submit button on page load, and disable button after result returned --- app/server.R | 1 + app/tab-submission.R | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/server.R b/app/server.R index 10d47dd..52ca83a 100644 --- a/app/server.R +++ b/app/server.R @@ -508,6 +508,7 @@ server <- function(input, output, session) { url = rv$url, token = rv$token ) + shinyjs::disable("submitWorkflow") HTML(glue('
    diff --git a/app/tab-submission.R b/app/tab-submission.R index 457376c..ac3412c 100644 --- a/app/tab-submission.R +++ b/app/tab-submission.R @@ -25,13 +25,13 @@ tab_submission <- card( value = "", placeholder = "e.g., Cohort 2" ), - actionButton( + shinyjs::disabled(actionButton( inputId = "submitWorkflow", label = "Submit Workflow", icon = icon("paper-plane"), width = "250px", class = "btn-success" - ), + )), card( uiOutput(outputId = "submissionResult") ), From a80d551490be2b73a596bc18060bb9d1885f0d7d Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 14:21:46 -0700 Subject: [PATCH 16/23] #160 move troubleshoot tab into workflow details tab --- app/server.R | 27 +++------------------------ app/tab-troubleshoot.R | 22 +++++----------------- app/tab-welcome.R | 4 ---- app/tab-workflow_details.R | 5 ++++- app/ui.R | 2 -- 5 files changed, 12 insertions(+), 48 deletions(-) diff --git a/app/server.R b/app/server.R index 52ca83a..5dab3e9 100644 --- a/app/server.R +++ b/app/server.R @@ -97,8 +97,7 @@ server <- function(input, output, session) { inputJSON_state = NULL, input2JSON_state = NULL, workOptions_state = NULL, - abortWorkflowID_state = NULL, - troubleWorkflowID_state = NULL + abortWorkflowID_state = NULL ) # Login and UI component handling @@ -540,34 +539,17 @@ server <- function(input, output, session) { }) ###### Troubleshoot tab ###### - ## Troubleshoot a workflow - input_troubleWorkflowID <- reactive({ - reactiveInput(rv_file$troubleWorkflowID_state, input$troubleWorkflowID) - }) - observeEvent(input$troubleWorkflowID, { - rv_file$troubleWorkflowID_state <- 'loaded' - }) - - observeEvent(input$troubleWorkflow, { + observeEvent(input$selectedWorkflowId, { output$troubleResult <- renderPrint({ - validate_workflowid(isolate(input$troubleWorkflowID)) stop_safe_loggedin_serverup(rv$url, rv$token, rv$own) cromwell_glob( - workflow_id = isolate(input_troubleWorkflowID()), + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token ) }) }) - ## reset trouble - observeEvent(input$resetTrouble, { - reset_inputs("troubleWorkflowID") - rv_file$troubleWorkflowID_state <- 'reset' - output$troubleResult <- renderText({}) - }) - - ############ CROMWELL Tracking Tab ############ workflowUpdate <- eventReactive(input$trackingUpdate, { @@ -668,9 +650,6 @@ server <- function(input, output, session) { observeEvent(input$linkToWorkflowDetailsTab, { nav_select("proof", "Workflow Details") }) - observeEvent(input$linkToTroubleshootingTab, { - nav_select("proof", "Troubleshoot") - }) observeEvent(input$linkToHelpTab, { nav_select("proof", "Help") }) diff --git a/app/tab-troubleshoot.R b/app/tab-troubleshoot.R index f201ae7..1190dc7 100644 --- a/app/tab-troubleshoot.R +++ b/app/tab-troubleshoot.R @@ -1,4 +1,6 @@ -tab_troublehsoot <- nav_panel(NULL, +library(shinyjs) + +tab_troublehsoot <- nav_panel(title = "Troubleshoot", card( class = "border border-primary", full_screen = TRUE, @@ -6,23 +8,9 @@ tab_troublehsoot <- nav_panel(NULL, card_body( fillable = FALSE, p("When a workflow fails but no jobs were started, or there appears to be no clear reason for a workflow to have failed, this tool can provide you the entire set of workflow metadata Cromwell has for your workflow in it's raw and unprocessed (json) form. For complex workflows, this can be rather large (and ugly!)."), - textInput( - inputId = "troubleWorkflowID", - label = "Workflow id to get metadata for:", - value = "", - placeholder = "577b9aa4-b26b-4fd6-9f17-7fb33780bbd0", - width = "25%" - ), - actionButton( - inputId = "troubleWorkflow", - class = "btn-sm", - label = "Get Workflow Metadata", - icon = icon("wrench"), - width = "250px" - ), - actionButton("resetTrouble", "Reset", class = "btn-sm", width = "250px"), br(), verbatimTextOutput(outputId = "troubleResult") ) - ) + ), + shinyjs::useShinyjs() ) diff --git a/app/tab-welcome.R b/app/tab-welcome.R index 59e8bab..ea453a9 100644 --- a/app/tab-welcome.R +++ b/app/tab-welcome.R @@ -39,10 +39,6 @@ tab_welcome <- nav_panel( ), tags$li("Check", actionLink("linkToWorkflowDetailsTab", "workflow details") - ), - tags$li("Check the", - actionLink("linkToTroubleshootingTab", "troubleshooting page"), - " to dig into error messages if needed" ) ), h4("To learn more about PROOF and WDL head over to the ", diff --git a/app/tab-workflow_details.R b/app/tab-workflow_details.R index adaf462..027dd73 100644 --- a/app/tab-workflow_details.R +++ b/app/tab-workflow_details.R @@ -1,5 +1,7 @@ library(listviewer) +source("tab-troubleshoot.R") + tab_workflow_details <- card( id = "workflow_details", card_header( @@ -62,6 +64,7 @@ tab_workflow_details <- card( ), downloadButton("downloadOutputs", "Download Workflow Output Data"), DTOutput("outputslistBatch") - ) + ), + tab_troublehsoot ) ) diff --git a/app/ui.R b/app/ui.R index 8dac724..2959319 100644 --- a/app/ui.R +++ b/app/ui.R @@ -24,7 +24,6 @@ source("tab-validate.R") source("tab-submission.R") source("tab-tracking.R") source("tab-workflow_details.R") -source("tab-troubleshoot.R") source("tab-details.R") ui <- cookies::add_cookie_handlers( @@ -59,7 +58,6 @@ ui <- cookies::add_cookie_handlers( tags$script(src = "https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js") ) ), - nav_panel(title = "Troubleshoot", tab_troublehsoot, shinyjs::useShinyjs()), nav_panel(title = "Help", card( shiny::includeMarkdown("about.md"), From 92c3de942ea42b164141be187a969c715ad51fdc Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 14:28:37 -0700 Subject: [PATCH 17/23] clean up workflow details page to have each panel be its own R object --- app/tab-troubleshoot.R | 2 +- app/tab-workflow_details.R | 131 +++++++++++++++++++++---------------- 2 files changed, 75 insertions(+), 58 deletions(-) diff --git a/app/tab-troubleshoot.R b/app/tab-troubleshoot.R index 1190dc7..52ca7bc 100644 --- a/app/tab-troubleshoot.R +++ b/app/tab-troubleshoot.R @@ -1,6 +1,6 @@ library(shinyjs) -tab_troublehsoot <- nav_panel(title = "Troubleshoot", +panel_troublehsoot <- nav_panel(title = "Troubleshoot", card( class = "border border-primary", full_screen = TRUE, diff --git a/app/tab-workflow_details.R b/app/tab-workflow_details.R index 027dd73..5c14042 100644 --- a/app/tab-workflow_details.R +++ b/app/tab-workflow_details.R @@ -2,6 +2,71 @@ library(listviewer) source("tab-troubleshoot.R") +panel_job_list <- nav_panel( + title = "Job List", + downloadButton("downloadJobs", + "Download Workflow Jobs Data", style = "width:20%"), + DTOutput("tasklistBatch") +) + +panel_workflow_description <- nav_panel( + title = "Workflow Description", + card_body( + uiOutput("workflowDescribe") + ) +) + +panel_diagram <- nav_panel( + title = "Diagram", + uiOutput("mermaid_diagram") +) + +panel_job_failures <- nav_panel( + title = "Job Failures", + p("Specific information for jobs with a status of 'Failed', only available upon request."), + actionButton( + inputId = "getFailedData", + label = "Get/Refresh Failed Job Metadata", + icon("refresh") + ), + downloadButton("downloadFails", "Download Call Failure Data"), + DTOutput("failurelistBatch") +) + +panel_call_caching <- nav_panel( + title = "Call Caching ", + p("Only available upon request. Note: this can be slow for very complex workflows. "), + actionButton( + inputId = "getCacheData", + label = "Get/Refresh Call Caching Metadata", + icon("refresh") + ), + downloadButton("downloadCache", "Download Call Caching Data"), + DTOutput("cachingListBatch") +) + +panel_options <- nav_panel( + title = "Workflow Options", + DTOutput("workflowOpt") +) + +panel_inputs <- nav_panel( + title = "Workflow Inputs", + reactjsonOutput("workflowInp", height = "100%") +) + +panel_outputs <- nav_panel( + title = "Workflow Outputs", + p("The specific outputs to the entire workflow itself are listed here only upon request and only if they are all available. "), + actionButton( + inputId = "getOutputData", + label = "Get/Refresh Workflow Output Metadata", + icon("refresh") + ), + downloadButton("downloadOutputs", "Download Workflow Output Data"), + DTOutput("outputslistBatch") +) + tab_workflow_details <- card( id = "workflow_details", card_header( @@ -9,62 +74,14 @@ tab_workflow_details <- card( class = "d-flex gap-1 justify-content-between" ), navset_underline( - nav_panel( - title = "Job List", - downloadButton("downloadJobs", "Download Workflow Jobs Data", style = "width:20%"), - DTOutput("tasklistBatch") - ), - nav_panel( - title = "Workflow Description", - card_body( - uiOutput("workflowDescribe") - ) - ), - nav_panel( - title = "Diagram", - uiOutput("mermaid_diagram") - ), - nav_panel( - title = "Job Failures", - p("Specific information for jobs with a status of 'Failed', only available upon request."), - actionButton( - inputId = "getFailedData", - label = "Get/Refresh Failed Job Metadata", - icon("refresh") - ), - downloadButton("downloadFails", "Download Call Failure Data"), - DTOutput("failurelistBatch") - ), - nav_panel( - title = "Call Caching ", - p("Only available upon request. Note: this can be slow for very complex workflows. "), - actionButton( - inputId = "getCacheData", - label = "Get/Refresh Call Caching Metadata", - icon("refresh") - ), - downloadButton("downloadCache", "Download Call Caching Data"), - DTOutput("cachingListBatch") - ), - nav_panel( - title = "Workflow Options", - DTOutput("workflowOpt") - ), - nav_panel( - title = "Workflow Inputs", - reactjsonOutput("workflowInp", height = "100%") - ), - nav_panel( - title = "Workflow Outputs", - p("The specific outputs to the entire workflow itself are listed here only upon request and only if they are all available. "), - actionButton( - inputId = "getOutputData", - label = "Get/Refresh Workflow Output Metadata", - icon("refresh") - ), - downloadButton("downloadOutputs", "Download Workflow Output Data"), - DTOutput("outputslistBatch") - ), - tab_troublehsoot + panel_job_list, + panel_workflow_description, + panel_diagram, + panel_job_failures, + panel_call_caching, + panel_options, + panel_inputs, + panel_outputs, + panel_troublehsoot ) ) From d03bdba2a47e29c0f520b9b76079298e572005c1 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 15:40:29 -0700 Subject: [PATCH 18/23] #160 rework header of workflow details, name and labels on left, ID on right --- app/server.R | 30 +++++++++++++++++++++++++----- app/ui.R | 5 ++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/app/server.R b/app/server.R index 5dab3e9..c6ffd97 100644 --- a/app/server.R +++ b/app/server.R @@ -26,6 +26,7 @@ library(rcromwell) library(cookies) library(listviewer) +library(rclipboard) library(ids) @@ -745,9 +746,12 @@ server <- function(input, output, session) { inputId = workflowDetailsId(w$workflow_id), label = "Workflow Details", class = "btn btn-secondary btn-sm", - onclick = glue('Shiny.setInputValue(\"selectedWorkflowId\", \"{w$workflow_id}\"); + onclick = glue(' + Shiny.setInputValue(\"selectedWorkflowId\", \"{w$workflow_id}\"); + Shiny.setInputValue(\"selectedWorkflowName\", \"{w$workflow_name}\"); Shiny.setInputValue(\"selectedWorkflowLabel\", \"{w$Label}\"); - Shiny.setInputValue(\"selectedWorkflowSecLabel\", \"{w$secondaryLabel}\")') + Shiny.setInputValue(\"selectedWorkflowSecLabel\", \"{w$secondaryLabel}\") + ') ), class = "d-flex justify-content-between gap-1", ), @@ -857,11 +861,27 @@ server <- function(input, output, session) { if (!is.null(input$selectedWorkflowId)) { htmltools::tagList( htmltools::tags$span( - h3("Workflow Specific Job Information", bsicons::bs_icon("caret-right"), paste(substring(input$selectedWorkflowId, 1, 13), " ...")), + h4(input$selectedWorkflowName, style = "display:inline"), + h5( + " (", + span(bsicons::bs_icon("tag-fill"), input$selectedWorkflowLabel), + span(bsicons::bs_icon("tag"), input$selectedWorkflowSecLabel), + ")", + style = "display:inline" + ) ), htmltools::tags$div( - span(bsicons::bs_icon("tag-fill"), input$selectedWorkflowLabel), - span(bsicons::bs_icon("tag"), input$selectedWorkflowSecLabel) + rclipButton( + inputId = "clipbtn", + label = "", + clipText = input$selectedWorkflowId, + icon = icon("clipboard"), + tooltip = "Copy workflow ID", + placement = "left", + options = list(delay = list(show = 800, hide = 100), trigger = "hover"), + class = "btn-secondary btn-sm" + ), + input$selectedWorkflowId ) ) } diff --git a/app/ui.R b/app/ui.R index 2959319..851d30c 100644 --- a/app/ui.R +++ b/app/ui.R @@ -52,8 +52,11 @@ ui <- cookies::add_cookie_handlers( }" ), ), - nav_panel(title = "Track workflows", tab_tracking, rclipboard::rclipboardSetup()), + nav_panel(title = "Track workflows", tab_tracking, + rclipboard::rclipboardSetup() + ), nav_panel(title = "Workflow Details", tab_workflow_details, + rclipboard::rclipboardSetup(), tags$head( tags$script(src = "https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js") ) From c3606d13502d6448e3147de3f1b89abcae5797eb Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 21:59:09 -0700 Subject: [PATCH 19/23] #160 workflow details work - add spinners to most tabs in workflow details tab - add alert to workflow options tab when theres no data to show - clean up some code --- app/server.R | 88 ++++++++++++++++++++++---------------- app/tab-troubleshoot.R | 6 ++- app/tab-workflow_details.R | 31 +++++++++++--- app/utils.R | 6 +++ 4 files changed, 86 insertions(+), 45 deletions(-) diff --git a/app/server.R b/app/server.R index c6ffd97..174abbc 100644 --- a/app/server.R +++ b/app/server.R @@ -947,24 +947,36 @@ server <- function(input, output, session) { }, names(workflowLabelsLst), unname(workflowLabelsLst)) ) }) - ## Get a table of workflow options - workflowOptions <- eventReactive(input$joblistCromwell_rows_selected, { - print("find options") - data <- workflowUpdate() - FOCUS_ID <- data[input$joblistCromwell_rows_selected, ]$workflow_id + + ## Workflow options + workflowOptions <- eventReactive(input$selectedWorkflowId, { as.data.frame(jsonlite::fromJSON( - cromwell_workflow(FOCUS_ID, + cromwell_workflow(input$selectedWorkflowId, url = rv$url, token = rv$token )$options )) }) - output$workflowOpt <- renderDT( - data <- workflowOptions(), - class = "compact", - filter = "top", - options = list(scrollX = TRUE), selection = "single", rownames = FALSE - ) + + output$workflowOpt <- renderUI({ + if (NROW(workflowOptions()) > 0) { + renderDT( + expr = workflowOptions(), + class = "compact", + filter = "top", + options = list(scrollX = TRUE), + selection = "single", + rownames = FALSE + ) + } else { + div( + "No options data found", + class = "alert alert-primary", + role = "alert" + ) + } + }) + ## Get a table of workflow inputs workflowInputs <- eventReactive(input$selectedWorkflowId, { print("find inputs") @@ -1008,13 +1020,11 @@ server <- function(input, output, session) { #### Call Data - callsUpdate <- eventReactive( - input$selectedWorkflowId, + callsUpdate <- eventReactive(input$selectedWorkflowId, { - data <- workflowUpdate() - FOCUS_ID <<- input$selectedWorkflowId print("callsUpdate(); Querying cromwell for metadata for calls.") - theseCalls <- cromwell_call(FOCUS_ID, + theseCalls <- cromwell_call( + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token ) @@ -1023,7 +1033,15 @@ server <- function(input, output, session) { } else { callDat <<- theseCalls %>% mutate(executionStatus = "NA") } - suppressWarnings(callDat %>% select(one_of("workflow_name", "detailedSubName", "callName", "executionStatus", "shardIndex", "callRoot", "start", "end", "callDuration", "docker", "modules"), everything())) + suppressWarnings( + callDat %>% + select( + one_of("workflow_name", "detailedSubName", "callName", + "executionStatus", "shardIndex", "callRoot", "start", + "end", "callDuration", "docker", "modules"), + everything() + ) + ) }, ignoreNULL = TRUE ) @@ -1072,24 +1090,22 @@ server <- function(input, output, session) { ## Failure data failsUpdate <- eventReactive(input$getFailedData, { - data <- workflowUpdate() - FOCUS_ID <- input$selectedWorkflowId - print("failsUpdate(); Querying cromwell for metadata for failures.") - suppressWarnings(failDat <- cromwell_failures(FOCUS_ID, + suppressWarnings(cromwell_failures( + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token ) %>% select(one_of( "callName", "jobId", "workflow_id", "detailedSubName", "shardIndex", "attempt", "failures.message", "failures.causedBy.message" - ), everything()) %>% unique()) - return(failDat) + ), everything()) %>% + unique()) }, ignoreNULL = TRUE ) output$failurelistBatch <- renderDT( - data <- failsUpdate(), + expr = failsUpdate(), class = "compact", filter = "top", options = list(scrollX = TRUE), @@ -1108,25 +1124,23 @@ server <- function(input, output, session) { ### Call Caching data cacheUpdate <- eventReactive(input$getCacheData, { - data <- workflowUpdate() - FOCUS_ID <<- input$selectedWorkflowId - print("cacheUpdate(); Querying cromwell for metadata for call caching.") - theseCache <- cromwell_cache(FOCUS_ID, + theseCache <- cromwell_cache( + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token ) if ("callCaching.effectiveCallCachingMode" %in% colnames(theseCache)) { - cacheDat <- theseCache + theseCache } else { - cacheDat <- theseCache %>% mutate(callCaching.effectiveCallCachingMode = "NA") + theseCache %>% + mutate(callCaching.effectiveCallCachingMode = "NA") } - cacheDat }, ignoreNULL = TRUE ) output$cachingListBatch <- renderDT( - data <- cacheUpdate() %>% + expr = cacheUpdate() %>% select( any_of( c("workflow_name", "workflow_id", "callName", "shardIndex", "executionStatus")), @@ -1152,10 +1166,8 @@ server <- function(input, output, session) { ### Go get the output data for the selected workflow outputsUpdate <- eventReactive(input$getOutputData, { - data <- workflowUpdate() - FOCUS_ID <<- input$selectedWorkflowId - print("outputsUpdate(); Querying cromwell for a list of workflow outputs.") - outDat <<- try(cromwell_outputs(FOCUS_ID, + outDat <<- try(cromwell_outputs( + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token ), silent = TRUE) @@ -1168,7 +1180,7 @@ server <- function(input, output, session) { ) ## render outputs list to a table output$outputslistBatch <- renderDT( - data <- outputsUpdate(), + expr = outputsUpdate(), class = "compact", filter = "top", options = list(scrollX = TRUE), diff --git a/app/tab-troubleshoot.R b/app/tab-troubleshoot.R index 52ca7bc..2a9b195 100644 --- a/app/tab-troubleshoot.R +++ b/app/tab-troubleshoot.R @@ -1,5 +1,7 @@ library(shinyjs) +source("utils.R") + panel_troublehsoot <- nav_panel(title = "Troubleshoot", card( class = "border border-primary", @@ -9,7 +11,9 @@ panel_troublehsoot <- nav_panel(title = "Troubleshoot", fillable = FALSE, p("When a workflow fails but no jobs were started, or there appears to be no clear reason for a workflow to have failed, this tool can provide you the entire set of workflow metadata Cromwell has for your workflow in it's raw and unprocessed (json) form. For complex workflows, this can be rather large (and ugly!)."), br(), - verbatimTextOutput(outputId = "troubleResult") + load_spinner( + verbatimTextOutput(outputId = "troubleResult") + ) ) ), shinyjs::useShinyjs() diff --git a/app/tab-workflow_details.R b/app/tab-workflow_details.R index 5c14042..9c93bd5 100644 --- a/app/tab-workflow_details.R +++ b/app/tab-workflow_details.R @@ -1,24 +1,31 @@ library(listviewer) source("tab-troubleshoot.R") +source("utils.R") panel_job_list <- nav_panel( title = "Job List", downloadButton("downloadJobs", "Download Workflow Jobs Data", style = "width:20%"), - DTOutput("tasklistBatch") + load_spinner( + DTOutput("tasklistBatch") + ) ) panel_workflow_description <- nav_panel( title = "Workflow Description", card_body( - uiOutput("workflowDescribe") + load_spinner( + uiOutput("workflowDescribe") + ) ) ) panel_diagram <- nav_panel( title = "Diagram", - uiOutput("mermaid_diagram") + load_spinner( + uiOutput("mermaid_diagram") + ) ) panel_job_failures <- nav_panel( @@ -47,12 +54,22 @@ panel_call_caching <- nav_panel( panel_options <- nav_panel( title = "Workflow Options", - DTOutput("workflowOpt") + card( + class = "border border-primary", + card_body( + fillable = TRUE, + load_spinner( + uiOutput("workflowOpt") + ) + ) + ) ) panel_inputs <- nav_panel( title = "Workflow Inputs", - reactjsonOutput("workflowInp", height = "100%") + load_spinner( + reactjsonOutput("workflowInp", height = "100%") + ) ) panel_outputs <- nav_panel( @@ -64,7 +81,9 @@ panel_outputs <- nav_panel( icon("refresh") ), downloadButton("downloadOutputs", "Download Workflow Output Data"), - DTOutput("outputslistBatch") + load_spinner( + DTOutput("outputslistBatch") + ) ) tab_workflow_details <- card( diff --git a/app/utils.R b/app/utils.R index e57bb12..55528b6 100644 --- a/app/utils.R +++ b/app/utils.R @@ -4,6 +4,12 @@ library(parsedate) library(uuid) library(rclipboard) library(shinyFeedback) +library(shinycssloaders) + +# Wrapped in a function so we can change options in one place +load_spinner <- function(...) { + shinycssloaders::withSpinner(...) +} # exact copy from shiny:::validateIcon proofValidateIcon <- function (icon) { From 6115cc0a1f76ad0b0c204249c1f4f23cd1838521 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Mon, 28 Oct 2024 22:04:28 -0700 Subject: [PATCH 20/23] code cleanup, remove an old file, and remove focus_id stuff --- app/server.R | 25 +++++-------------------- app/tab-details.R | 20 -------------------- 2 files changed, 5 insertions(+), 40 deletions(-) delete mode 100644 app/tab-details.R diff --git a/app/server.R b/app/server.R index 174abbc..333ec42 100644 --- a/app/server.R +++ b/app/server.R @@ -42,7 +42,6 @@ source("cookies-db.R") SANITIZE_ERRORS <- FALSE PROOF_TIMEOUT <- 20 -FOCUS_ID <- 1 SHINY_LOGGING <- as.logical(Sys.getenv("SHINY_LOG", FALSE)) # FIXME: maybe remove later, was running into some timeouts during testing @@ -890,9 +889,8 @@ server <- function(input, output, session) { ## Get a table of workflow labels workflowLabels <- eventReactive(input$selectedWorkflowId, { print("find Labels") - data <- workflowUpdate() - FOCUS_ID <- input$selectedWorkflowId - workflow <- cromwell_workflow(FOCUS_ID, + workflow <- cromwell_workflow( + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token ) @@ -930,7 +928,7 @@ server <- function(input, output, session) { everything() ) ) - }) + }) output$workflowDescribe <- renderUI({ wl <- purrr::discard_at(workflowLabels(), c("workflow", "inputs")) @@ -979,15 +977,8 @@ server <- function(input, output, session) { ## Get a table of workflow inputs workflowInputs <- eventReactive(input$selectedWorkflowId, { - print("find inputs") - data <- workflowUpdate() - - FOCUS_ID <- input$selectedWorkflowId - output$currentWorkflowId <- renderText({ - paste("Workflow ID: ", FOCUS_ID) - }) - - cromwell_workflow(FOCUS_ID, + cromwell_workflow( + workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token )$inputs @@ -1000,11 +991,6 @@ server <- function(input, output, session) { observeEvent(input$workflowInp_edit, { str(input$workflowInp_edit, max.level=2) }) - ### set workflow id display in viewer tab back to none - ### when nothing selected in the Workflows Run table - observeEvent(input$joblistCromwell_rows_selected, { - output$currentWorkflowId <- renderText({"Workflow ID: "}) - }, ignoreNULL = FALSE) ## Render a list of jobs in a table for a workflow output$joblistCromwell <- renderDT({ @@ -1022,7 +1008,6 @@ server <- function(input, output, session) { #### Call Data callsUpdate <- eventReactive(input$selectedWorkflowId, { - print("callsUpdate(); Querying cromwell for metadata for calls.") theseCalls <- cromwell_call( workflow_id = input$selectedWorkflowId, url = rv$url, diff --git a/app/tab-details.R b/app/tab-details.R deleted file mode 100644 index 083f9cb..0000000 --- a/app/tab-details.R +++ /dev/null @@ -1,20 +0,0 @@ -library(listviewer) - -tab_details <- card( - id = "details", - navset_underline( - nav_panel( - title = "Workflow Inputs", - textOutput("currentWorkflowId"), - p(""), - actionButton("linkToTrackingTab_from_workflow_inputs", "Back to Track Jobs Tab", width = "250px"), - p(""), - reactjsonOutput("workflowInp", height = "100%") - ), - nav_panel( - title = "Mermaid", - actionButton("linkToTrackingTab_from_mermaid", "Back to Track Jobs Tab", width = "250px"), - uiOutput("mermaid_diagram") - ) - ) -) From a079cefff9905dcfdf8e5e809abab8cb892d0257 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Tue, 29 Oct 2024 06:51:23 -0700 Subject: [PATCH 21/23] #160 workflow details - add no data alerts to tabs where appropriate; make buttons a reasonable size --- app/server.R | 75 +++++++++++++++++++++++++------------- app/tab-workflow_details.R | 48 ++++++++++++++---------- app/ui.R | 1 - app/utils.R | 8 ++++ 4 files changed, 86 insertions(+), 46 deletions(-) diff --git a/app/server.R b/app/server.R index 333ec42..f5fb9ee 100644 --- a/app/server.R +++ b/app/server.R @@ -1097,6 +1097,20 @@ server <- function(input, output, session) { rownames = FALSE ) + output$failurelistBatch <- renderUI({ + if (NROW(failsUpdate()) > 0) { + renderDT( + expr = failsUpdate(), + class = "compact", + filter = "top", + options = list(scrollX = TRUE), + rownames = FALSE + ) + } else { + alert("No failures data found") + } + }) + output$downloadFails <- downloadHandler( filename = function() { paste0(unique(failsUpdate()$workflow_id), "-callFailureData.csv") @@ -1124,19 +1138,26 @@ server <- function(input, output, session) { ignoreNULL = TRUE ) - output$cachingListBatch <- renderDT( - expr = cacheUpdate() %>% - select( - any_of( - c("workflow_name", "workflow_id", "callName", "shardIndex", "executionStatus")), - everything() - ) %>% - unique(), - class = "compact", - filter = "top", - options = list(scrollX = TRUE), - rownames = FALSE - ) + output$cachingListBatch <- renderUI({ + if (NROW(cacheUpdate()) > 0) { + renderDT( + expr = cacheUpdate() %>% + select( + any_of( + c("workflow_name", "workflow_id", "callName", + "shardIndex", "executionStatus")), + everything() + ) %>% + unique(), + class = "compact", + filter = "top", + options = list(scrollX = TRUE), + rownames = FALSE + ) + } else { + alert("No call caching data found") + } + }) output$downloadCache <- downloadHandler( filename = function() { @@ -1151,26 +1172,28 @@ server <- function(input, output, session) { ### Go get the output data for the selected workflow outputsUpdate <- eventReactive(input$getOutputData, { - outDat <<- try(cromwell_outputs( + cromwell_outputs( workflow_id = input$selectedWorkflowId, url = rv$url, token = rv$token - ), silent = TRUE) - if (!is.data.frame(outDat)) { - outDat <- dplyr::tibble("workflow_id" = "No outputs are available for this workflow yet.") - } - outDat + ) }, ignoreNULL = TRUE ) ## render outputs list to a table - output$outputslistBatch <- renderDT( - expr = outputsUpdate(), - class = "compact", - filter = "top", - options = list(scrollX = TRUE), - rownames = FALSE - ) + output$outputslistBatch <- renderUI({ + if (NROW(outputsUpdate()) > 0) { + renderDT( + expr = outputsUpdate(), + class = "compact", + filter = "top", + options = list(scrollX = TRUE), + rownames = FALSE + ) + } else { + alert("No output data found") + } + }) ## Prep outputs table for download output$downloadOutputs <- downloadHandler( filename = function() { diff --git a/app/tab-workflow_details.R b/app/tab-workflow_details.R index 9c93bd5..bfafe30 100644 --- a/app/tab-workflow_details.R +++ b/app/tab-workflow_details.R @@ -34,10 +34,15 @@ panel_job_failures <- nav_panel( actionButton( inputId = "getFailedData", label = "Get/Refresh Failed Job Metadata", - icon("refresh") + icon = icon("refresh"), + width = "300px" ), - downloadButton("downloadFails", "Download Call Failure Data"), - DTOutput("failurelistBatch") + downloadButton( + outputId = "downloadFails", + label = "Download Call Failure Data", + style = "width:300px;" + ), + uiOutput("failurelistBatch") ) panel_call_caching <- nav_panel( @@ -46,22 +51,24 @@ panel_call_caching <- nav_panel( actionButton( inputId = "getCacheData", label = "Get/Refresh Call Caching Metadata", - icon("refresh") + icon = icon("refresh"), + width = "300px" + ), + downloadButton( + outputId = "downloadCache", + label = "Download Call Caching Data", + style = "width:300px;" ), - downloadButton("downloadCache", "Download Call Caching Data"), - DTOutput("cachingListBatch") + load_spinner( + uiOutput("cachingListBatch") + ) ) panel_options <- nav_panel( title = "Workflow Options", - card( - class = "border border-primary", - card_body( - fillable = TRUE, - load_spinner( - uiOutput("workflowOpt") - ) - ) + br(), + load_spinner( + uiOutput("workflowOpt") ) ) @@ -78,12 +85,15 @@ panel_outputs <- nav_panel( actionButton( inputId = "getOutputData", label = "Get/Refresh Workflow Output Metadata", - icon("refresh") + icon = icon("refresh"), + width = "350px" ), - downloadButton("downloadOutputs", "Download Workflow Output Data"), - load_spinner( - DTOutput("outputslistBatch") - ) + downloadButton( + outputId = "downloadOutputs", + label = "Download Workflow Output Data", + style = "width:350px;" + ), + uiOutput("outputslistBatch") ) tab_workflow_details <- card( diff --git a/app/ui.R b/app/ui.R index 851d30c..f4c704a 100644 --- a/app/ui.R +++ b/app/ui.R @@ -24,7 +24,6 @@ source("tab-validate.R") source("tab-submission.R") source("tab-tracking.R") source("tab-workflow_details.R") -source("tab-details.R") ui <- cookies::add_cookie_handlers( page_navbar( diff --git a/app/utils.R b/app/utils.R index 55528b6..aa44f9a 100644 --- a/app/utils.R +++ b/app/utils.R @@ -185,3 +185,11 @@ card_header_color <- function(status) { parse_date_tz <- function(x, tz = "America/Los_Angeles") { parsedate::parse_date(x, default_tz = tz) } + +alert <- function(..., class = "alert alert-primary") { + div( + ..., + class = class, + role = "alert" + ) +} From 8a03d230a268912b0991e842eaa926a865f692a1 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Tue, 29 Oct 2024 15:57:51 -0700 Subject: [PATCH 22/23] make login button green and add spinner to login modal; FH logo link to fredhutch.org --- app/buttons.R | 2 +- app/modals.R | 6 +++++- app/server.R | 3 +++ app/ui.R | 15 +++++++++------ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/buttons.R b/app/buttons.R index 30d3665..19bef6c 100644 --- a/app/buttons.R +++ b/app/buttons.R @@ -2,7 +2,7 @@ logInButton <- actionButton( inputId = "proofAuth", label = "PROOF Login", - class = "btn-sm", + class = "btn-success btn-sm", style = "color: white;", icon = icon("truck-fast") diff --git a/app/modals.R b/app/modals.R index 464e939..9ee890f 100644 --- a/app/modals.R +++ b/app/modals.R @@ -13,7 +13,11 @@ loginModal <- function(failed = FALSE, error = "Invalid username or password") { }, footer = tagList( modalButton("Cancel"), - actionButton("submit", "Submit") + shinyFeedback::loadingButton( + inputId = "submit", + label = "Submit", + class = "btn btn-default" + ) ), easyClose = TRUE ) diff --git a/app/server.R b/app/server.R index f5fb9ee..eb83f54 100644 --- a/app/server.R +++ b/app/server.R @@ -184,6 +184,9 @@ server <- function(input, output, session) { same_site = "strict" ) + # reset loading spinner + shinyFeedback::resetLoadingButton("submit") + removeModal() } } else { diff --git a/app/ui.R b/app/ui.R index f4c704a..3033808 100644 --- a/app/ui.R +++ b/app/ui.R @@ -29,12 +29,15 @@ ui <- cookies::add_cookie_handlers( page_navbar( id = "proof", title = tags$span( - tags$img( - src = "fred-hutch.png", - width = "96px", - height = "auto", - class = "me-3", - alt = "Fred Hutch logo" + tags$a( + tags$img( + src = "fred-hutch.png", + width = "96px", + height = "auto", + class = "me-3", + alt = "Fred Hutch logo" + ), + href = "https://www.fredhutch.org" ), "" ), From 487481c6247e86ef435cf447fb8c64e427cbc294 Mon Sep 17 00:00:00 2001 From: Scott Chamberlain Date: Wed, 30 Oct 2024 11:39:24 -0700 Subject: [PATCH 23/23] bump mermaid.js to 11.4.0 --- app/ui.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ui.R b/app/ui.R index 3033808..f8ea8d0 100644 --- a/app/ui.R +++ b/app/ui.R @@ -60,7 +60,7 @@ ui <- cookies::add_cookie_handlers( nav_panel(title = "Workflow Details", tab_workflow_details, rclipboard::rclipboardSetup(), tags$head( - tags$script(src = "https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js") + tags$script(src = "https://cdn.jsdelivr.net/npm/mermaid@11.4.0/dist/mermaid.min.js") ) ), nav_panel(title = "Help",