19783: Review updates
authorPeter Amstutz <peter.amstutz@curii.com>
Fri, 9 Dec 2022 20:19:22 +0000 (15:19 -0500)
committerPeter Amstutz <peter.amstutz@curii.com>
Fri, 9 Dec 2022 20:19:22 +0000 (15:19 -0500)
Load fewer items to be more responsive & update message when not
everything was listed.

Use full text search instead of substring search on names.

Tweak search box help text.

Fix bug where collections used PDH instead of UUID as tree ids,
resulting in collisions and weird behavior.

Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

src/services/api/filter-builder.ts
src/store/tree-picker/tree-picker-actions.ts
src/views-components/projects-tree-picker/projects-tree-picker.tsx

index da67935a1e5d8a44c5bf2c601c3fc639204ca8ab..bb97665a8c6652a7b89324872a416e3b39c343a5 100644 (file)
@@ -64,7 +64,7 @@ export class FilterBuilder {
         return this.addCondition("properties." + field, "exists", false, "", "", resourcePrefix);
     }
 
-    public addFullTextSearch(value: string) {
+    public addFullTextSearch(value: string, table?: string) {
         const regex = /"[^"]*"/;
         const matches: any[] = [];
 
@@ -76,10 +76,15 @@ export class FilterBuilder {
             match = value.match(regex);
         }
 
+        let searchIn = 'any';
+        if (table) {
+            searchIn = table + ".any";
+        }
+
         const terms = value.trim().split(/(\s+)/).concat(matches);
         terms.forEach(term => {
             if (term !== " ") {
-                this.addCondition("any", "ilike", term, "%", "%");
+                this.addCondition(searchIn, "ilike", term, "%", "%");
             }
         });
         return this;
index cabc9f7211ca40d279677803895696bc8efebafd..460a23e3d778c0d3670e5d360ef06bdb00a0f408 100644 (file)
@@ -136,24 +136,26 @@ export const loadProject = (params: LoadProjectParamsWithId) =>
         const state = getState();
 
         if (state.treePickerSearch.collectionFilterValues[pickerId]) {
-            filterB = filterB.addILike('collections.name', state.treePickerSearch.collectionFilterValues[pickerId]);
+            filterB = filterB.addFullTextSearch(state.treePickerSearch.collectionFilterValues[pickerId], 'collections');
         } else {
             filterB = filterB.addNotIn("collections.properties.type", ["intermediate", "log"]);
         }
 
         if (searchProjects && state.treePickerSearch.projectSearchValues[pickerId]) {
-            filterB = filterB.addILike('groups.name', state.treePickerSearch.projectSearchValues[pickerId]);
+            filterB = filterB.addFullTextSearch(state.treePickerSearch.projectSearchValues[pickerId], 'groups');
         }
 
         const filters = filterB.getFilters();
 
-        const { items, itemsAvailable } = await services.groupsService.contents((loadShared || searchProjects) ? '' : id, { filters, excludeHomeProject: loadShared || undefined, limit: 1000 });
+        const itemLimit = 200;
 
-        if (itemsAvailable > 1000) {
+        const { items, itemsAvailable } = await services.groupsService.contents((loadShared || searchProjects) ? '' : id, { filters, excludeHomeProject: loadShared || undefined, limit: itemLimit });
+
+        if (itemsAvailable > itemLimit) {
             items.push({
                 uuid: "more-items-available",
                 kind: ResourceKind.WORKFLOW,
-                name: "*** Not all items were loaded (limit 1000 items) ***",
+                name: `*** Not all items listed (${items.length} out of ${itemsAvailable}), reduce item count with search or filter ***`,
                 description: "",
                 definition: "",
                 ownerUuid: "",
@@ -208,7 +210,7 @@ export const loadCollection = (id: string, pickerId: string) =>
 
             const node = getNode(id)(picker);
             if (node && 'kind' in node.value && node.value.kind === ResourceKind.COLLECTION) {
-                const files = await services.collectionService.files(node.value.portableDataHash);
+                const files = await services.collectionService.files(node.value.uuid);
                 const tree = createCollectionFilesTree(files);
                 const sorted = sortFilesTree(tree);
                 const filesTree = mapTreeValues(services.collectionService.extendFileURL)(sorted);
index de7362d93cdd70b19086b7ae1d67a4a622baad48..2711c77725d4f8dc83c00949927d2c49e918acc5 100644 (file)
@@ -81,7 +81,7 @@ type CssRules = 'pickerHeight' | 'searchFlex' | 'scrolledBox';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     pickerHeight: {
-        height: "70vh"
+        height: "calc(70vh - 100px)"
     },
     searchFlex: {
         display: "flex",
@@ -89,7 +89,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         paddingBottom: "1em"
     },
     scrolledBox: {
-        height: "100%",
+        height: "calc(100% - 50px)",
         overflow: "scroll"
     }
 });
@@ -142,9 +142,9 @@ export const ProjectsTreePicker = connect(mapStateToProps, mapDispatchToProps)(
                 };
                 return <div className={this.props.classes.pickerHeight} >
                     <span className={this.props.classes.searchFlex}>
-                        <SearchInput value="" label="Search all Projects" selfClearProp='' onSearch={onProjectSearch} debounce={200} />
+                        <SearchInput value="" label="Search for a Project" selfClearProp='' onSearch={onProjectSearch} debounce={200} />
                         {this.props.includeCollections &&
-                            <SearchInput value="" label="Filter Collections inside Projects" selfClearProp='' onSearch={onCollectionFilter} debounce={200} />}
+                            <SearchInput value="" label="Filter Collections list in Projects" selfClearProp='' onSearch={onCollectionFilter} debounce={200} />}
                     </span>
 
                     <div className={this.props.classes.scrolledBox}>