Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add and support app buttons #1692

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
} 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 @@
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;

Check warning on line 290 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L289-L290

Added lines #L289 - L290 were not covered by tests
}
}
return false;
};
Expand Down Expand Up @@ -447,13 +452,38 @@
}
};

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);

Check warning on line 462 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L461-L462

Added lines #L461 - L462 were not covered by tests
if (check) {
canHandle.items[item.id] = canHandle.items[item.id] || {};
canHandle.items[item.id][appname] = check;

Check warning on line 465 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L465

Added line #L465 was not covered by tests
}
});
folders.forEach((folder) => {
const check = app.check('item', folder, this.parentView.parentModel);

Check warning on line 469 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L468-L469

Added lines #L468 - L469 were not covered by tests
if (check) {
canHandle.folders[folder.id] = canHandle.folders[folder.id] || {};
canHandle.folders[folder.id][appname] = check;

Check warning on line 472 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L472

Added line #L472 was not covered by tests
}
});
});
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 @@
item._href += '&filter=' + encodeURIComponent(filter);
}
});
} else if (nav.type === 'open') {
this.collection.forEach((item) => {
let apps = availableApps.items[item.id];

Check warning on line 525 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L524-L525

Added lines #L524 - L525 were not covered by tests
let app;
if (nav.name && apps[nav.name]) {
app = apps[nav.name];

Check warning on line 528 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L528

Added line #L528 was not covered by tests
}
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];

Check warning on line 532 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L532

Added line #L532 was not covered by tests
}
if (app.url && app.url !== true) {
item._href = app.url;
item._hrefTarget = '_blank';

Check warning on line 536 in girder/girder_large_image/web_client/views/itemList.js

View check run for this annotation

Codecov / codecov/patch

girder/girder_large_image/web_client/views/itemList.js#L535-L536

Added lines #L535 - L536 were not covered by tests
}
});
}
// TODO: handle nav.type open
}

function itemListRender() {
Expand Down Expand Up @@ -537,7 +582,8 @@
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 @@
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 @@
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;