11package org .labkey .nextflow ;
22
3+ import lombok .Getter ;
4+ import lombok .Setter ;
35import org .apache .commons .lang3 .StringUtils ;
46import org .apache .logging .log4j .Logger ;
57import org .labkey .api .action .ApiResponse ;
68import org .labkey .api .action .ApiSimpleResponse ;
79import org .labkey .api .action .FormViewAction ;
810import org .labkey .api .action .MutatingApiAction ;
9- import org .labkey .api .action .SimpleViewAction ;
1011import org .labkey .api .action .SpringActionController ;
1112import org .labkey .api .admin .AdminUrls ;
1213import org .labkey .api .data .PropertyManager ;
1516import org .labkey .api .pipeline .PipelineJob ;
1617import org .labkey .api .pipeline .PipelineService ;
1718import org .labkey .api .pipeline .PipelineStatusUrls ;
19+ import org .labkey .api .pipeline .browse .PipelinePathForm ;
1820import org .labkey .api .security .AdminConsoleAction ;
1921import org .labkey .api .security .RequiresPermission ;
2022import org .labkey .api .security .permissions .AdminOperationsPermission ;
21- import org .labkey .api .security .permissions .InsertPermission ;
2223import org .labkey .api .security .permissions .ReadPermission ;
2324import org .labkey .api .security .permissions .SiteAdminPermission ;
2425import org .labkey .api .util .Button ;
26+ import org .labkey .api .util .DOM ;
27+ import org .labkey .api .util .FileUtil ;
28+ import org .labkey .api .util .HtmlString ;
2529import org .labkey .api .util .PageFlowUtil ;
30+ import org .labkey .api .util .Path ;
2631import org .labkey .api .util .URLHelper ;
32+ import org .labkey .api .util .element .Select ;
2733import org .labkey .api .util .logging .LogHelper ;
28- import org .labkey .api .view .ActionURL ;
2934import org .labkey .api .view .HtmlView ;
3035import org .labkey .api .view .JspView ;
3136import org .labkey .api .view .NavTree ;
3641import org .springframework .validation .Errors ;
3742import org .springframework .web .servlet .ModelAndView ;
3843
44+ import java .io .File ;
45+ import java .util .Arrays ;
46+ import java .util .List ;
47+
3948import static org .labkey .api .util .DOM .Attribute .checked ;
49+ import static org .labkey .api .util .DOM .Attribute .hidden ;
4050import static org .labkey .api .util .DOM .Attribute .method ;
4151import static org .labkey .api .util .DOM .Attribute .name ;
4252import static org .labkey .api .util .DOM .Attribute .type ;
4353import static org .labkey .api .util .DOM .Attribute .value ;
4454import static org .labkey .api .util .DOM .DIV ;
4555import static org .labkey .api .util .DOM .INPUT ;
4656import static org .labkey .api .util .DOM .LK .FORM ;
57+ import static org .labkey .api .util .DOM .UL ;
4758import static org .labkey .api .util .DOM .at ;
4859import static org .labkey .nextflow .NextFlowManager .NEXTFLOW_CONFIG ;
4960
@@ -59,32 +70,6 @@ public NextFlowController()
5970 setActionResolver (_actionResolver );
6071 }
6172
62- @ RequiresPermission (ReadPermission .class )
63- public static class BeginAction extends SimpleViewAction <Object >
64- {
65- @ Override
66- public ModelAndView getView (Object o , BindException errors )
67- {
68- boolean enabled = NextFlowManager .get ().isEnabled (getContainer ());
69- return new HtmlView ("NextFlow" ,
70- DIV (
71- DIV ("NextFlow integration is " + (enabled ? "enabled" : "disabled" ) + " in this " + (getContainer ().isProject () ? "project" : "folder" ) + "." ),
72- DIV (
73- getContainer ().hasPermission (getUser (), SiteAdminPermission .class ) ?
74- new Button .ButtonBuilder ("Enable/Disable" ).href (new ActionURL (NextFlowEnableAction .class , getContainer ())).build () : null ,
75- " " ,
76- enabled && getContainer ().hasPermission (getUser (), InsertPermission .class ) ?
77- new Button .ButtonBuilder ("Run NextFlow Analysis" ).href (new ActionURL (NextFlowRunAction .class , getContainer ())).build () : null )));
78- }
79-
80- @ Override
81- public void addNavTrail (NavTree root )
82- {
83- root .addChild ("NextFlow" );
84- }
85- }
86-
87-
8873 @ RequiresPermission (SiteAdminPermission .class )
8974 public static class DeleteNextFlowConfigurationAction extends MutatingApiAction <Object >
9075 {
@@ -196,8 +181,8 @@ public void setEnabled(Boolean enabled)
196181 }
197182 }
198183
199- @ RequiresPermission (SiteAdminPermission .class )
200- public static class NextFlowEnableAction extends FormViewAction <EnabledForm >
184+ @ RequiresPermission (ReadPermission .class )
185+ public static class BeginAction extends FormViewAction <EnabledForm >
201186 {
202187 @ Override
203188 public void validateCommand (EnabledForm target , Errors errors )
@@ -208,21 +193,30 @@ public void validateCommand(EnabledForm target, Errors errors)
208193 @ Override
209194 public ModelAndView getView (EnabledForm form , boolean reshow , BindException errors )
210195 {
211- Boolean status = NextFlowManager .get ().getEnabledState (getContainer ());
212- boolean inheritedStatus = NextFlowManager .get ().isEnabled (getContainer ().getParent ());
213-
214- return new HtmlView ("Enable/Disable NextFlow" ,
215- FORM (at (method , "POST" ),
216- DIV (INPUT (at (type , "radio" , name , "enabled" , value , Boolean .TRUE .toString (), (status == Boolean .TRUE ? checked : null ), null )),
217- "Enabled" ),
218- DIV (INPUT (at (type , "radio" , name , "enabled" , value , Boolean .FALSE .toString (), (status == Boolean .FALSE ? checked : null ), null )),
219- "Disabled" ),
220- DIV (INPUT (at (type , "radio" , name , "enabled" , value , "" , (status == null ? checked : null ), null )),
221- getContainer ().isRoot () ?
222- "Unset" :
223- "Inherited from " + getContainer ().getParent ().getPath () + " (currently " + (inheritedStatus ? "enabled" : "disabled" ) + ")" ),
224- new Button .ButtonBuilder ("Save" ).submit (true ).build (), " " ,
225- new Button .ButtonBuilder ("Cancel" ).href (getContainer ().getStartURL (getUser ())).build ()));
196+ if (getUser ().hasSiteAdminPermission ())
197+ {
198+ Boolean status = NextFlowManager .get ().getEnabledState (getContainer ());
199+ boolean inheritedStatus = NextFlowManager .get ().isEnabled (getContainer ().getParent ());
200+
201+ return new HtmlView ("Enable or Disable NextFlow" ,
202+ FORM (at (method , "POST" ),
203+ DIV (INPUT (at (type , "radio" , name , "enabled" , value , Boolean .TRUE .toString (), (status == Boolean .TRUE ? checked : null ), null )),
204+ "Enabled" ),
205+ DIV (INPUT (at (type , "radio" , name , "enabled" , value , Boolean .FALSE .toString (), (status == Boolean .FALSE ? checked : null ), null )),
206+ "Disabled" ),
207+ DIV (INPUT (at (type , "radio" , name , "enabled" , value , "" , (status == null ? checked : null ), null )),
208+ getContainer ().isRoot () ?
209+ "Unset" :
210+ "Inherited from " + getContainer ().getParent ().getPath () + " (currently " + (inheritedStatus ? "enabled" : "disabled" ) + ")" ),
211+ new Button .ButtonBuilder ("Save" ).submit (true ).build (), " " ,
212+ new Button .ButtonBuilder ("Cancel" ).href (getContainer ().getStartURL (getUser ())).build ()));
213+ }
214+ else
215+ {
216+ return new HtmlView ("NextFlow Integration Status" ,
217+ DIV ("NextFlow integration is " + (NextFlowManager .get ().isEnabled (getContainer ()) ? "enabled" : "disabled" ) + " in this " + (getContainer ().isProject () ? "project" : "folder" ) + "." )
218+ );
219+ }
226220 }
227221
228222 @ Override
@@ -235,7 +229,7 @@ public boolean handlePost(EnabledForm form, BindException errors)
235229 @ Override
236230 public void addNavTrail (NavTree root )
237231 {
238- root .addChild ("Enable/Disable NextFlow" );
232+ root .addChild ("NextFlow Integration Status " );
239233 }
240234
241235 @ Override
@@ -245,11 +239,18 @@ public URLHelper getSuccessURL(EnabledForm o)
245239 }
246240 }
247241
242+ @ Getter @ Setter
243+ public static class AnalyzeForm extends PipelinePathForm
244+ {
245+ private boolean launch = false ;
246+ private String configFile ;
247+ }
248+
248249 @ RequiresPermission (AdminOperationsPermission .class )
249- public class NextFlowRunAction extends FormViewAction <Object >
250+ public class NextFlowRunAction extends FormViewAction <AnalyzeForm >
250251 {
251252 @ Override
252- public void validateCommand (Object o , Errors errors )
253+ public void validateCommand (AnalyzeForm o , Errors errors )
253254 {
254255 if (!NextFlowManager .get ().isEnabled (getContainer ()))
255256 {
@@ -258,26 +259,69 @@ public void validateCommand(Object o, Errors errors)
258259 }
259260
260261 @ Override
261- public ModelAndView getView (Object o , boolean b , BindException errors )
262+ public ModelAndView getView (AnalyzeForm o , boolean b , BindException errors )
262263 {
263- return new HtmlView ("NextFlow Runner" , DIV ("Run NextFlow Pipeline" ,
264- FORM (at (method , "POST" ),
265- new Button .ButtonBuilder ("Start NextFlow" ).submit (true ).build ())));
264+ NextFlowConfiguration config = NextFlowManager .get ().getConfiguration ();
265+ if (config .getNextFlowConfigFilePath () != null )
266+ {
267+ File configDir = new File (config .getNextFlowConfigFilePath ());
268+ if (configDir .isDirectory ())
269+ {
270+ File [] files = configDir .listFiles ();
271+ if (files != null && files .length > 0 )
272+ {
273+ List <File > configFiles = Arrays .asList (files );
274+ return new HtmlView ("NextFlow Runner" , DIV (
275+ FORM (at (method , "POST" ),
276+ INPUT (at (hidden , true , name , "launch" , value , true )),
277+ Arrays .stream (o .getFile ()).map (f -> INPUT (at (hidden , true , name , "file" , value , f ))).toList (),
278+ "Files: " ,
279+ UL (Arrays .stream (o .getFile ()).map (DOM ::LI )),
280+ "Config: " ,
281+ new Select .SelectBuilder ().name ("configFile" ).addOptions (configFiles .stream ().filter (f -> f .isFile () && f .getName ().toLowerCase ().endsWith (".config" )).map (File ::getName ).sorted (String .CASE_INSENSITIVE_ORDER ).toList ()).build (),
282+ new Button .ButtonBuilder ("Start NextFlow" ).submit (true ).build ())));
283+ }
284+ }
285+ }
286+ return new HtmlView (HtmlString .of ("Couldn't find NextFlow config file(s)" ));
266287 }
267288
268289 @ Override
269- public boolean handlePost (Object o , BindException errors ) throws Exception
290+ public boolean handlePost (AnalyzeForm form , BindException errors ) throws Exception
270291 {
271- ViewBackgroundInfo info = getViewBackgroundInfo ();
272- PipeRoot root = PipelineService .get ().findPipelineRoot (info .getContainer ());
273- PipelineJob job = new NextFlowPipelineJob (info , root );
274- PipelineService .get ().queueJob (job );
292+ if (!form .isLaunch ())
293+ {
294+ return false ;
295+ }
296+
297+ NextFlowConfiguration config = NextFlowManager .get ().getConfiguration ();
298+ File configDir = new File (config .getNextFlowConfigFilePath ());
299+ File configFile = FileUtil .appendPath (configDir , Path .parse (form .getConfigFile ()));
300+ if (!configFile .exists ())
301+ {
302+ errors .reject (ERROR_MSG , "Config file does not exist" );
303+ }
304+ else
305+ {
306+ List <File > inputFiles = form .getValidatedFiles (getContainer ());
307+ if (inputFiles .isEmpty ())
308+ {
309+ errors .reject (ERROR_MSG , "No input files" );
310+ }
311+ else
312+ {
313+ ViewBackgroundInfo info = getViewBackgroundInfo ();
314+ PipeRoot root = PipelineService .get ().findPipelineRoot (info .getContainer ());
315+ PipelineJob job = NextFlowPipelineJob .create (info , root , configFile .toPath (), inputFiles .stream ().map (File ::toPath ).toList ());
316+ PipelineService .get ().queueJob (job );
317+ }
318+ }
275319
276320 return !errors .hasErrors ();
277321 }
278322
279323 @ Override
280- public URLHelper getSuccessURL (Object o )
324+ public URLHelper getSuccessURL (AnalyzeForm o )
281325 {
282326 return PageFlowUtil .urlProvider (PipelineStatusUrls .class ).urlBegin (getContainer ());
283327 }
0 commit comments