Commit 3ac87d43 authored by 20after4's avatar 20after4
Browse files

Cleanup + added "html" chart type

parent 5dc6aaef
......@@ -169,6 +169,11 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
"bootstrap": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
"integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
......
This diff is collapsed.
This diff is collapsed.
import { BubbleController } from 'chart.js/auto';
class CategoricalBubbleController extends BubbleController {
/**
* Parse array of objects
* @protected
*/ parseObjectData(meta, data, start, count) {
const parsed = super.parseObjectData(meta, data, start, count);
for(let i = 0; i < parsed.length; i++){
const item = data[start + i];
// @ts-ignore
parsed[i]._custom = item && item.r && +item.r || this.resolveDataElementOptions(i + start).radius;
}
return parsed;
}
}
CategoricalBubbleController.id = 'categoricalBubble';
CategoricalBubbleController.defaults = {
datasetElementType: false,
dataElementType: 'point',
animations: {
numbers: {
type: 'number',
properties: [
'x',
'y',
'borderWidth',
'radius'
]
}
}
};
CategoricalBubbleController.overrides = {
scales: {
x: {
type: 'category'
},
y: {
type: 'category'
}
},
plugins: {
tooltip: {
callbacks: {
title (context) {
var value = context[0] && context[0].parsed && context[0].parsed['value'];
if (!value) {
return '';
}
return value;
}
}
}
}
};
Chart.register(CategoricalBubbleController);
export { CategoricalBubbleController };
import Tonic from '@optoolco/tonic';
import { InputFilter } from './filter-input.js';
class DashboardApp extends Tonic {
connected() {
this.setState();
this.addEventListener('change', this.change);
const self = this;
const form = this.querySelector('form');
this.submitListener = function(e) {
self.submit(e, this);
};
this.popstateListener = function(e) {
window.setTimeout(function() {
self.popstate(e);
}, 0);
};
//form.addEventListener('submit', this.submitListener);
window.addEventListener('popstate', this.popstateListener);
}
change(e) {
if (!e.target.state) {
return;
}
this.state.values[e.target.id] = e.target.value;
for(const i in e.target.state.values){
this.state.values[i] = e.target.state.values[i];
}
console.log('change:', e, this.state.values);
}
popstate(e1) {
this.setState(history.state);
}
setState(state = null) {
if (state) {
this.state = state;
}
const form = this.querySelector('form');
if (!form) {
return;
}
for (const ele of form.elements){
var eleid = ele.getAttribute('controller');
var filter_ele = document.getElementById(eleid);
if (filter_ele) {
filter_ele.setState(this.state);
} else {
eleid = ele.id;
}
if (this.state.values.hasOwnProperty(eleid)) {
const val = this.state.values[eleid] || '';
document.getElementById(eleid).value = val;
}
}
}
submit(e2, originalTarget) {
e2.preventDefault();
e2.stopPropagation();
for (var child of this.querySelectorAll('.filter')){
if (child['modifyState']) {
child.modifyState(this.state);
}
}
if (!this.state.values['project']) {
var input = this.querySelector('.autocomplete input');
input.focus();
input.select();
return false;
}
const url = new URL(window.location.href);
for(const k in this.state.values){
var val = this.state.values[k];
if (val && val['value']) {
val = val['value'];
} else if (!val) {
val = '';
}
url.searchParams.set(k, val);
}
console.log('submit', this.state.values);
history.pushState(this.state, '', url);
const res = fetch(url.toString()).then(function(response) {
if (response.status === 200) {
const tmpl = document.createElement('template');
response.text().then(function(text) {
tmpl.innerHTML = text;
const newBody = tmpl.content.querySelector('.metrics-report');
const oldBody = document.querySelector('.metrics-report');
oldBody.replaceWith(newBody);
});
}
});
return false;
}
render() {
return this.html`
<form id='form_${this.id}'>
<data-source id='datasource'></data-source>
<div class="container-fluid p-0 dashboard-filters">
<autocomplete-filter id='project'></autocomplete-filter>
<input-filter id='task_id' label='Task' style='display:none'></input-filter>
<input-filter id='column' label='Column' style='display:none'></input-filter>
<daterange-filter id='date'>
</daterange-filter>
<div id="filter-group-buttons" class="col-sm-1 align-self-center align-items-center col-auto">
<input type="submit" value="Update" class="button">
</div>
</div>
</form>
${this.childNodes}
`;
}
constructor(){
super();
if (history.state) {
this.setState(history.state);
} else {
this.state.values = {
};
}
}
}
Tonic.add(DashboardApp);
export { DashboardApp, InputFilter };
export default DashboardApp;
import Autocomplete from '@trevoreyre/autocomplete-js/dist/autocomplete.esm.js';
export default Autocomplete;
import Autocomplete from '@trevoreyre/autocomplete-js/dist/autocomplete.esm.js';
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _findTasks() {
_findTasks = _asyncToGenerator(function*(tasks) {
var ids = tasks.split(' ');
var id_str = ids.map((id)=>"'" + id + "'"
).join(",");
var query = `/metrics/Task.json??sql=select+name%2C+status%2C+phid%2C+dateCreated%2C+dateModified%2C+description%2C+authorPHID%2C+ownerPHID%2C+priority%2C+points%2C+subtype%2C+closerPHID%2C+dateClosed%2C+[custom.points.final]%2C+[custom.deadline.start]%2C+id%2C+type%2C+attachments+from+Task+WHERE+id+in+(${id_str})+order+by+dateModified&_shape=objects&_size=max`;
const response = yield fetch(query);
const fetched = yield response.json();
return fetched;
});
return _findTasks.apply(this, arguments);
}
function findTasks(tasks) {
return _findTasks.apply(this, arguments);
}
function projectSearcher() {
var projects = [];
function _fetchProjectsJSON() {
_fetchProjectsJSON = _asyncToGenerator(function*() {
const response = yield fetch("/metrics/project_tree.json?_shape=objects&_size=max&_ttl=86400");
const fetched = yield response.json();
return fetched;
});
return _fetchProjectsJSON.apply(this, arguments);
}
function fetchProjectsJSON() {
return _fetchProjectsJSON.apply(this, arguments);
}
const elements = document.querySelectorAll('.autocomplete');
if (elements && elements.length) {
fetchProjectsJSON().then((fetched)=>{
projects = fetched.rows;
});
}
elements.forEach((el)=>{
var hiddeninput = el.parentElement.querySelector('input[type=hidden]');
var completer = new Autocomplete(el, {
search: (input)=>{
if (input.length < 1) {
return [];
}
let text = input.toLowerCase();
let words = text.split(/\W+/);
function score1(project) {
var strings = [
project.name.toLowerCase()
];
if (project.slug) {
strings.push(project.slug);
}
var score = 0;
for (let w of words){
var cnt = 0;
for (let s of strings){
if (!s) {
continue;
}
if (s.startsWith(text)) {
cnt += 2;
}
if (s.startsWith(w)) {
cnt++;
}
if (s.includes(w)) {
cnt++;
}
}
if (cnt < 1) {
score = 0;
break;
} else {
score += cnt;
}
}
return score;
}
var result = projects.filter(score1);
if (result.length > 1) {
result = result.sort(function(a, b) {
return score1(b) - score1(a);
});
}
return result;
},
autoSelect: true,
onUpdate: (results, selectedIndex)=>{
if (selectedIndex > -1) {
hiddeninput.value = results[selectedIndex].phid;
} else {
hiddeninput.value = '';
}
},
onSubmit: (result)=>{
if (result && result.phid) {
result = result.phid;
} else {
result = '';
}
hiddeninput.value = result;
},
getResultValue: (result)=>result.name
,
renderResult: (result, props)=>`
<li ${props}>
<div>
${result.name}
</div>
</li>
`
,
debounceTime: 500
});
});
}
export { projectSearcher, findTasks };
{"version":3,"file":"autocomplete.js","sourceRoot":"","sources":["autocomplete.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
import { BubbleController } from './_snowpack/pkg/chartjs/auto.js';
class CategoricalBubbleController extends BubbleController {
/**
* Parse array of objects
* @protected
*/ parseObjectData(meta, data, start, count) {
const parsed = super.parseObjectData(meta, data, start, count);
for(let i = 0; i < parsed.length; i++){
const item = data[start + i];
// @ts-ignore
parsed[i]._custom = item && item.r && +item.r || this.resolveDataElementOptions(i + start).radius;
}
return parsed;
}
}
CategoricalBubbleController.id = 'categoricalBubble';
CategoricalBubbleController.defaults = {
datasetElementType: false,
dataElementType: 'point',
animations: {
numbers: {
type: 'number',
properties: [
'x',
'y',
'borderWidth',
'radius'
]
}
}
};
CategoricalBubbleController.overrides = {
scales: {
x: {
type: 'category'
},
y: {
type: 'category'
}
},
plugins: {
tooltip: {
callbacks: {
title (context) {
var value = context[0] && context[0].parsed && context[0].parsed['value'];
if (!value) {
return '';
}
return value;
}
}
}
}
};
Chart.register(CategoricalBubbleController);
export { CategoricalBubbleController };
import Tonic from './_snowpack/pkg/@optoolco/tonic.js';
import { InputFilter } from './filter-input.js';
class DashboardApp extends Tonic {
connected() {
this.setState();
this.addEventListener('change', this.change);
const self = this;
const form = this.querySelector('form');
this.submitListener = function(e) {
self.submit(e, this);
};
this.popstateListener = function(e) {
window.setTimeout(function() {
self.popstate(e);
}, 0);
};
//form.addEventListener('submit', this.submitListener);
window.addEventListener('popstate', this.popstateListener);
}
change(e) {
if (!e.target.state) {
return;
}
this.state.values[e.target.id] = e.target.value;
for(const i in e.target.state.values){
this.state.values[i] = e.target.state.values[i];
}
console.log('change:', e, this.state.values);
}
popstate(e1) {
this.setState(history.state);
}
setState(state = null) {
if (state) {
this.state = state;
}
const form = this.querySelector('form');
if (!form) {
return;
}
for (const ele of form.elements){
var eleid = ele.getAttribute('controller');
var filter_ele = document.getElementById(eleid);
if (filter_ele) {
filter_ele.setState(this.state);
} else {
eleid = ele.id;
}
if (this.state.values.hasOwnProperty(eleid)) {
const val = this.state.values[eleid] || '';
document.getElementById(eleid).value = val;
}
}
}
submit(e2, originalTarget) {
e2.preventDefault();
e2.stopPropagation();
for (var child of this.querySelectorAll('.filter')){
if (child['modifyState']) {
child.modifyState(this.state);
}
}
if (!this.state.values['project']) {
var input = this.querySelector('.autocomplete input');
input.focus();
input.select();
return false;
}
const url = new URL(window.location.href);
for(const k in this.state.values){
var val = this.state.values[k];
if (val && val['value']) {
val = val['value'];
} else if (!val) {
val = '';
}
url.searchParams.set(k, val);
}
console.log('submit', this.state.values);
history.pushState(this.state, '', url);
const res = fetch(url.toString()).then(function(response) {
if (response.status === 200) {
const tmpl = document.createElement('template');
response.text().then(function(text) {
tmpl.innerHTML = text;
const newBody = tmpl.content.querySelector('.metrics-report');
const oldBody = document.querySelector('.metrics-report');
oldBody.replaceWith(newBody);
});
}
});
return false;
}
render() {
return this.html`
<form id='form_${this.id}'>
<data-source id='datasource'></data-source>
<div class="container-fluid p-0 dashboard-filters">
<autocomplete-filter id='project'></autocomplete-filter>
<input-filter id='task_id' label='Task' style='display:none'></input-filter>
<input-filter id='column' label='Column' style='display:none'></input-filter>
<daterange-filter id='date'>
</daterange-filter>
<div id="filter-group-buttons" class="col-sm-1 align-self-center align-items-center col-auto">
<input type="submit" value="Update" class="button">
</div>
</div>
</form>
${this.childNodes}
`;
}
constructor(){
super();
if (history.state) {
this.setState(history.state);
} else {
this.state.values = {
};
}
}
}
Tonic.add(DashboardApp);
export { DashboardApp, InputFilter };
export default DashboardApp;
import { t as tonic } from '../../common/index-3f0ff0c0.js';
import '../../common/_commonjsHelpers-db517561.js';
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen,<