Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into otp
Browse files Browse the repository at this point in the history
  • Loading branch information
brianhelba committed Jun 4, 2018
2 parents 24c5989 + 358bafc commit 882df3c
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 228 deletions.
2 changes: 1 addition & 1 deletion clients/python/girder_client/__init__.py
Expand Up @@ -34,7 +34,7 @@
from contextlib import contextmanager
from requests_toolbelt import MultipartEncoder

__version__ = '2.3.0'
__version__ = '2.4.0'
__license__ = 'Apache 2.0'

DEFAULT_PAGE_LIMIT = 50 # Number of results to fetch per request
Expand Down
4 changes: 4 additions & 0 deletions girder/models/model_base.py
Expand Up @@ -54,6 +54,10 @@ def __call__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(_ModelSingleton, cls).__call__(*args, **kwargs)
_modelSingletons.append(cls._instance)
# It is not safe to ever set cls._instance back to None in an attempt to force singleton
# recreation, since some models have event bindings that will not be destroyed (so the
# old singletons will still have instance-bound methods that are event-bound to and fire
# on model-related events)
return cls._instance


Expand Down
7 changes: 6 additions & 1 deletion girder/utility/acl_mixin.py
Expand Up @@ -67,7 +67,12 @@ def load(self, id, level=AccessType.ADMIN, user=None, objectId=True,
else:
loadType = doc.get('attachedToType')
loadId = doc.get('attachedToId')
self.model(loadType).load(loadId, level=level, user=user, exc=exc)
if isinstance(loadType, six.string_types):
self.model(loadType).load(loadId, level=level, user=user, exc=exc)
elif isinstance(loadType, list) and len(loadType) == 2:
self.model(*loadType).load(loadId, level=level, user=user, exc=exc)
else:
raise Exception('Invalid model type: %s' % str(loadType))

self._removeSupplementalFields(doc, fields)

Expand Down
2 changes: 1 addition & 1 deletion plugins/jobs/plugin.yml
Expand Up @@ -4,4 +4,4 @@ url: http://girder.readthedocs.io/en/latest/plugins.html#jobs
version: 2.0.0
npm:
dependencies:
vega: ^2.6.0
vega-lib: ^3.3.1
4 changes: 2 additions & 2 deletions plugins/jobs/plugin_tests/jobsSpec.js
Expand Up @@ -497,11 +497,11 @@ describe('Unit test the job list widget.', function () {
});
waitsFor(function () {
// Charts will render asynchronously with Vega
return widget.$('.g-jobs-graph svg .mark-rect.timing rect').length;
return widget.$('.g-jobs-graph svg .mark-rect.timing path').length;
}, 'timing history graph to render');

runs(function () {
expect(widget.$('.g-jobs-graph svg .mark-rect.timing rect').length).toBe(6);
expect(widget.$('.g-jobs-graph svg .mark-rect.timing path').length).toBe(9);
$('.g-jobs.nav.nav-tabs li a[name="time"]').tab('show');
});
waitsFor(function () {
Expand Down
47 changes: 26 additions & 21 deletions plugins/jobs/web_client/views/JobGraphWidget.js
@@ -1,6 +1,7 @@
import _ from 'underscore';
import $ from 'jquery';
import vg from 'vega';
import { parse,
View as VegaView } from 'vega-lib';
import moment from 'moment';

import View from 'girder/views/View';
Expand Down Expand Up @@ -64,28 +65,32 @@ const JobGraphWidget = View.extend({
// the minimum width needed for each job is 10px
let numberOfJobs = Math.min(this.collection.size(), Math.floor(width / 10));
let vegaData = this._prepareDataForChart(numberOfJobs);
let withForEachJob = width / numberOfJobs;
let widthForEachJob = width / numberOfJobs;
// if the width for each job is less than 20px, remove axe labels
if (withForEachJob < 20) {
config.axes[0].properties.labels.opacity = { value: 0 };
if (widthForEachJob < 20) {
config.axes[0].encode.labels.opacity = { value: 0 };
}
config.width = width;
config.height = this.$('.g-jobs-graph').height();
config.data[0].values = vegaData;

const minval = Math.min(0, Math.min.apply(this, vegaData.map((d) => d.elapsed === undefined ? 10 : d.elapsed)) / 1000);
config.data[1].values = [minval < -86400 ? -86400 : minval];

config.scales[1].type = this.yScale;
let allStatus = JobStatus.getAll().filter((status) => this.timingFilter ? this.timingFilter[status.text] : true);
config.scales[2].domain = allStatus.map((status) => status.text);
config.scales[2].range = allStatus.map((status) => status.color);
config.scales[3].domain = this.collection.pluck('_id');
config.scales[3].range = this.collection.pluck('title');

vg.parse.spec(config, (chart) => {
var view = chart({
el: this.$('.g-jobs-graph').get(0),
renderer: 'svg'
}).update();
view.on('click', openDetailView(view));
});
const runtime = parse(config);
const view = new VegaView(runtime)
.initialize(document.querySelector('.g-jobs-graph'))
.renderer('svg')
.hover()
.run();
view.addEventListener('click', openDetailView(view));

let positiveTimings = _.clone(this.timingFilter);
this.timingFilterWidget.setItems(positiveTimings);
Expand All @@ -99,11 +104,11 @@ const JobGraphWidget = View.extend({
// the minimum width needed for each job is 6px
let numberOfJobs = Math.min(this.collection.size(), Math.floor(width / 6));
let vegaData = this._prepareDataForChart(numberOfJobs);
let withForEachJob = width / numberOfJobs;
let widthForEachJob = width / numberOfJobs;
// if the width for each job is less than 20px, remove date axe and axe labels
if (withForEachJob < 20) {
if (widthForEachJob < 20) {
config.axes.splice(0, 1);
config.axes[0].properties.labels.opacity = { value: 0 };
config.axes[0].encode.labels.opacity = { value: 0 };
}
config.width = width;
config.height = this.$('.g-jobs-graph').height();
Expand All @@ -126,13 +131,13 @@ const JobGraphWidget = View.extend({
config.scales[4].domain = allStatus.map((status) => status.text);
config.scales[4].range = allStatus.map((status) => status.color);

vg.parse.spec(config, (chart) => {
var view = chart({
el: this.$('.g-jobs-graph').get(0),
renderer: 'svg'
}).update();
view.on('click', openDetailView(view));
});
const runtime = parse(config);
const view = new VegaView(runtime)
.initialize(document.querySelector('.g-jobs-graph'))
.renderer('svg')
.hover()
.run();
view.addEventListener('click', openDetailView(view));

let positiveTimings = _.clone(this.timingFilter);
delete positiveTimings['Inactive'];
Expand Down
106 changes: 51 additions & 55 deletions plugins/jobs/web_client/views/timeChartConfig.js
@@ -1,40 +1,35 @@
const timeChartConfig = {
'width': 894,
'height': 673,
'padding': 'strict',
'autosize': 'fit',
'data': [
{
'name': 'table',
'values': [],
'transform': [
{
'type': 'filter',
'test': 'datum.elapsed > 0'
},
{
'type': 'formula',
'field': 'elapsed',
'expr': 'datum.elapsed/1000'
'expr': 'datum.elapsed > 0'
},
{
'type': 'aggregate',
'groupby': ['id', 'title', 'currentStatus'],
'summarize': [
{
'field': 'elapsed',
'ops': ['sum'],
'as': ['sum_y']
}
]
'fields': ['elapsed'],
'ops': ['sum'],
'as': ['sum_y']
},
{
'type': 'formula',
'as': 'adjSum_y',
'expr': 'datum.sum_y/1000'
}
]
}
],
'scales': [
{
'name': 'x',
'type': 'ordinal',
'points': true,
'type': 'point',
'range': 'width',
'domain': {
'data': 'table',
Expand All @@ -49,7 +44,7 @@ const timeChartConfig = {
'fields': [
{
'data': 'table',
'field': 'sum_y'
'field': 'adjSum_y'
}
]
}
Expand All @@ -75,39 +70,40 @@ const timeChartConfig = {
],
'axes': [
{
'type': 'x',
'scale': 'x',
'orient': 'top',
'properties': {
'encode': {
'labels': {
'text': { 'scale': 'xlabels2' },
'angle': { 'value': -50 },
'align': { 'value': 'left' },
'itemName': { 'value': 'xlabel2' }
'update': {
'text': { 'field': 'value', 'scale': 'xlabels2' },
'angle': { 'value': -50 },
'align': { 'value': 'left' },
'itemName': { 'value': 'xlabel2' }
}
}
},
'offset': 10
},
{
'type': 'x',
'scale': 'x',
'orient': 'bottom',
'subdivide': 3,
'properties': {
'encode': {
'labels': {
'text': { 'scale': 'xlabels' },
'angle': { 'value': 50 },
'align': { 'value': 'left' },
'itemName': { 'value': 'xlabel' }
'update': {
'text': { 'field': 'value', 'scale': 'xlabels' },
'angle': { 'value': 50 },
'align': { 'value': 'left' },
'itemName': { 'value': 'xlabel' }
}
}
}
},
{
'type': 'y',
'orient': 'left',
'scale': 'y',
'format': 's',
'title': 'seconds',
'properties': {
'encode': {
'labels': {
'itemName': { 'value': 'ylabel' }
}
Expand All @@ -117,40 +113,40 @@ const timeChartConfig = {
'signals': [
{
'name': 'hover',
'init': {
'value': {
'pos': {},
'datum': {}
},
'streams': [
'on': [
{
'type': '@circle:mousemove',
'expr': '{ pos: {x: eventX(), y: eventY()}, datum:datum}'
'events': '@circle:mousemove',
'update': '{ pos: {x: x(), y: y()}, datum:datum}'
},
{
'type': '@circle:mouseout',
'expr': '{pos:{},datum:{}}'
'events': '@circle:mouseout',
'update': '{pos:{},datum:{}}'
}
]
},
{
'name': 'tt0',
'init': {},
'expr': '{ title:hover.datum.title, sum_y:hover.datum["sum_y"] }'
'value': {},
'update': '{ title:hover.datum.title, sum_y:hover.datum["sum_y"] }'
},
{
'name': 'tt1',
'init': {},
'expr': '{ sum_y:!tt0.sum_y?"":timeFormat(tt0.sum_y>3600000? "%H:%M:%S.%Ls":(tt0.sum_y>60000?"%M:%S.%Ls":"%S.%Ls"), datetime(0,0,0,0,0,0,tt0.sum_y)) }'
'value': {},
'update': '{ sum_y:!tt0.sum_y?"":timeFormat(datetime(0,0,0,0,0,0,tt0.sum_y), tt0.sum_y>3600000? "%H:%M:%S.%Ls":(tt0.sum_y>60000?"%M:%S.%Ls":"%S.%Ls")) }'
},
{
'name': 'tt2',
'init': {},
'expr': '{ width:!tt0.title?0:max(tt0.title.length, tt1.sum_y.length)*7 }'
'value': {},
'update': '{ width:!tt0.title?0:max(tt0.title.length, tt1.sum_y.length)*7 }'
},
{
'name': 'tooltip',
'init': {},
'expr': '{ y:hover.pos.y+30, x:(hover.pos.x>width-tt2.width+5?hover.pos.x-tt2.width-5:hover.pos.x+5), width:tt2.width, title:tt0.title, sum_y:tt1.sum_y }'
'value': {},
'update': '{ y:hover.pos.y+30, x:(hover.pos.x>width-tt2.width+5?hover.pos.x-tt2.width-5:hover.pos.x+5), width:tt2.width, title:tt0.title, sum_y:tt1.sum_y }'
}
],
'marks': [
Expand All @@ -160,15 +156,15 @@ const timeChartConfig = {
'from': {
'data': 'table'
},
'properties': {
'encode': {
'enter': {
'x': {
'scale': 'x',
'field': 'id'
},
'y': {
'scale': 'y',
'field': 'sum_y'
'field': 'adjSum_y'
},
'itemName': {
'value': 'line'
Expand Down Expand Up @@ -196,15 +192,15 @@ const timeChartConfig = {
'from': {
'data': 'table'
},
'properties': {
'encode': {
'enter': {
'x': {
'scale': 'x',
'field': 'id'
},
'y': {
'scale': 'y',
'field': 'sum_y'
'field': 'adjSum_y'
},
'itemName': {
'value': 'circle'
Expand All @@ -228,7 +224,7 @@ const timeChartConfig = {
},
{
'type': 'group',
'properties': {
'encode': {
'update': {
'x': { 'signal': 'tooltip.x' },
'y': { 'signal': 'tooltip.y' },
Expand All @@ -244,7 +240,7 @@ const timeChartConfig = {
{
'name': 'title',
'type': 'text',
'properties': {
'encode': {
'update': {
'x': { 'value': 6 },
'y': { 'value': 14 },
Expand All @@ -256,7 +252,7 @@ const timeChartConfig = {
{
'name': 'elapsed',
'type': 'text',
'properties': {
'encode': {
'update': {
'x': { 'value': 6 },
'y': { 'value': 30 },
Expand All @@ -273,8 +269,8 @@ const timeChartConfig = {
{
'fill': 'timing',
'title': 'Status',
'offset': -3,
'properties': {
'offset': 20,
'encode': {
'title': {
'dx': { 'value': 13 },
'fontSize': { 'value': 12 }
Expand Down

0 comments on commit 882df3c

Please sign in to comment.