2020import org .labkey .api .util .Pair ;
2121import org .labkey .test .BaseWebDriverTest ;
2222import org .labkey .test .Locator ;
23+ import org .labkey .test .WebTestHelper ;
2324import org .labkey .test .categories .External ;
2425import org .labkey .test .categories .MacCossLabModules ;
2526import org .labkey .test .components .WebPart ;
27+ import org .labkey .test .components .html .BootstrapMenu ;
2628import org .labkey .test .components .panoramapublic .TargetedMsExperimentWebPart ;
2729import org .labkey .test .pages .panoramapublic .DataValidationPage ;
2830import org .labkey .test .util .DataRegionTable ;
31+ import org .labkey .test .util .EscapeUtil ;
2932import org .labkey .test .util .Ext4Helper ;
3033import org .labkey .test .util .TextSearcher ;
34+ import org .openqa .selenium .WebElement ;
3135
3236import java .util .ArrayList ;
3337import java .util .List ;
38+ import java .util .Map ;
3439
40+ import static org .junit .Assert .assertEquals ;
41+ import static org .junit .Assert .assertFalse ;
3542import static org .junit .Assert .assertNotEquals ;
3643import static org .junit .Assert .assertNotNull ;
3744import static org .junit .Assert .assertTrue ;
@@ -107,6 +114,12 @@ public void testAddModInfo()
107114 testCustomizeGrid (STRUCTURAL_MOD , true );
108115 testCustomizeGrid (ISOTOPE_MOD , true );
109116
117+ // The web part title links to the full query grid. It must not let a caller widen the
118+ // scope to all folders.
119+ verifyModificationQueryScopeIsRestricted ();
120+ // The standalone web part grid on this page must not be widened by a URL either.
121+ verifyModificationWebPartScopeIsRestricted ();
122+
110123 // Match structural modification
111124 goToExperimentDetailsPage ();
112125 testSaveMatchForStructuralMod (propionylation , List .of (propionyl , new Unimod (206 , "Delta:H(4)C(3)O(1)" , propionyl .getFormula ())),
@@ -128,6 +141,65 @@ public void testAddModInfo()
128141 testCopy (projectName , folderName , experimentTitle , folderName + " Copy" );
129142 }
130143
144+ // CreateView on these queries restricts the grids to the current folder or the current folder and subfolders.
145+ // Check that a wider scope asked for in the URL is restricted, and that an allowed scope still works.
146+ private void verifyModificationQueryScopeIsRestricted ()
147+ {
148+ for (String queryName : List .of ("IsotopeModifications" , "StructuralModifications" ))
149+ {
150+ // The Folder Filter dropdown offers the narrow scopes but not All Folders.
151+ assertFolderFilterMenuHidesAllFolders (queryName );
152+ // A URL asking for All Folders is restricted to the current and subfolders.
153+ assertContainerFilterScope (queryName , "AllFolders" , DataRegionTable .ContainerFilterType .CURRENT_AND_SUBFOLDERS );
154+ // "Current and Subfolders" is allowed.
155+ assertContainerFilterScope (queryName , "CurrentAndSubfolders" , DataRegionTable .ContainerFilterType .CURRENT_AND_SUBFOLDERS );
156+ }
157+ }
158+
159+ // The standalone modification web parts (added to a folder page, not the experiment details page)
160+ // read the scope straight from the URL. Check that a wider folder scope in the URL is restricted there too.
161+ private void verifyModificationWebPartScopeIsRestricted ()
162+ {
163+ for (String webPartName : List .of (STRUCTURAL_MOD , ISOTOPE_MOD ))
164+ {
165+ // Go to the dashboard tab that holds the web parts, then re-request the same page with a
166+ // "AllFolders" filter in the URL. The web part's data region is named after its title.
167+ goToDashboard ();
168+ String url = getCurrentRelativeURL ();
169+ url += (url .contains ("?" ) ? "&" : "?" ) + EscapeUtil .encode (webPartName ) + ".containerFilterName=AllFolders" ;
170+ beginAt (url );
171+ var grid = new DataRegionTable (webPartName , this );
172+ assertEquals ("Standalone '" + webPartName + "' web part should restrict an All Folders URL to the current and subfolders" ,
173+ DataRegionTable .ContainerFilterType .CURRENT_AND_SUBFOLDERS , grid .getContainerFilter ());
174+ }
175+ }
176+
177+ private void assertFolderFilterMenuHidesAllFolders (String queryName )
178+ {
179+ beginAt (WebTestHelper .buildURL ("query" , getCurrentContainerPath (), "executeQuery" ,
180+ Map .of ("schemaName" , "panoramapublic" , "query.queryName" , queryName )));
181+ BootstrapMenu viewsMenu = new DataRegionTable ("query" , this ).getViewsMenu ();
182+ viewsMenu .openMenuTo ("Folder Filter" , "Folder Filter" );
183+ List <String > options = viewsMenu .findVisibleMenuItems ().stream ().map (WebElement ::getText ).map (String ::trim ).toList ();
184+ // The allowed scope is present. This also guards against an empty menu making the check below pass for free.
185+ assertTrue ("Folder Filter for query '" + queryName + "' should offer 'Current folder and subfolders'. Found: " + options ,
186+ options .contains (DataRegionTable .ContainerFilterType .CURRENT_AND_SUBFOLDERS .getLabel ()));
187+ // All Folders is not offered.
188+ assertFalse ("Folder Filter for query '" + queryName + "' must not offer 'All Folders'. Found: " + options ,
189+ options .contains (DataRegionTable .ContainerFilterType .ALL_FOLDERS .getLabel ()));
190+ }
191+
192+ private void assertContainerFilterScope (String queryName , String requestedFilterName , DataRegionTable .ContainerFilterType expected )
193+ {
194+ beginAt (WebTestHelper .buildURL ("query" , getCurrentContainerPath (), "executeQuery" ,
195+ Map .of ("schemaName" , "panoramapublic" ,
196+ "query.queryName" , queryName ,
197+ "query.containerFilterName" , requestedFilterName )));
198+ var grid = new DataRegionTable ("query" , this );
199+ assertEquals ("Folder Filter for query '" + queryName + "' requested as '" + requestedFilterName + "' was not the expected scope" ,
200+ expected , grid .getContainerFilter ());
201+ }
202+
131203 private void testNoMatchForStructuralMod (String modificationName )
132204 {
133205 var modsTable = new DataRegionTable (STRUCTURAL_MOD , this );
0 commit comments