Skip to content

Commit

Permalink
Add and support app buttons
Browse files Browse the repository at this point in the history
This doesn't yet support custom icons or folder level buttons.

This also doesn't support custom open functions (just open urls).
  • Loading branch information
manthey committed Oct 17, 2024
1 parent 91dcdb7 commit e54f603
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 1.30.1

### Improvements

- Support generalized application buttons ([#1692](../../pull/1692))

### Bug Fixes

- Don't use a default for yaml config files except .large_image_config.yaml ([#1685](../../pull/1685))
Expand Down
4 changes: 4 additions & 0 deletions girder/girder_large_image/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def _groupingPipeline(initialPipeline, cbase, grouping, sort=None):
initialPipeline.append({'$set': {'firstOrder': {
'$mergeObjects': ['$firstOrder', centry]}}})
initialPipeline.append({'$replaceRoot': {'newRoot': '$firstOrder'}})
initialPipeline.append({'$set': {'meta._grouping': {
'keys': grouping['keys'],
'values': [f'${key}' for key in grouping['keys']],
}}})


def _itemFindRecursive( # noqa
Expand Down
7 changes: 6 additions & 1 deletion girder/girder_large_image/web_client/templates/itemList.pug
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ ul.g-item-list.li-item-list(layout_mode=(itemList.layout || {}).mode || '', meta
skip = true;
}
});
#{divtype}.li-item-list-cell(class=classes.join(' '), g-item-cid=item.cid, href=item._href ? item._href : `#item/${item.id}`, title=colNames[colidx])
#{divtype}.li-item-list-cell(class=classes.join(' '), g-item-cid=item.cid, href=item._href ? item._href : `#item/${item.id}`, title=colNames[colidx], target=item._href && item._hrefTarget ? item._hrefTarget : undefined)
if !skip && column.label
span.g-item-list-label
= column.label
Expand All @@ -62,6 +62,11 @@ ul.g-item-list.li-item-list(layout_mode=(itemList.layout || {}).mode || '', meta
a.g-view-inline(title="View in browser", target="_blank", rel="noopener noreferrer",
href=item.downloadUrl({contentDisposition: 'inline'}))
i.icon-eye
if availableApps && availableApps.items[item.id]
- const apps = Object.entries(availableApps.items[item.id]).sort(([name1, app1], [name2, app2]) => { let diff = (app1.priority || 0) - (app2.priority || 0); return diff ? diff : (registeredApps[name1].name.toLowerCase() > registeredApps[name2].name.toLowerCase() ? 1 : -1); })
for app in apps
a.g-hui-open-link(title="Open in " + registeredApps[app[0]].name, href=app[1].url target="_blank")
i.icon-link-ext
else if column.value === 'size'
.g-item-size= formatSize(item.get('size'))
else if column.value === 'description'
Expand Down
84 changes: 74 additions & 10 deletions girder/girder_large_image/web_client/views/itemList.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ wrap(HierarchyWidget, 'render', function (render) {
} else {
this.$('.li-flatten-item-list').removeClass('hidden');
}

const updateChecked = () => {
// const resources = this._getCheckedResourceParam();
// TODO: handle checked resources for apps
};

this.listenTo(this.itemListView, 'g:checkboxesChanged', updateChecked);
this.listenTo(this.folderListView, 'g:checkboxesChanged', updateChecked);
});

wrap(FolderListWidget, 'checkAll', function (checkAll, checked) {
Expand Down Expand Up @@ -277,13 +285,10 @@ wrap(ItemListWidget, 'render', function (render) {
return true;
}
if (nav.type === 'open') {
// TODO: handle open type
// we probably need to get all the grouped items to pass them to
// the .open-in-volview button via that _getCheckedResourceParam
// call OR modify the volview plugin to have an open item with less
// context. The current folder context would ideally be the
// deepest common parent rather than our current folder. Where
// does volview store its zip file?
if (item._href) {
window.open(item._href, '_blank');
return true;
}
}
return false;
};
Expand Down Expand Up @@ -447,13 +452,38 @@ wrap(ItemListWidget, 'render', function (render) {
}
};

this.checkApps = (resources) => {
const items = this.collection.models;
const folders = [this.parentView.parentModel];
const canHandle = {items: {}, folders: {}};
// TODO: handle checked resources
Object.entries(ItemListWidget.registeredApplications).forEach(([appname, app]) => {
items.forEach((item) => {
const check = app.check('item', item, this.parentView.parentModel);
if (check) {
canHandle.items[item.id] = canHandle.items[item.id] || {};
canHandle.items[item.id][appname] = check;
}
});
folders.forEach((folder) => {
const check = app.check('item', folder, this.parentView.parentModel);
if (check) {
canHandle.folders[folder.id] = canHandle.folders[folder.id] || {};
canHandle.folders[folder.id][appname] = check;
}
});
});
return canHandle;
};

/**
* For each item in the collection, if we are navigating to something other
* than the item, set an href property.
*/
function adjustItemHref() {
function adjustItemHref(availableApps) {
this.collection.forEach((item) => {
item._href = undefined;
item._hrefTarget = undefined;
});
const list = this._confList();
const nav = (list || {}).navigate;
Expand Down Expand Up @@ -490,8 +520,23 @@ wrap(ItemListWidget, 'render', function (render) {
item._href += '&filter=' + encodeURIComponent(filter);
}
});
} else if (nav.type === 'open') {
this.collection.forEach((item) => {
let apps = availableApps.items[item.id];
let app;
if (nav.name && apps[nav.name]) {
app = apps[nav.name];
}
if (!app) {
apps = Object.entries(apps).sort(([name1, app1], [name2, app2]) => { const diff = (app1.priority || 0) - (app2.priority || 0); return diff || (ItemListWidget.registeredApplications[name1].name.toLowerCase() > ItemListWidget.registeredApplications[name2].name.toLowerCase() ? 1 : -1); });
app = apps[0][1];
}
if (app.url && app.url !== true) {
item._href = app.url;
item._hrefTarget = '_blank';
}
});
}
// TODO: handle nav.type open
}

function itemListRender() {
Expand Down Expand Up @@ -537,7 +582,8 @@ wrap(ItemListWidget, 'render', function (render) {
this._setSort();
return;
}
adjustItemHref.call(this);
const availableApps = this.checkApps();
adjustItemHref.call(this, availableApps);
this.$el.html(ItemListTemplate({
items: this.collection.toArray(),
isParentPublic: this.public,
Expand All @@ -556,6 +602,8 @@ wrap(ItemListWidget, 'render', function (render) {
sort: this._lastSort,
MetadatumWidget: MetadatumWidget,
accessLevel: this.accessLevel,
registeredApps: ItemListWidget.registeredApplications,
availableApps: availableApps,
parentView: this,
AccessType: AccessType
}));
Expand Down Expand Up @@ -694,4 +742,20 @@ function itemListMetadataEdit(evt) {
return false;
}

/**
* This is a dictionary where the key is the unique application identified.
* Each dictionary contains
* name: the display name
* icon: an optional url to an icon to display
* check: a method that takes (modelType, model, currentFolder) where
* modelType is either 'item', 'folder', or 'resource' and model is a
* bootstrap model or a resource dictionary of models. The function
* returns an object with {url: <url>, priority: <integer>, open:
* <function>} where url is the url to open if possible, the open function
* is a method to call to open the model. Priority affects the order that
* the open calls are listed in (lower is earlier). Return undefined or
* false if the application cannot open this model.
*/
ItemListWidget.registeredApplications = {};

export default ItemListWidget;

0 comments on commit e54f603

Please sign in to comment.