From 1844a1d132c451fe671145eb60fc92656b247d55 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Wed, 8 Nov 2023 13:52:01 -0500 Subject: [PATCH] Configurable item list grid view The item list view can switch to a grid mode. This could use some better styling for the column titles, for the short grid items, and for individual column entries in the grid view. --- CHANGELOG.md | 1 + docs/girder_config_options.rst | 18 ++++++++++ .../web_client/stylesheets/itemList.styl | 14 ++++++++ .../web_client/templates/itemList.pug | 34 +++++++++++++++---- test/test_files/.large_image_config.yaml | 10 ++++++ 5 files changed, 70 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b24dbfe9a..3f74318af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Improvements - Have zarr use read-only mode ([#1360](../../pull/1360)) - Use minified geojs ([#1362](../../pull/1362)) +- Configurable item list grid view ([#1363](../../pull/1363)) ### Bug Fixes - Default to "None" for the DICOM assetstore limit ([#1359](../../pull/1359)) diff --git a/docs/girder_config_options.rst b/docs/girder_config_options.rst index 8f8716c2e..78ef39d40 100644 --- a/docs/girder_config_options.rst +++ b/docs/girder_config_options.rst @@ -55,6 +55,13 @@ This is used to specify how items appear in item lists. There are two settings, --- # If present, show a table with column headers in item lists itemList: + # layout does not need to be specified. + layout: + # The default layout is a list. This can optionally be "grid" + mode: grid + # max-width is only used in grid mode. It is the maximum width in + # pixels for grid entries. It defaults to 250. + max-width: 250 # show these columns in order from left to right. Each column has a # "type" and "value". It optionally has a "title" used for the column # header, and a "format" used for searching and filtering. @@ -99,6 +106,17 @@ This is used to specify how items appear in item lists. There are two settings, # the length of arrays. value: gloms.length title: Number of Gloms + # You can have this value be populated for just some of the items by + # specifying an "only" list. Each entry in the only list must have + # the "type" and "value" as per the column it is filtering on, plus a + # "match" value that is used as a case-insensitive RegExp. All such + # limits must match to show the value. + only: + - + type: record + value: name + # only show this for items whose names end with ".svs". + match: "\\.svs$" # You can edit metadata in a item list by adding the edit: true entry # and the options from the itemMetadata records that are detailed # below. In this case, edits to metadata that validate are saved diff --git a/girder/girder_large_image/web_client/stylesheets/itemList.styl b/girder/girder_large_image/web_client/stylesheets/itemList.styl index de559d012..69b605c22 100644 --- a/girder/girder_large_image/web_client/stylesheets/itemList.styl +++ b/girder/girder_large_image/web_client/stylesheets/itemList.styl @@ -84,6 +84,20 @@ ul.g-item-list justify-content center width inherit + &.li-item-list[layout_mode="grid"] + display block + + &>li.g-item-list-entry + display inline-block + overflow hidden + border 1px solid rgba(0, 0, 0, 0.1) + padding 1px + vertical-align top + max-width 250px + + &>li>.li-item-list-cell + display inline-block + .li-item-list-filter padding-left 12px diff --git a/girder/girder_large_image/web_client/templates/itemList.pug b/girder/girder_large_image/web_client/templates/itemList.pug index 857191a08..d186bf75e 100644 --- a/girder/girder_large_image/web_client/templates/itemList.pug +++ b/girder/girder_large_image/web_client/templates/itemList.pug @@ -1,18 +1,20 @@ -ul.g-item-list.li-item-list +ul.g-item-list.li-item-list(layout_mode=(itemList.layout || {}).mode || '') + - var colNames = []; li.li-item-list-header if checkboxes span.li-item-list-header - for column in itemList.columns + for column, colidx in itemList.columns if column.type !== 'image' || hasAnyLargeImage span.li-item-list-header( class=((column.type === 'record' && column.value !== 'controls') || column.type === 'metadata' ? 'sortable' : '') + ' ' + (sort && sort[0].type === column.type && sort[0].value === column.value ? sort[0].dir : ''), column_type=column.type, column_value=column.value) if column.title !== undefined - = column.title + - colNames[colidx] = column.title else - = `${column.value.substr(0, 1).toUpperCase()}${column.value.substr(1)}` + - colNames[colidx] = `${column.value.substr(0, 1).toUpperCase()}${column.value.substr(1)}` + = colNames[colidx] each item in items - li.g-item-list-entry(class=(highlightItem && item.id === selectedItemId ? 'g-selected' : ''), public=(isParentPublic ? 'true' : 'false')) + li.g-item-list-entry(class=(highlightItem && item.id === selectedItemId ? 'g-selected' : ''), public=(isParentPublic ? 'true' : 'false'), style=(itemList.layout || {}).mode == 'grid' ? ('max-width: ' + parseInt((itemList.layout || {})['max-width'] || 250) + 'px') : '') if checkboxes span.li-item-list-cell input.g-list-checkbox(type="checkbox", g-item-cid=item.cid) @@ -23,8 +25,26 @@ ul.g-item-list.li-item-list var classes = divtype == 'a' ? ['g-item-list-link']: []; if (('' + column.type + column.value).match(/^[a-zA-Z][a-zA-Z0-9-_]*$/)) classes.push(`li-column-${column.type}-${column.value}`); if (('' + column.type).match(/^[a-zA-Z][a-zA-Z0-9-_]*$/)) classes.push(`li-column-${column.type}`); - #{divtype}.li-item-list-cell(class=classes.join(' '), g-item-cid=item.cid, href=`#item/${item.id}`) - if column.type === 'record' + var skip = false; + (column.only || []).forEach((only) => { + if (!(only || {}).match) { + return; + } + var onlyval = (only.type === 'record' && only.value === 'name') ? item.name() : (only.type === 'record' && only.value === 'description') ? item.get(only.value) : ''; + if (only.type === 'metadata') { + onlyval = item.get('meta') || {}; + only.value.split('.').forEach((part) => { + onlyval = (onlyval || {})[part]; + }) + } + if (onlyval.match(new RegExp(only.match, 'i')) === null) { + skip = true; + } + }); + #{divtype}.li-item-list-cell(class=classes.join(' '), g-item-cid=item.cid, href=`#item/${item.id}`, title=colNames[colidx]) + if skip + //- ignore + else if column.type === 'record' if column.value === 'name' span.g-item-list-link i.icon-doc-text-inv diff --git a/test/test_files/.large_image_config.yaml b/test/test_files/.large_image_config.yaml index 0dee9d424..24693f87d 100644 --- a/test/test_files/.large_image_config.yaml +++ b/test/test_files/.large_image_config.yaml @@ -3,6 +3,11 @@ access: user: # itemList adjustments itemList: + layout: + # grid or list + # mode: grid + # for grids, how wide should items be + min-width: 200 # Show these columns columns: - @@ -24,6 +29,11 @@ access: type: metadata value: Stain format: text + # Only show this record for entries that match a particular value + only: + - type: record + value: name + match: "\\.svs$" - type: metadata value: Classification