sidekiq 6.5.2 → 6.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

@@ -0,0 +1,7 @@
1
+ /*!
2
+ * chartjs-plugin-annotation v2.0.0
3
+ * https://www.chartjs.org/chartjs-plugin-annotation/index
4
+ * (c) 2022 chartjs-plugin-annotation Contributors
5
+ * Released under the MIT License
6
+ */
7
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["chart.js","chart.js/helpers"],e):(t="undefined"!=typeof globalThis?globalThis:t||self)["chartjs-plugin-annotation"]=e(t.Chart,t.Chart.helpers)}(this,(function(t,e){"use strict";const o={modes:{point:(t,e)=>r(t,e,{intersect:!0}),nearest:(t,o,n)=>function(t,o,n){let i=Number.POSITIVE_INFINITY;return r(t,o,n).reduce(((t,r)=>{const s=r.getCenterPoint(),a=function(t,e,o){if("x"===o)return{x:t.x,y:e.y};if("y"===o)return{x:e.x,y:t.y};return e}(o,s,n.axis),d=e.distanceBetweenPoints(o,a);return d<i?(t=[r],i=d):d===i&&t.push(r),t}),[]).sort(((t,e)=>t._index-e._index)).slice(0,1)}(t,o,n),x:(t,e,o)=>r(t,e,{intersect:o.intersect,axis:"x"}),y:(t,e,o)=>r(t,e,{intersect:o.intersect,axis:"y"})}};function n(t,e,n){return(o.modes[n.mode]||o.modes.nearest)(t,e,n)}function r(t,e,o){return t.visibleElements.filter((t=>o.intersect?t.inRange(e.x,e.y):function(t,e,o){return"x"!==o&&"y"!==o?t.inRange(e.x,e.y,"x",!0)||t.inRange(e.x,e.y,"y",!0):t.inRange(e.x,e.y,o,!0)}(t,e,o.axis)))}const i=["enter","leave"],s=i.concat("click");function a(t,e,o){if(t.listened)switch(e.type){case"mousemove":case"mouseout":return function(t,e,o){if(!t.moveListened)return;let r;r="mousemove"===e.type?n(t,e,o.interaction):[];const i=t.hovered;t.hovered=r;const s={state:t,event:e};let a=d(s,"leave",i,r);return d(s,"enter",r,i)||a}(t,e,o);case"click":return function(t,e,o){const r=t.listeners,i=n(t,e,o.interaction);let s;for(const t of i)s=l(t.options.click||r.click,t,e)||s;return s}(t,e,o)}}function d({state:t,event:e},o,n,r){let i;for(const s of n)r.indexOf(s)<0&&(i=l(s.options[o]||t.listeners[o],s,e)||i);return i}function l(t,o,n){return!0===e.callback(t,[o.$context,n])}const c=(t,e)=>e>t||t.length>e.length&&t.slice(0,e.length)===e,h=.001,u=(t,e,o)=>Math.min(o,Math.max(e,t));function f(t,e,o){for(const n of Object.keys(t))t[n]=u(t[n],e,o);return t}function x(t,{x:e,y:o,x2:n,y2:r},i,s){const a=s/2,d=t.x>=e-a-h&&t.x<=n+a+h,l=t.y>=o-a-h&&t.y<=r+a+h;return"x"===i?d:("y"===i||d)&&l}function y(t,e){const{centerX:o,centerY:n}=t.getProps(["centerX","centerY"],e);return{x:o,y:n}}const p=t=>"string"==typeof t&&t.endsWith("%"),b=t=>u(parseFloat(t)/100,0,1);function g(t,e){return"start"===e?0:"end"===e?t:p(e)?b(e)*t:t/2}function m(t,e){return"number"==typeof e?e:p(e)?b(e)*t:t}function w(t){return e.isObject(t)?{x:e.valueOrDefault(t.x,"center"),y:e.valueOrDefault(t.y,"center")}:{x:t=e.valueOrDefault(t,"center"),y:t}}function v(t){return t&&(e.defined(t.xValue)||e.defined(t.yValue))}const S=new Map;function M(t){if(t&&"object"==typeof t){const e=t.toString();return"[object HTMLImageElement]"===e||"[object HTMLCanvasElement]"===e}}function C(t,{x:o,y:n},r){r&&(t.translate(o,n),t.rotate(e.toRadians(r)),t.translate(-o,-n))}function D(t,e){if(e&&e.borderWidth)return t.lineCap=e.borderCapStyle,t.setLineDash(e.borderDash),t.lineDashOffset=e.borderDashOffset,t.lineJoin=e.borderJoinStyle,t.lineWidth=e.borderWidth,t.strokeStyle=e.borderColor,!0}function j(t,e){t.shadowColor=e.backgroundShadowColor,t.shadowBlur=e.shadowBlur,t.shadowOffsetX=e.shadowOffsetX,t.shadowOffsetY=e.shadowOffsetY}function k(t,o){const n=o.content;if(M(n))return{width:m(n.width,o.width),height:m(n.height,o.height)};const r=e.toFont(o.font),i=o.textStrokeWidth,s=e.isArray(n)?n:[n],a=s.join()+r.string+i+(t._measureText?"-spriting":"");if(!S.has(a)){t.save(),t.font=r.string;const e=s.length;let o=0;for(let n=0;n<e;n++){const e=s[n];o=Math.max(o,t.measureText(e).width+i)}t.restore();const n=e*r.lineHeight+i;S.set(a,{width:o,height:n})}return S.get(a)}function P(t,o,n){const{x:r,y:i,width:s,height:a}=o;t.save(),j(t,n);const d=D(t,n);t.fillStyle=n.backgroundColor,t.beginPath(),e.addRoundedRectPath(t,{x:r,y:i,w:s,h:a,radius:f(e.toTRBLCorners(n.borderRadius),0,Math.min(s,a)/2)}),t.closePath(),t.fill(),d&&(t.shadowColor=n.borderShadowColor,t.stroke()),t.restore()}function O(t,o,n){return o="number"==typeof o?o:t.parse(o),e.isFinite(o)?t.getPixelForValue(o):n}function A(t,e,o){const n=e[o];if(n||"scaleID"===o)return n;const r=o.charAt(0),i=Object.values(t).filter((t=>t.axis&&t.axis===r));return i.length?i[0].id:r}function I(t,e){if(t){const o=t.options.reverse;return{start:O(t,e.min,o?e.end:e.start),end:O(t,e.max,o?e.start:e.end)}}}function Y(t,e){const{chartArea:o,scales:n}=t,r=n[A(n,e,"xScaleID")],i=n[A(n,e,"yScaleID")];let s=o.width/2,a=o.height/2;return r&&(s=O(r,e.xValue,r.left+r.width/2)),i&&(a=O(i,e.yValue,i.top+i.height/2)),{x:s,y:a}}function R(t,e){const o=t.scales,n=o[A(o,e,"xScaleID")],r=o[A(o,e,"yScaleID")];if(!n&&!r)return{};let{left:i,right:s}=n||t.chartArea,{top:a,bottom:d}=r||t.chartArea;const l=X(n,{min:e.xMin,max:e.xMax,start:i,end:s});i=l.start,s=l.end;const c=X(r,{min:e.yMin,max:e.yMax,start:d,end:a});return a=c.start,d=c.end,{x:i,y:a,x2:s,y2:d,width:s-i,height:d-a,centerX:i+(s-i)/2,centerY:a+(d-a)/2}}function W(t,e){if(!v(e)){const o=R(t,e);let n=e.radius;n&&!isNaN(n)||(n=Math.min(o.width,o.height)/2,e.radius=n);const r=2*n;return{x:o.x+e.xAdjust,y:o.y+e.yAdjust,x2:o.x+r+e.xAdjust,y2:o.y+r+e.yAdjust,centerX:o.centerX+e.xAdjust,centerY:o.centerY+e.yAdjust,width:r,height:r}}return function(t,e){const o=Y(t,e),n=2*e.radius;return{x:o.x-e.radius+e.xAdjust,y:o.y-e.radius+e.yAdjust,x2:o.x+e.radius+e.xAdjust,y2:o.y+e.radius+e.yAdjust,centerX:o.x+e.xAdjust,centerY:o.y+e.yAdjust,width:n,height:n}}(t,e)}function X(t,e){const o=I(t,e)||e;return{start:Math.min(o.start,o.end),end:Math.max(o.start,o.end)}}function E(t,e,o){const n=Math.cos(o),r=Math.sin(o),i=e.x,s=e.y;return{x:i+n*(t.x-i)-r*(t.y-s),y:s+r*(t.x-i)+n*(t.y-s)}}function T(t,o,n){const r=function(t,o,n){const r=o.axis,i=o.id,s=r+"ScaleID",a={min:e.valueOrDefault(o.min,Number.NEGATIVE_INFINITY),max:e.valueOrDefault(o.max,Number.POSITIVE_INFINITY)};for(const e of n)e.scaleID===i?V(e,o,["value","endValue"],a):A(t,e,s)===i&&V(e,o,[r+"Min",r+"Max",r+"Value"],a);return a}(t.scales,o,n);let i=z(o,r,"min","suggestedMin");i=z(o,r,"max","suggestedMax")||i,i&&"function"==typeof o.handleTickRangeOptions&&o.handleTickRangeOptions()}function z(t,o,n,r){if(e.isFinite(o[n])&&!function(t,o,n){return e.defined(t[o])||e.defined(t[n])}(t.options,n,r)){const e=t[n]!==o[n];return t[n]=o[n],e}}function _(t,e){for(const o of["scaleID","xScaleID","yScaleID"]){const n=A(e,t,o);n&&!e[n]&&N(t,o)&&console.warn(`No scale found with id '${n}' for annotation '${t.id}'`)}}function N(t,o){if("scaleID"===o)return!0;const n=o.charAt(0);for(const o of["Min","Max","Value"])if(e.defined(t[n+o]))return!0;return!1}function V(t,o,n,r){for(const i of n){const n=t[i];if(e.defined(n)){const t=o.parse(n);r.min=Math.min(r.min,t),r.max=Math.max(r.max,t)}}}class B extends t.Element{inRange(t,o,n,r){const{x:i,y:s}=E({x:t,y:o},this.getCenterPoint(r),e.toRadians(-this.options.rotation));return x({x:i,y:s},this.getProps(["x","y","x2","y2"],r),n,this.options.borderWidth)}getCenterPoint(t){return y(this,t)}draw(t){t.save(),C(t,this.getCenterPoint(),this.options.rotation),P(t,this,this.options),t.restore()}get label(){return this.elements&&this.elements[0]}resolveElementProperties(t,e){const o=R(t,e),{x:n,y:r}=o;return o.elements=[{type:"label",optionScope:"label",properties:L(t,o,e)}],o.initProperties={x:n,y:r},o}}function H(t,e){const{start:o,end:n,borderWidth:r}=t,{position:i,padding:{start:s,end:a},adjust:d}=e;return o+r/2+d+g(n-r-o-s-a-e.size,i)}function L(t,o,n){const r=n.label;r.backgroundColor="transparent",r.callout.display=!1;const i=w(r.position),s=e.toPadding(r.padding),a=k(t.ctx,r),d=function({properties:t,options:e},o,n,r){const{x:i,x2:s,width:a}=t;return H({start:i,end:s,size:a,borderWidth:e.borderWidth},{position:n.x,padding:{start:r.left,end:r.right},adjust:e.label.xAdjust,size:o.width})}({properties:o,options:n},a,i,s),l=function({properties:t,options:e},o,n,r){const{y:i,y2:s,height:a}=t;return H({start:i,end:s,size:a,borderWidth:e.borderWidth},{position:n.y,padding:{start:r.top,end:r.bottom},adjust:e.label.yAdjust,size:o.height})}({properties:o,options:n},a,i,s),c=a.width+s.width,h=a.height+s.height;return{x:d,y:l,x2:d+c,y2:l+h,width:c,height:h,centerX:d+c/2,centerY:l+h/2,rotation:r.rotation}}B.id="boxAnnotation",B.defaults={adjustScaleRange:!0,backgroundShadowColor:"transparent",borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderRadius:0,borderShadowColor:"transparent",borderWidth:1,display:!0,label:{backgroundColor:"transparent",borderWidth:0,callout:{display:!1},color:"black",content:null,display:!1,drawTime:void 0,font:{family:void 0,lineHeight:void 0,size:void 0,style:void 0,weight:"bold"},height:void 0,padding:6,position:"center",rotation:void 0,textAlign:"start",textStrokeColor:void 0,textStrokeWidth:0,width:void 0,xAdjust:0,yAdjust:0,z:void 0},rotation:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,xMax:void 0,xMin:void 0,xScaleID:void 0,yMax:void 0,yMin:void 0,yScaleID:void 0,z:0},B.defaultRoutes={borderColor:"color",backgroundColor:"color"},B.descriptors={label:{_fallback:!0}};const $=(t,e,o)=>({x:t.x+o*(e.x-t.x),y:t.y+o*(e.y-t.y)}),F=(t,e,o)=>$(e,o,Math.abs((t-e.y)/(o.y-e.y))).x,J=(t,e,o)=>$(e,o,Math.abs((t-e.x)/(o.x-e.x))).y,q=t=>t*t;class U extends t.Element{inRange(t,e,o,n){const r=this.options.borderWidth/2;if("x"!==o&&"y"!==o){const o={mouseX:t,mouseY:e};return function(t,{mouseX:e,mouseY:o},n=.001,r){const{x:i,y:s,x2:a,y2:d}=t.getProps(["x","y","x2","y2"],r),l=a-i,c=d-s,h=q(l)+q(c),u=0===h?-1:((e-i)*l+(o-s)*c)/h;let f,x;u<0?(f=i,x=s):u>1?(f=a,x=d):(f=i+u*l,x=s+u*c);return q(e-f)+q(o-x)<=n}(this,o,q(r),n)||Q(this,o,n)}const i=((t,e,{x:o,y:n,x2:r,y2:i},s)=>"y"===s?{start:Math.min(n,i),end:Math.max(n,i),value:e}:{start:Math.min(o,r),end:Math.max(o,r),value:t})(t,e,this.getProps(["x","y","x2","y2"],n),o);return i.value>=i.start-r&&i.value<=i.end+r||Q(this,{mouseX:t,mouseY:e},n,o)}getCenterPoint(t){return y(this,t)}draw(t){const{x:e,y:o,x2:n,y2:r,options:i}=this;if(t.save(),!D(t,i))return t.restore();j(t,i);const s=Math.atan2(r-o,n-e),a=Math.sqrt(Math.pow(n-e,2)+Math.pow(r-o,2)),{startOpts:d,endOpts:l,startAdjust:c,endAdjust:h}=function(t){const e=t.options,o=e.arrowHeads&&e.arrowHeads.start,n=e.arrowHeads&&e.arrowHeads.end;return{startOpts:o,endOpts:n,startAdjust:nt(t,o),endAdjust:nt(t,n)}}(this);t.translate(e,o),t.rotate(s),t.beginPath(),t.moveTo(0+c,0),t.lineTo(a-h,0),t.shadowColor=i.borderShadowColor,t.stroke(),rt(t,0,c,d),rt(t,a,-h,l),t.restore()}get label(){return this.elements&&this.elements[0]}resolveElementProperties(t,e){const{scales:o,chartArea:n}=t,r=o[e.scaleID],i={x:n.left,y:n.top,x2:n.right,y2:n.bottom};let s,a;if(r)s=O(r,e.value,NaN),a=O(r,e.endValue,s),r.isHorizontal()?(i.x=s,i.x2=a):(i.y=s,i.y2=a);else{const t=o[A(o,e,"xScaleID")],n=o[A(o,e,"yScaleID")];t&&Z(i,t,{min:e.xMin,max:e.xMax,start:t.left,end:t.right,startProp:"x",endProp:"x2"}),n&&Z(i,n,{min:e.yMin,max:e.yMax,start:n.bottom,end:n.top,startProp:"y",endProp:"y2"})}const{x:d,y:l,x2:c,y2:h}=i,u=function({x:t,y:e,x2:o,y2:n},{top:r,right:i,bottom:s,left:a}){return!(t<a&&o<a||t>i&&o>i||e<r&&n<r||e>s&&n>s)}(i,t.chartArea),f=u?function(t,e,o){const{x:n,y:r}=K(t,e,o),{x:i,y:s}=K(e,t,o);return{x:n,y:r,x2:i,y2:s,width:Math.abs(i-n),height:Math.abs(s-r)}}({x:d,y:l},{x:c,y:h},t.chartArea):{x:d,y:l,x2:c,y2:h,width:Math.abs(c-d),height:Math.abs(h-l)};return f.centerX=(c+d)/2,f.centerY=(h+l)/2,u||(e.label.display=!1),f.elements=[{type:"label",optionScope:"label",properties:tt(t,f,e.label)}],f}}U.id="lineAnnotation";const G={backgroundColor:void 0,backgroundShadowColor:void 0,borderColor:void 0,borderDash:void 0,borderDashOffset:void 0,borderShadowColor:void 0,borderWidth:void 0,display:void 0,fill:void 0,length:void 0,shadowBlur:void 0,shadowOffsetX:void 0,shadowOffsetY:void 0,width:void 0};function K({x:t,y:e},o,{top:n,right:r,bottom:i,left:s}){return t<s&&(e=J(s,{x:t,y:e},o),t=s),t>r&&(e=J(r,{x:t,y:e},o),t=r),e<n&&(t=F(n,{x:t,y:e},o),e=n),e>i&&(t=F(i,{x:t,y:e},o),e=i),{x:t,y:e}}function Q(t,{mouseX:e,mouseY:o},n,r){const i=t.label;return i.options.display&&i.inRange(e,o,r,n)}function Z(t,e,o){const n=I(e,o);t[o.startProp]=n.start,t[o.endProp]=n.end}function tt(t,o,n){n.callout.display=!1;const r=n.borderWidth,i=e.toPadding(n.padding),s=k(t.ctx,n);return function(t,o,n,r){const{width:i,height:s,padding:a}=n,{xAdjust:d,yAdjust:l}=o,c={x:t.x,y:t.y},h={x:t.x2,y:t.y2},u="auto"===o.rotation?function(t){const{x:o,y:n,x2:r,y2:i}=t,s=Math.atan2(i-n,r-o);return s>e.PI/2?s-e.PI:s<e.PI/-2?s+e.PI:s}(t):e.toRadians(o.rotation),f=function(t,e,o){const n=Math.cos(o),r=Math.sin(o);return{w:Math.abs(t*n)+Math.abs(e*r),h:Math.abs(t*r)+Math.abs(e*n)}}(i,s,u),x=function(t,e,o,n){let r;const i=function(t,e){const{x:o,x2:n,y:r,y2:i}=t,s=Math.min(r,i)-e.top,a=Math.min(o,n)-e.left,d=e.bottom-Math.max(r,i),l=e.right-Math.max(o,n);return{x:Math.min(a,l),y:Math.min(s,d),dx:a<=l?1:-1,dy:s<=d?1:-1}}(t,n);r="start"===e.position?et({w:t.x2-t.x,h:t.y2-t.y},o,e,i):"end"===e.position?1-et({w:t.x-t.x2,h:t.y-t.y2},o,e,i):g(1,e.position);return r}(t,o,{labelSize:f,padding:a},r),y=$(c,h,x),p={size:f.w,min:r.left,max:r.right,padding:a.left},b={size:f.h,min:r.top,max:r.bottom,padding:a.top},m=ot(y.x,p)+d,w=ot(y.y,b)+l;return{x:m-i/2,y:w-s/2,x2:m+i/2,y2:w+s/2,centerX:m,centerY:w,width:i,height:s,rotation:e.toDegrees(u)}}(o,n,{width:s.width+i.width+r,height:s.height+i.height+r,padding:i},t.chartArea)}function et(t,e,o,n){const{labelSize:r,padding:i}=e,s=t.w*n.dx,a=t.h*n.dy,d=s>0&&(r.w/2+i.left-n.x)/s,l=a>0&&(r.h/2+i.top-n.y)/a;return u(Math.max(d,l),0,.25)}function ot(t,e){const{size:o,min:n,max:r,padding:i}=e,s=o/2;return o>r-n?(r+n)/2:(n>=t-i-s&&(t=n+i+s),r<=t+i+s&&(t=r-i-s),t)}function nt(t,e){if(!e||!e.display)return 0;const{length:o,width:n}=e,r=t.options.borderWidth/2,i={x:o,y:n+r},s={x:0,y:r};return Math.abs(F(0,i,s))}function rt(t,e,o,n){if(!n||!n.display)return;const{length:r,width:i,fill:s,backgroundColor:a,borderColor:d}=n,l=Math.abs(e-r)+o;t.beginPath(),j(t,n),D(t,n),t.moveTo(l,-i),t.lineTo(e+o,0),t.lineTo(l,i),!0===s?(t.fillStyle=a||d,t.closePath(),t.fill(),t.shadowColor="transparent"):t.shadowColor=n.borderShadowColor,t.stroke()}U.defaults={adjustScaleRange:!0,arrowHeads:{display:!1,end:Object.assign({},G),fill:!1,length:12,start:Object.assign({},G),width:6},borderDash:[],borderDashOffset:0,borderShadowColor:"transparent",borderWidth:2,display:!0,endValue:void 0,label:{backgroundColor:"rgba(0,0,0,0.8)",backgroundShadowColor:"transparent",borderCapStyle:"butt",borderColor:"black",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderRadius:6,borderShadowColor:"transparent",borderWidth:0,callout:{display:!1},color:"#fff",content:null,display:!1,drawTime:void 0,font:{family:void 0,lineHeight:void 0,size:void 0,style:void 0,weight:"bold"},height:void 0,padding:6,position:"center",rotation:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,textAlign:"center",textStrokeColor:void 0,textStrokeWidth:0,width:void 0,xAdjust:0,yAdjust:0,z:void 0},scaleID:void 0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,value:void 0,xMax:void 0,xMin:void 0,xScaleID:void 0,yMax:void 0,yMin:void 0,yScaleID:void 0,z:0},U.descriptors={arrowHeads:{start:{_fallback:!0},end:{_fallback:!0},_fallback:!0}},U.defaultRoutes={borderColor:"color"};class it extends t.Element{inRange(t,o,n,r){const i=this.options.rotation,s=this.options.borderWidth;if("x"!==n&&"y"!==n)return function(t,o,n,r){const{width:i,height:s,centerX:a,centerY:d}=o,l=i/2,c=s/2;if(l<=0||c<=0)return!1;const h=e.toRadians(n||0),u=r/2||0,f=Math.cos(h),x=Math.sin(h),y=Math.pow(f*(t.x-a)+x*(t.y-d),2),p=Math.pow(x*(t.x-a)-f*(t.y-d),2);return y/Math.pow(l+u,2)+p/Math.pow(c+u,2)<=1.0001}({x:t,y:o},this.getProps(["width","height","centerX","centerY"],r),i,s);const{x:a,y:d,x2:l,y2:c}=this.getProps(["x","y","x2","y2"],r),u=s/2,f="y"===n?{start:d,end:c}:{start:a,end:l},x=E({x:t,y:o},this.getCenterPoint(r),e.toRadians(-i));return x[n]>=f.start-u-h&&x[n]<=f.end+u+h}getCenterPoint(t){return y(this,t)}draw(t){const{width:o,height:n,centerX:r,centerY:i,options:s}=this;t.save(),C(t,this.getCenterPoint(),s.rotation),j(t,this.options),t.beginPath(),t.fillStyle=s.backgroundColor;const a=D(t,s);t.ellipse(r,i,n/2,o/2,e.PI/2,0,2*e.PI),t.fill(),a&&(t.shadowColor=s.borderShadowColor,t.stroke()),t.restore()}resolveElementProperties(t,e){return R(t,e)}}it.id="ellipseAnnotation",it.defaults={adjustScaleRange:!0,backgroundShadowColor:"transparent",borderDash:[],borderDashOffset:0,borderShadowColor:"transparent",borderWidth:1,display:!0,rotation:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,xMax:void 0,xMin:void 0,xScaleID:void 0,yMax:void 0,yMin:void 0,yScaleID:void 0,z:0},it.defaultRoutes={borderColor:"color",backgroundColor:"color"};const st=["left","bottom","top","right"];class at extends t.Element{inRange(t,o,n,r){const{x:i,y:s}=E({x:t,y:o},this.getCenterPoint(r),e.toRadians(-this.rotation));return x({x:i,y:s},this.getProps(["x","y","x2","y2"],r),n,this.options.borderWidth)}getCenterPoint(t){return y(this,t)}draw(t){const o=this.options;o.display&&o.content&&(t.save(),C(t,this.getCenterPoint(),this.rotation),function(t,o){const{pointX:n,pointY:r,options:i}=o,s=i.callout,a=s&&s.display&&function(t,o){const n=o.position;if(st.includes(n))return n;return function(t,o){const{x:n,y:r,x2:i,y2:s,width:a,height:d,pointX:l,pointY:c,centerX:h,centerY:u,rotation:f}=t,x={x:h,y:u},y=o.start,p=m(a,y),b=m(d,y),g=[n,n+p,n+p,i],w=[r+b,s,r,s],v=[];for(let t=0;t<4;t++){const o=E({x:g[t],y:w[t]},x,e.toRadians(f));v.push({position:st[t],distance:e.distanceBetweenPoints(o,{x:l,y:c})})}return v.sort(((t,e)=>t.distance-e.distance))[0].position}(t,o)}(o,s);if(!a||function(t,e,o){const{pointX:n,pointY:r}=t,i=e.margin;let s=n,a=r;"left"===o?s+=i:"right"===o?s-=i:"top"===o?a+=i:"bottom"===o&&(a-=i);return t.inRange(s,a)}(o,s,a))return;t.save(),t.beginPath();if(!D(t,s))return t.restore();const{separatorStart:d,separatorEnd:l}=function(t,e){const{x:o,y:n,x2:r,y2:i}=t,s=function(t,e){const{width:o,height:n,options:r}=t,i=r.callout.margin+r.borderWidth/2;if("right"===e)return o+i;if("bottom"===e)return n+i;return-i}(t,e);let a,d;"left"===e||"right"===e?(a={x:o+s,y:n},d={x:a.x,y:i}):(a={x:o,y:n+s},d={x:r,y:a.y});return{separatorStart:a,separatorEnd:d}}(o,a),{sideStart:c,sideEnd:h}=function(t,e,o){const{y:n,width:r,height:i,options:s}=t,a=s.callout.start,d=function(t,e){const o=e.side;if("left"===t||"top"===t)return-o;return o}(e,s.callout);let l,c;"left"===e||"right"===e?(l={x:o.x,y:n+m(i,a)},c={x:l.x+d,y:l.y}):(l={x:o.x+m(r,a),y:o.y},c={x:l.x,y:l.y+d});return{sideStart:l,sideEnd:c}}(o,a,d);(s.margin>0||0===i.borderWidth)&&(t.moveTo(d.x,d.y),t.lineTo(l.x,l.y));t.moveTo(c.x,c.y),t.lineTo(h.x,h.y);const u=E({x:n,y:r},o.getCenterPoint(),e.toRadians(-o.rotation));t.lineTo(u.x,u.y),t.stroke(),t.restore()}(t,this),P(t,this,o),function(t,o,n){const r=n.content;if(M(r))return void t.drawImage(r,o.x,o.y,o.width,o.height);const i=e.isArray(r)?r:[r],s=e.toFont(n.font),a=s.lineHeight,d=function(t,e){const{x:o,width:n}=t,r=e.textAlign;return"center"===r?o+n/2:"end"===r||"right"===r?o+n:o}(o,n),l=o.y+a/2+n.textStrokeWidth/2;t.save(),t.font=s.string,t.textBaseline="middle",t.textAlign=n.textAlign,function(t,e){if(e.textStrokeWidth>0)return t.lineJoin="round",t.miterLimit=2,t.lineWidth=e.textStrokeWidth,t.strokeStyle=e.textStrokeColor,!0}(t,n)&&i.forEach(((e,o)=>t.strokeText(e,d,l+o*a))),t.fillStyle=n.color,i.forEach(((e,o)=>t.fillText(e,d,l+o*a))),t.restore()}(t,function({x:t,y:o,width:n,height:r,options:i}){const s=i.borderWidth/2,a=e.toPadding(i.padding);return{x:t+a.left+s,y:o+a.top+s,width:n-a.left-a.right-i.borderWidth,height:r-a.top-a.bottom-i.borderWidth}}(this),o),t.restore())}resolveElementProperties(t,o){let n;if(v(o))n=Y(t,o);else{const{centerX:e,centerY:r}=R(t,o);n={x:e,y:r}}const r=e.toPadding(o.padding),i=function(t,e,o,n){const r=e.width+n.width+o.borderWidth,i=e.height+n.height+o.borderWidth,s=w(o.position),a=dt(t.x,r,o.xAdjust,s.x),d=dt(t.y,i,o.yAdjust,s.y);return{x:a,y:d,x2:a+r,y2:d+i,width:r,height:i,centerX:a+r/2,centerY:d+i/2}}(n,k(t.ctx,o),o,r);return{pointX:n.x,pointY:n.y,...i,rotation:o.rotation}}}function dt(t,e,o=0,n){return t-g(e,n)+o}at.id="labelAnnotation",at.defaults={adjustScaleRange:!0,backgroundColor:"transparent",backgroundShadowColor:"transparent",borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderRadius:0,borderShadowColor:"transparent",borderWidth:0,callout:{borderCapStyle:"butt",borderColor:void 0,borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:1,display:!1,margin:5,position:"auto",side:5,start:"50%"},color:"black",content:null,display:!0,font:{family:void 0,lineHeight:void 0,size:void 0,style:void 0,weight:void 0},height:void 0,padding:6,position:"center",rotation:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,textAlign:"center",textStrokeColor:void 0,textStrokeWidth:0,width:void 0,xAdjust:0,xMax:void 0,xMin:void 0,xScaleID:void 0,xValue:void 0,yAdjust:0,yMax:void 0,yMin:void 0,yScaleID:void 0,yValue:void 0,z:0},at.defaultRoutes={borderColor:"color"};class lt extends t.Element{inRange(t,e,o,n){const{x:r,y:i,x2:s,y2:a,width:d}=this.getProps(["x","y","x2","y2","width"],n),l=this.options.borderWidth;if("x"!==o&&"y"!==o)return function(t,e,o,n){if(!t||!e||o<=0)return!1;const r=n/2;return Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2)<=Math.pow(o+r,2)}({x:t,y:e},this.getCenterPoint(n),d/2,l);const c=l/2,h="y"===o?{start:i,end:a,value:e}:{start:r,end:s,value:t};return h.value>=h.start-c&&h.value<=h.end+c}getCenterPoint(t){return y(this,t)}draw(t){const o=this.options,n=o.borderWidth;if(o.radius<.1)return;t.save(),t.fillStyle=o.backgroundColor,j(t,o);const r=D(t,o);o.borderWidth=0,e.drawPoint(t,o,this.centerX,this.centerY),r&&!M(o.pointStyle)&&(t.shadowColor=o.borderShadowColor,t.stroke()),t.restore(),o.borderWidth=n}resolveElementProperties(t,e){return W(t,e)}}lt.id="pointAnnotation",lt.defaults={adjustScaleRange:!0,backgroundShadowColor:"transparent",borderDash:[],borderDashOffset:0,borderShadowColor:"transparent",borderWidth:1,display:!0,pointStyle:"circle",radius:10,rotation:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,xAdjust:0,xMax:void 0,xMin:void 0,xScaleID:void 0,xValue:void 0,yAdjust:0,yMax:void 0,yMin:void 0,yScaleID:void 0,yValue:void 0,z:0},lt.defaultRoutes={borderColor:"color",backgroundColor:"color"};class ct extends t.Element{inRange(t,o,n,r){if("x"!==n&&"y"!==n)return this.options.radius>=.1&&this.elements.length>1&&function(t,e,o,n){let r=!1,i=t[t.length-1].getProps(["bX","bY"],n);for(const s of t){const t=s.getProps(["bX","bY"],n);t.bY>o!=i.bY>o&&e<(i.bX-t.bX)*(o-t.bY)/(i.bY-t.bY)+t.bX&&(r=!r),i=t}return r}(this.elements,t,o,r);const i=E({x:t,y:o},this.getCenterPoint(r),e.toRadians(-this.options.rotation)),s=this.elements.map((t=>"y"===n?t.bY:t.bX)),a=Math.min(...s),d=Math.max(...s);return i[n]>=a&&i[n]<=d}getCenterPoint(t){return y(this,t)}draw(t){const{elements:e,options:o}=this;t.save(),t.beginPath(),t.fillStyle=o.backgroundColor,j(t,o);const n=D(t,o);let r=!0;for(const o of e)r?(t.moveTo(o.x,o.y),r=!1):t.lineTo(o.x,o.y);t.closePath(),t.fill(),n&&(t.shadowColor=o.borderShadowColor,t.stroke()),t.restore()}resolveElementProperties(t,o){const n=W(t,o),{x:r,y:i}=n,{sides:s,rotation:a}=o,d=[],l=2*e.PI/s;let c=a*e.RAD_PER_DEG;for(let t=0;t<s;t++,c+=l)d.push(ht(n,o,c));return n.elements=d,n.initProperties={x:r,y:i},n}}function ht({centerX:t,centerY:e},{radius:o,borderWidth:n},r){const i=n/2,s=Math.sin(r),a=Math.cos(r),d={x:t+s*o,y:e-a*o};return{type:"point",optionScope:"point",properties:{x:d.x,y:d.y,centerX:d.x,centerY:d.y,bX:t+s*(o+i),bY:e-a*(o+i)}}}ct.id="polygonAnnotation",ct.defaults={adjustScaleRange:!0,backgroundShadowColor:"transparent",borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderShadowColor:"transparent",borderWidth:1,display:!0,point:{radius:0},radius:10,rotation:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,sides:3,xAdjust:0,xMax:void 0,xMin:void 0,xScaleID:void 0,xValue:void 0,yAdjust:0,yMax:void 0,yMin:void 0,yScaleID:void 0,yValue:void 0,z:0},ct.defaultRoutes={borderColor:"color",backgroundColor:"color"};const ut={box:B,ellipse:it,label:at,line:U,point:lt,polygon:ct};Object.keys(ut).forEach((e=>{t.defaults.describe(`elements.${ut[e].id}`,{_fallback:"plugins.annotation.common"})}));const ft={update:Object.assign};function xt(t="line"){return ut[t]?t:(console.warn(`Unknown annotation type: '${t}', defaulting to 'line'`),"line")}function yt(o,n,r,i){const s=function(e,o,n){if("reset"===n||"none"===n||"resize"===n)return ft;return new t.Animations(e,o)}(o,r.animations,i),a=n.annotations,d=function(t,e){const o=e.length,n=t.length;if(n<o){const e=o-n;t.splice(n,0,...new Array(e))}else n>o&&t.splice(o,n-o);return t}(n.elements,a);for(let t=0;t<a.length;t++){const n=a[t],r=gt(d,t,n.type),i=n.setContext(vt(o,r,n)),l=r.resolveElementProperties(o,i);l.skip=pt(l),"elements"in l&&(bt(r,l,i,s),delete l.elements),e.defined(r.x)||Object.assign(r,l),l.options=mt(i),s.update(r,l)}}function pt(t){return isNaN(t.x)||isNaN(t.y)}function bt(t,{elements:e,initProperties:o},n,r){const i=t.elements||(t.elements=[]);i.length=e.length;for(let t=0;t<e.length;t++){const s=e[t],a=s.properties,d=gt(i,t,s.type,o),l=n[s.optionScope].override(s);a.options=mt(l),r.update(d,a)}}function gt(t,o,n,r){const i=ut[xt(n)];let s=t[o];return s&&s instanceof i||(s=t[o]=new i,e.isObject(r)&&Object.assign(s,r)),s}function mt(t){const e=ut[xt(t.type)],o={};o.id=t.id,o.type=t.type,o.drawTime=t.drawTime,Object.assign(o,wt(t,e.defaults),wt(t,e.defaultRoutes));for(const e of s)o[e]=t[e];return o}function wt(t,o){const n={};for(const r of Object.keys(o)){const i=o[r],s=t[r];n[r]=e.isObject(i)?wt(s,i):s}return n}function vt(t,e,o){return e.$context||(e.$context=Object.assign(Object.create(t.getContext()),{element:e,id:o.id,type:"annotation"}))}const St=new Map;var Mt={id:"annotation",version:"2.0.0",beforeRegister(){!function(t,e,o,n=!0){const r=o.split(".");let i=0;for(const s of e.split(".")){const a=r[i++];if(parseInt(s,10)<parseInt(a,10))break;if(c(a,s)){if(n)throw new Error(`${t} v${o} is not supported. v${e} or newer is required.`);return!1}}}("chart.js","3.7",t.Chart.version)},afterRegister(){t.Chart.register(ut)},afterUnregister(){t.Chart.unregister(ut)},beforeInit(t){St.set(t,{annotations:[],elements:[],visibleElements:[],listeners:{},listened:!1,moveListened:!1,hovered:[]})},beforeUpdate(t,o,n){const r=St.get(t).annotations=[];let i=n.annotations;e.isObject(i)?Object.keys(i).forEach((t=>{const o=i[t];e.isObject(o)&&(o.id=t,r.push(o))})):e.isArray(i)&&r.push(...i),function(t,e){for(const o of t)_(o,e)}(r,t.scales)},afterDataLimits(t,e){const o=St.get(t);T(t,e.scale,o.annotations.filter((t=>t.display&&t.adjustScaleRange)))},afterUpdate(t,o,r){const a=St.get(t);!function(t,o,r){o.listened=!1,o.moveListened=!1,o._getElements=n,s.forEach((t=>{"function"==typeof r[t]?(o.listened=!0,o.listeners[t]=r[t]):e.defined(o.listeners[t])&&delete o.listeners[t]})),i.forEach((t=>{"function"==typeof r[t]&&(o.moveListened=!0)})),o.listened&&o.moveListened||o.annotations.forEach((t=>{o.listened||"function"!=typeof t.click||(o.listened=!0),o.moveListened||i.forEach((e=>{"function"==typeof t[e]&&(o.listened=!0,o.moveListened=!0)}))}))}(0,a,r),yt(t,a,r,o.mode),a.visibleElements=a.elements.filter((t=>!t.skip&&t.options.display))},beforeDatasetsDraw(t,e,o){Ct(t,"beforeDatasetsDraw",o.clip)},afterDatasetsDraw(t,e,o){Ct(t,"afterDatasetsDraw",o.clip)},beforeDraw(t,e,o){Ct(t,"beforeDraw",o.clip)},afterDraw(t,e,o){Ct(t,"afterDraw",o.clip)},beforeEvent(t,e,o){a(St.get(t),e.event,o)&&(e.changed=!0)},destroy(t){St.delete(t)},_getState:t=>St.get(t),defaults:{animations:{numbers:{properties:["x","y","x2","y2","width","height","centerX","centerY","pointX","pointY","radius"],type:"number"}},clip:!0,interaction:{mode:void 0,axis:void 0,intersect:void 0},common:{drawTime:"afterDatasetsDraw",label:{}}},descriptors:{_indexable:!1,_scriptable:t=>!s.includes(t),annotations:{_allKeys:!1,_fallback:(t,e)=>`elements.${ut[xt(e.type)].id}`},interaction:{_fallback:!0},common:{label:{_fallback:!0}}},additionalOptionScopes:[""]};function Ct(t,o,n){const{ctx:r,chartArea:i}=t,{visibleElements:s}=St.get(t);n&&e.clipArea(r,i);const a=function(t,e){const o=[];for(const n of t)if(n.options.drawTime===e&&o.push(n),n.elements&&n.elements.length)for(const t of n.elements)t.options.display&&t.options.drawTime===e&&o.push(t);return o}(s,o).sort(((t,e)=>t.options.z-e.options.z));for(const e of a)e.draw(t.ctx,i);n&&e.unclipArea(r)}return t.Chart.register(Mt),Mt}));
@@ -0,0 +1,262 @@
1
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
2
+ Chart.defaults.borderColor = "#333"
3
+ Chart.defaults.color = "#aaa"
4
+ }
5
+
6
+ class BaseChart {
7
+ constructor(id, options) {
8
+ this.ctx = document.getElementById(id);
9
+ this.options = options
10
+ this.fallbackColor = "#999";
11
+ this.colors = [
12
+ // Colors taken from https://www.chartjs.org/docs/latest/samples/utils.html
13
+ "#537bc4",
14
+ "#4dc9f6",
15
+ "#f67019",
16
+ "#f53794",
17
+ "#acc236",
18
+ "#166a8f",
19
+ "#00a950",
20
+ "#58595b",
21
+ "#8549ba",
22
+ "#991b1b",
23
+ ];
24
+
25
+ this.chart = new Chart(this.ctx, {
26
+ type: this.options.chartType,
27
+ data: { labels: this.options.labels, datasets: this.datasets },
28
+ options: this.chartOptions,
29
+ });
30
+ }
31
+
32
+ addMarksToChart() {
33
+ this.options.marks.forEach(([bucket, label], i) => {
34
+ this.chart.options.plugins.annotation.annotations[`deploy-${i}`] = {
35
+ type: "line",
36
+ xMin: bucket,
37
+ xMax: bucket,
38
+ borderColor: "rgba(220, 38, 38, 0.4)",
39
+ borderWidth: 2,
40
+ };
41
+ });
42
+ }
43
+ }
44
+
45
+ class JobMetricsOverviewChart extends BaseChart {
46
+ constructor(id, options) {
47
+ super(id, { ...options, chartType: "line" });
48
+ this.swatches = [];
49
+
50
+ this.addMarksToChart();
51
+ this.chart.update();
52
+ }
53
+
54
+ registerSwatch(id) {
55
+ const el = document.getElementById(id);
56
+ el.onchange = () => this.toggle(el.value, el.checked);
57
+ this.swatches[el.value] = el;
58
+ this.updateSwatch(el.value);
59
+ }
60
+
61
+ updateSwatch(kls) {
62
+ const el = this.swatches[kls];
63
+ const ds = this.chart.data.datasets.find((ds) => ds.label == kls);
64
+ el.checked = !!ds;
65
+ el.style.color = ds ? ds.borderColor : null;
66
+ }
67
+
68
+ toggle(kls, visible) {
69
+ if (visible) {
70
+ this.chart.data.datasets.push(this.dataset(kls));
71
+ } else {
72
+ const i = this.chart.data.datasets.findIndex((ds) => ds.label == kls);
73
+ this.colors.unshift(this.chart.data.datasets[i].borderColor);
74
+ this.chart.data.datasets.splice(i, 1);
75
+ }
76
+
77
+ this.updateSwatch(kls);
78
+ this.chart.update();
79
+ }
80
+
81
+ dataset(kls) {
82
+ const color = this.colors.shift() || this.fallbackColor;
83
+
84
+ return {
85
+ label: kls,
86
+ data: this.options.series[kls],
87
+ borderColor: color,
88
+ backgroundColor: color,
89
+ borderWidth: 2,
90
+ pointRadius: 2,
91
+ };
92
+ }
93
+
94
+ get datasets() {
95
+ return Object.entries(this.options.series)
96
+ .filter(([kls, _]) => this.options.visible.includes(kls))
97
+ .map(([kls, _]) => this.dataset(kls));
98
+ }
99
+
100
+ get chartOptions() {
101
+ return {
102
+ aspectRatio: 4,
103
+ scales: {
104
+ y: {
105
+ beginAtZero: true,
106
+ title: {
107
+ text: "Total execution time (sec)",
108
+ display: true,
109
+ },
110
+ },
111
+ },
112
+ interaction: {
113
+ mode: "x",
114
+ },
115
+ plugins: {
116
+ legend: {
117
+ display: false,
118
+ },
119
+ tooltip: {
120
+ callbacks: {
121
+ title: (items) => `${items[0].label} UTC`,
122
+ label: (item) =>
123
+ `${item.dataset.label}: ${item.parsed.y.toFixed(1)} seconds`,
124
+ footer: (items) => {
125
+ const bucket = items[0].label;
126
+ const marks = this.options.marks.filter(([b, _]) => b == bucket);
127
+ return marks.map(([b, msg]) => `Deploy: ${msg}`);
128
+ },
129
+ },
130
+ },
131
+ },
132
+ };
133
+ }
134
+ }
135
+
136
+ class HistTotalsChart extends BaseChart {
137
+ constructor(id, options) {
138
+ super(id, { ...options, chartType: "bar" });
139
+ }
140
+
141
+ get datasets() {
142
+ return [{
143
+ data: this.options.series,
144
+ backgroundColor: this.colors[0],
145
+ borderWidth: 0,
146
+ }];
147
+ }
148
+
149
+ get chartOptions() {
150
+ return {
151
+ aspectRatio: 6,
152
+ scales: {
153
+ y: {
154
+ beginAtZero: true,
155
+ title: {
156
+ text: "Total jobs",
157
+ display: true,
158
+ },
159
+ },
160
+ },
161
+ interaction: {
162
+ mode: "x",
163
+ },
164
+ plugins: {
165
+ legend: {
166
+ display: false,
167
+ },
168
+ tooltip: {
169
+ callbacks: {
170
+ label: (item) => `${item.parsed.y} jobs`,
171
+ },
172
+ },
173
+ },
174
+ };
175
+ }
176
+ }
177
+
178
+ class HistBubbleChart extends BaseChart {
179
+ constructor(id, options) {
180
+ super(id, { ...options, chartType: "bubble" });
181
+
182
+ this.addMarksToChart();
183
+ this.chart.update();
184
+ }
185
+
186
+ get datasets() {
187
+ const data = [];
188
+ let maxCount = 0;
189
+
190
+ Object.entries(this.options.hist).forEach(([bucket, hist]) => {
191
+ hist.forEach((count, histBucket) => {
192
+ if (count > 0) {
193
+ data.push({
194
+ x: bucket,
195
+ // histogram data is ordered fastest to slowest, but this.histIntervals is
196
+ // slowest to fastest (so it displays correctly on the chart).
197
+ y:
198
+ this.options.histIntervals[this.options.histIntervals.length - 1 - histBucket] /
199
+ 1000,
200
+ count: count,
201
+ });
202
+
203
+ if (count > maxCount) maxCount = count;
204
+ }
205
+ });
206
+ });
207
+
208
+ // Chart.js will not calculate the bubble size. We have to do that.
209
+ const maxRadius = this.ctx.offsetWidth / this.options.labels.length;
210
+ const minRadius = 1
211
+ const multiplier = (maxRadius / maxCount) * 1.5;
212
+ data.forEach((entry) => {
213
+ entry.r = entry.count * multiplier + minRadius;
214
+ });
215
+
216
+ return [{
217
+ data: data,
218
+ backgroundColor: "#537bc4",
219
+ borderColor: "#537bc4",
220
+ }];
221
+ }
222
+
223
+ get chartOptions() {
224
+ return {
225
+ aspectRatio: 3,
226
+ scales: {
227
+ x: {
228
+ type: "category",
229
+ labels: this.options.labels,
230
+ },
231
+ y: {
232
+ title: {
233
+ text: "Execution time (sec)",
234
+ display: true,
235
+ },
236
+ },
237
+ },
238
+ interaction: {
239
+ mode: "x",
240
+ },
241
+ plugins: {
242
+ legend: {
243
+ display: false,
244
+ },
245
+ tooltip: {
246
+ callbacks: {
247
+ title: (items) => `${items[0].raw.x} UTC`,
248
+ label: (item) =>
249
+ `${item.parsed.y} seconds: ${item.raw.count} job${
250
+ item.raw.count == 1 ? "" : "s"
251
+ }`,
252
+ footer: (items) => {
253
+ const bucket = items[0].raw.x;
254
+ const marks = this.options.marks.filter(([b, _]) => b == bucket);
255
+ return marks.map(([b, msg]) => `Deploy: ${msg}`);
256
+ },
257
+ },
258
+ },
259
+ },
260
+ };
261
+ }
262
+ }
@@ -67,10 +67,15 @@ body {
67
67
  padding: 0 20px;
68
68
  }
69
69
 
70
- h3 {
70
+ h1, h2, h3 {
71
+ font-size: 24px;
71
72
  line-height: 45px;
72
73
  }
73
74
 
75
+ .header-with-subheader h2 {
76
+ margin-top: -18px;
77
+ }
78
+
74
79
  .centered {
75
80
  text-align: center;
76
81
  }
@@ -954,3 +959,41 @@ div.interval-slider input {
954
959
  padding: 3px 7px;
955
960
  margin-left: 5px;
956
961
  }
962
+
963
+ .metrics-swatch-wrapper {
964
+ display: flex;
965
+ align-items: center;
966
+ gap: 6px;
967
+ }
968
+
969
+ .metrics-swatch[type=checkbox] {
970
+ display: inline-block;
971
+ width: 16px;
972
+ height: 16px;
973
+ margin: 0;
974
+ border-radius: 2px;
975
+ appearance: none;
976
+ -webkit-appearance: none;
977
+ -moz-appearance: none;
978
+ border: 1px solid #bbb;
979
+ color: white;
980
+ background-color: currentColor;
981
+ }
982
+
983
+ /* We need to add the checkmark since we've taken over the appearance */
984
+ .metrics-swatch[type=checkbox]:checked {
985
+ border-color: currentColor;
986
+ background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
987
+ background-size: 100% 100%;
988
+ background-position: center;
989
+ background-repeat: no-repeat;
990
+ }
991
+
992
+ .metrics-swatch[type=checkbox]:focus {
993
+ outline: 1px solid #888;
994
+ outline-offset: 2px;
995
+ }
996
+
997
+ canvas {
998
+ margin: 20px 0 30px;
999
+ }
data/web/locales/el.yml CHANGED
@@ -6,11 +6,12 @@ el: # <---- change this to your locale code
6
6
  Namespace: Namespace
7
7
  Realtime: Τρέχουσα Κατάσταση
8
8
  History: Ιστορικό
9
- Busy: Απασχολημένο
10
- Processed: Επεξεργάστηκε
11
- Failed: Απέτυχε
12
- Scheduled: Προγραματίστηκε
13
- Retries: Προσπάθειες
9
+ Busy: Υπό επεξεργασία
10
+ Utilization: Σε χρήση
11
+ Processed: Επεξεργάστηκαν
12
+ Failed: Απέτυχαν
13
+ Scheduled: Προγραμματισμένα
14
+ Retries: Επαναλήψεις
14
15
  Enqueued: Μπήκαν στην στοίβα
15
16
  Worker: Εργάτης
16
17
  LivePoll: Τρέχουσα Κατάσταση
@@ -20,40 +21,42 @@ el: # <---- change this to your locale code
20
21
  Job: Εργασία
21
22
  Arguments: Ορίσματα
22
23
  Extras: Extras
23
- Started: Ξεκίνησαν
24
+ Started: Ξεκίνησε
24
25
  ShowAll: Εμφάνιση Όλων
25
26
  CurrentMessagesInQueue: Τρέχουσες εργασίες <span class='title'>%{queue}</span>
26
27
  Delete: Διαγραφή
27
28
  AddToQueue: Προσθήκη στην στοίβα
28
- AreYouSureDeleteJob: Θέλετε να διαγράψετε την εργασία αυτη;
29
- AreYouSureDeleteQueue: Θέλετε να διαγράψετε την %{queue} στοίβα?
29
+ AreYouSureDeleteJob: Θέλετε να διαγράψετε αυτή την εργασία;
30
+ AreYouSureDeleteQueue: Θέλετε να διαγράψετε την στοίβα %{queue}; Αυτό θα διαγράψει όλες τις εργασίες εντός της στοίβας, θα εμφανιστεί ξανά εάν προωθήσετε περισσότερες εργασίες σε αυτήν στο μέλλον.
30
31
  Queues: Στοίβες
31
32
  Size: Μέγεθος
32
33
  Actions: Ενέργειες
33
- NextRetry: Επόμενη προσπάθεια
34
- RetryCount: Αριθμός προσπαθειών
35
- RetryNow: Προσπάθησε τώρα
36
- LastRetry: Τελευταία προσπάθεια
34
+ NextRetry: Επόμενη Προσπάθεια
35
+ RetryCount: Αριθμός Προσπαθειών
36
+ RetryNow: Επανάληψη Τώρα
37
+ # Kill: Kill
38
+ LastRetry: Τελευταία Προσπάθεια
37
39
  OriginallyFailed: Αρχικές Αποτυχίες
38
- AreYouSure: Είστε σίγουρος?
39
- DeleteAll: Διαγραφή όλων
40
+ AreYouSure: Είστε σίγουρος;
41
+ DeleteAll: Διαγραφή Όλων
40
42
  RetryAll: Επανάληψη Όλων
41
- NoRetriesFound: Δεν βρέθηκαν προσπάθειες
43
+ # KillAll: Kill All
44
+ NoRetriesFound: Δεν βρέθηκαν εργασίες προς επαναλήψη
42
45
  Error: Σφάλμα
43
46
  ErrorClass: Κλάση σφάλματος
44
47
  ErrorMessage: Μήνυμα Σφάλματος
45
- ErrorBacktrace: Σφάλμα Backtrace
48
+ ErrorBacktrace: Backtrace Σφάλματος
46
49
  GoBack: ← Πίσω
47
50
  NoScheduledFound: Δεν βρέθηκαν προγραμματισμένες εργασίες
48
51
  When: Πότε
49
52
  ScheduledJobs: Προγραμματισμένες Εργασίες
50
- idle: αδρανής
51
- active: ενεργή
53
+ idle: αδρανές
54
+ active: ενεργό
52
55
  Version: Έκδοση
53
56
  Connections: Συνδέσεις
54
57
  MemoryUsage: Χρήση Μνήμης
55
58
  PeakMemoryUsage: Μέγιστη Χρήση Μνήμης
56
- Uptime: Διάρκεια Λειτουργείας (ημέρες)
59
+ Uptime: Ημέρες Λειτουργίας
57
60
  OneWeek: 1 εβδομάδα
58
61
  OneMonth: 1 μήνας
59
62
  ThreeMonths: 3 μήνες
@@ -62,7 +65,28 @@ el: # <---- change this to your locale code
62
65
  DeadJobs: Αδρανείς Εργασίες
63
66
  NoDeadJobsFound: Δεν βρέθηκαν αδρανείς εργασίες
64
67
  Dead: Αδρανείς
68
+ Process: Διεργασία
65
69
  Processes: Διεργασίες
70
+ Name: Όνομα
66
71
  Thread: Νήμα
67
72
  Threads: Νήματα
68
73
  Jobs: Εργασίες
74
+ Paused: Σε παύση
75
+ Stop: Διακοπή
76
+ Quiet: Σίγαση
77
+ StopAll: Διακοπή Όλων
78
+ QuietAll: Σίγαση Όλων
79
+ PollingInterval: Συχνότητα Ανανέωσης
80
+ Plugins: Πρόσθετα
81
+ NotYetEnqueued: Δεν προστέθηκε στην στοίβα ακόμη
82
+ CreatedAt: Δημιουργήθηκε στις
83
+ BackToApp: Πίσω στην Εφαρμογή
84
+ Latency: Καθυστέρηση
85
+ Pause: Παύση
86
+ Unpause: Κατάργηση Παύσης
87
+ Metrics: Μετρήσεις
88
+ NoDataFound: Δεν βρέθηκαν δεδομένα
89
+ ExecutionTime: Συνολικός Χρόνος Εκτέλεσης
90
+ AvgExecutionTime: Μέσος Χρόνος Εκτέλεσης
91
+ # Context: Context
92
+
data/web/locales/en.yml CHANGED
@@ -86,5 +86,8 @@ en: # <---- change this to your locale code
86
86
  Unpause: Unpause
87
87
  Metrics: Metrics
88
88
  NoDataFound: No data found
89
- ExecutionTime: Execution Time
89
+ ExecutionTime: Total Execution Time
90
+ AvgExecutionTime: Average Execution Time
90
91
  Context: Context
92
+ Bucket: Bucket
93
+ NoJobMetricsFound: No recent job metrics were found
@@ -1,59 +1,69 @@
1
+ <script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
2
+ <script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
3
+ <script type="text/javascript" src="<%= root_path %>javascripts/metrics.js"></script>
1
4
 
2
- <h1><%= t('Metrics') %></h1>
5
+ <h2>Total execution time</h2>
3
6
 
4
- <h3>Top Jobs by Processed Count</h3>
5
- <% top = @resultset[:top_classes] %>
7
+ <%
8
+ table_limit = 20
9
+ chart_limit = 5
10
+ job_results = @query_result.job_results.sort_by { |(kls, jr)| jr.totals["s"] }.reverse.first(table_limit)
11
+ visible_kls = job_results.first(chart_limit).map(&:first)
12
+ %>
6
13
 
7
- <% topp = top["p"]&.first(10) %>
8
- <div class="table_container">
9
- <table class="table table-bordered table-striped table-hover">
10
- <tbody>
11
- <tr>
12
- <th><%= t('Name') %></th>
13
- <th><%= t('Processed') %></th>
14
- <th><%= t('ExecutionTime') %></th>
15
- </tr>
16
- <% if topp %>
17
- <% topp.each do |kls, val| %>
18
- <tr>
19
- <td><code><a href="<%= root_path %>metrics/<%= kls %>"><%= kls %></a></code></td>
20
- <td><%= val %></td>
21
- <td><%= top.dig("ms", kls) %></td>
22
- </tr>
23
- <% end %>
24
- <% else %>
25
- <tr><td colspan=3><%= t("NoDataFound") %></td></tr>
26
- <% end %>
27
- </tbody>
28
- </table>
29
- </div>
14
+ <canvas id="job-metrics-overview-chart"></canvas>
15
+
16
+ <script>
17
+ window.jobMetricsChart = new JobMetricsOverviewChart(
18
+ "job-metrics-overview-chart",
19
+ <%= Sidekiq.dump_json({
20
+ series: job_results.map { |(kls, jr)| [kls, jr.dig("series", "s")] }.to_h,
21
+ marks: @query_result.marks.map { |m| [m.bucket, m.label] },
22
+ visible: visible_kls,
23
+ labels: @query_result.buckets,
24
+ }) %>
25
+ )
26
+ </script>
30
27
 
31
- <h3>Top Jobs by Execution Time</h3>
28
+ <h2>Most Time-Consuming Jobs</h2>
32
29
 
33
- <% topms = top["ms"]&.first(10) %>
34
30
  <div class="table_container">
35
31
  <table class="table table-bordered table-striped table-hover">
36
32
  <tbody>
37
33
  <tr>
38
34
  <th><%= t('Name') %></th>
39
35
  <th><%= t('Processed') %></th>
36
+ <th><%= t('Failed') %></th>
40
37
  <th><%= t('ExecutionTime') %></th>
38
+ <th><%= t('AvgExecutionTime') %></th>
41
39
  </tr>
42
- <% if topms %>
43
- <% topms.each do |kls, val| %>
40
+ <% if job_results.any? %>
41
+ <% job_results.each_with_index do |(kls, jr), i| %>
44
42
  <tr>
45
- <td><code><a href="<%= root_path %>metrics/<%= kls %>"><%= kls %></a></code></td>
46
- <td><%= top.dig("p", kls) %></td>
47
- <td><%= val %></td>
43
+ <td>
44
+ <div class="metrics-swatch-wrapper">
45
+ <% id = "metrics-swatch-#{kls}" %>
46
+ <input
47
+ type="checkbox"
48
+ id="<%= id %>"
49
+ class="metrics-swatch"
50
+ value="<%= kls %>"
51
+ />
52
+ <code><a href="<%= root_path %>metrics/<%= kls %>"><%= kls %></a></code>
53
+ </div>
54
+ <script>jobMetricsChart.registerSwatch("<%= id %>")</script>
55
+ </td>
56
+ <td><%= jr.dig("totals", "p") %></td>
57
+ <td><%= jr.dig("totals", "f") %></td>
58
+ <td><%= jr.dig("totals", "s").round(2) %> seconds</td>
59
+ <td><%= jr.total_avg("s").round(2) %> seconds</td>
48
60
  </tr>
49
61
  <% end %>
50
62
  <% else %>
51
- <tr><td colspan=3><%= t("NoDataFound") %></td></tr>
63
+ <tr><td colspan=5><%= t("NoDataFound") %></td></tr>
52
64
  <% end %>
53
65
  </tbody>
54
66
  </table>
55
67
  </div>
56
68
 
57
- <p>
58
- Data from <%= @resultset[:starts_at] %> to <%= @resultset[:ends_at] %>
59
- </p>
69
+ <p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p>