2021-09-06 11:50:35 +00:00
|
|
|
<html>
|
|
|
|
<head>
|
2021-09-06 14:21:07 +00:00
|
|
|
<title>Plan</title>
|
2021-09-06 11:50:35 +00:00
|
|
|
<style>
|
|
|
|
body { font-family: monospace; }
|
|
|
|
table { border: solid;}
|
|
|
|
img {
|
|
|
|
width:50px;
|
|
|
|
height:50px;
|
|
|
|
}
|
|
|
|
td {
|
|
|
|
width:60px;
|
|
|
|
height:30px;
|
|
|
|
text-align: center;
|
|
|
|
border: solid 1px;
|
|
|
|
}
|
2021-09-06 13:37:20 +00:00
|
|
|
.card { border-radius: 6px;
|
|
|
|
border: solid 1px #000;
|
|
|
|
color: white;
|
|
|
|
min-width: 1em;
|
|
|
|
height: 1em;
|
|
|
|
padding: 1px 3px 3px ;
|
|
|
|
text-align: center;
|
|
|
|
font-weight: bold;
|
|
|
|
margin: 2px;
|
|
|
|
display: inline-block;
|
|
|
|
}
|
2021-09-06 14:21:07 +00:00
|
|
|
#trash {
|
|
|
|
padding: 0.3em;
|
|
|
|
width: 50px;
|
|
|
|
border-radius: 3px;
|
|
|
|
margin: 1em;
|
|
|
|
font-size: 2em;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.hl { background-color: red; color: white; }
|
2021-09-06 11:50:35 +00:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<center>
|
|
|
|
<h1>Plan</h1>
|
2021-09-06 14:21:07 +00:00
|
|
|
<h3>Team</h3>
|
2021-09-06 12:48:48 +00:00
|
|
|
<div id="devs"></div>
|
2021-09-06 14:21:07 +00:00
|
|
|
<h3>releases</h3>
|
2021-09-06 12:48:48 +00:00
|
|
|
<div id="main"></div>
|
2021-09-06 14:21:07 +00:00
|
|
|
<div id="trash">🗑</div>
|
2021-09-06 11:50:35 +00:00
|
|
|
</body>
|
|
|
|
<script>
|
2021-09-06 13:37:20 +00:00
|
|
|
// (function () {
|
2021-09-06 12:48:48 +00:00
|
|
|
|
2021-09-06 15:35:54 +00:00
|
|
|
function debug(args) { console.log(args); }
|
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function enabledrag(event) { event.preventDefault(); }
|
2021-09-06 15:27:11 +00:00
|
|
|
|
|
|
|
var state = null;
|
|
|
|
function retrieveState(){
|
|
|
|
var savestr = localStorage.getItem('plannerstate');
|
|
|
|
if (savestr) {
|
|
|
|
state = JSON.parse(savestr);
|
|
|
|
} else {
|
|
|
|
state = {people: ["Ag",
|
|
|
|
"Ambrose",
|
|
|
|
"Irina",
|
|
|
|
"Kiril",
|
|
|
|
"Mark",
|
|
|
|
"Olivier",
|
|
|
|
"Rob",
|
|
|
|
"Wanderson",
|
|
|
|
],
|
|
|
|
fts: [ "SX Session",
|
|
|
|
"Bug Squashing",
|
|
|
|
"Secure Client" ],
|
|
|
|
assignments: {}
|
|
|
|
};
|
|
|
|
}
|
2021-09-06 15:35:54 +00:00
|
|
|
debug(state);
|
2021-09-06 15:27:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function saveState() {
|
|
|
|
localStorage.setItem('plannerstate',JSON.stringify(state));
|
|
|
|
}
|
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function init(){
|
2021-09-06 15:27:11 +00:00
|
|
|
retrieveState();
|
2021-09-06 15:35:54 +00:00
|
|
|
debug(state);
|
2021-09-06 14:21:07 +00:00
|
|
|
var devcards=document.getElementById("devs");
|
2021-09-06 15:27:11 +00:00
|
|
|
state.people.forEach(function(p) {
|
2021-09-06 14:21:07 +00:00
|
|
|
devcards.appendChild( createDev(p) );
|
|
|
|
})
|
2021-09-06 15:27:11 +00:00
|
|
|
renderState();
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderState () {
|
|
|
|
if (state) {
|
|
|
|
// build main table
|
|
|
|
var main = document.getElementById("main");
|
|
|
|
main.innerHTML='';
|
|
|
|
main.appendChild(genTable());
|
|
|
|
var cells = document.querySelectorAll("td");
|
|
|
|
cells.forEach(function(cell) {
|
|
|
|
cell.ondragover = enabledrag;
|
|
|
|
cell.ondrop = function(ev){drop(ev,this);};
|
|
|
|
});
|
|
|
|
// build trash
|
|
|
|
var trashel = document.getElementById("trash");
|
|
|
|
trashel.ondragover = enabledrag;
|
|
|
|
trashel.ondrop = trash;
|
|
|
|
trashel.ondragenter = hltrash;
|
|
|
|
trashel.ondragleave = unhltrash;
|
|
|
|
var cards = document.querySelectorAll(".card");
|
|
|
|
cards.forEach(function(card){ card.draggable = true; card.ondragstart = drag; });
|
|
|
|
// build assignments
|
|
|
|
for ( cellid in state.assignments ) {
|
2021-09-06 15:35:54 +00:00
|
|
|
state.assignments[cellid].forEach (function(member) {
|
2021-09-06 15:27:11 +00:00
|
|
|
var el = document.getElementById( cellid );
|
2021-09-06 15:35:54 +00:00
|
|
|
debug("devcard; member: " + member + ", cellid: " + cellid);
|
2021-09-06 15:27:11 +00:00
|
|
|
el.appendChild(devcard(member, cellid));
|
2021-09-06 15:35:54 +00:00
|
|
|
})
|
2021-09-06 15:27:11 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-06 14:21:07 +00:00
|
|
|
}
|
2021-09-06 13:37:20 +00:00
|
|
|
|
2021-09-06 12:48:48 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function genTable () {
|
|
|
|
var t = document.createElement("table");
|
|
|
|
t.id = "maintable";
|
|
|
|
var previous = 2; // nb of previous release to show (2 means, 1 previous to prod, + current in prod)
|
|
|
|
var nexts = 4; // nb of next releases to show
|
|
|
|
var nbcolumns = previous + nexts;
|
|
|
|
var rels = releases( previous, nexts );
|
|
|
|
rels[0]="FT";
|
|
|
|
t.appendChild(mkTitleRow(rels));
|
2021-09-06 15:27:11 +00:00
|
|
|
state.fts.forEach( function(ft) {
|
|
|
|
t.appendChild(mkRow(ft,nbcolumns,rels));
|
2021-09-06 14:21:07 +00:00
|
|
|
});
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
function mkTitleRow( vs ) {
|
|
|
|
var rows = document.createElement("tr");
|
|
|
|
vs.forEach (function(v) {
|
|
|
|
var c = document.createElement("th");
|
|
|
|
c.textContent = v;
|
|
|
|
rows.appendChild(c);
|
|
|
|
});
|
|
|
|
return rows;
|
|
|
|
}
|
2021-09-06 15:27:11 +00:00
|
|
|
|
|
|
|
function safe (str) {
|
|
|
|
var safestr = str.replace(/\W/g,'_');
|
|
|
|
return safestr;
|
|
|
|
}
|
|
|
|
|
|
|
|
function mkid(ft,rel) {
|
|
|
|
return "cell-" + safe(ft) + "-" + rel;
|
|
|
|
}
|
2021-09-06 15:35:54 +00:00
|
|
|
|
2021-09-06 15:27:11 +00:00
|
|
|
function mkRow( ft, n, rels ) {
|
2021-09-06 14:21:07 +00:00
|
|
|
var rows = document.createElement("tr");
|
2021-09-06 11:50:35 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
var ttitle = document.createElement("th");
|
|
|
|
ttitle.textContent = ft;
|
|
|
|
rows.appendChild(ttitle)
|
2021-09-06 13:37:20 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
var arr = new Array(n);
|
|
|
|
arr.fill("");
|
2021-09-06 15:27:11 +00:00
|
|
|
i=1;
|
2021-09-06 14:21:07 +00:00
|
|
|
arr.forEach (function(v) {
|
|
|
|
var c = document.createElement("td");
|
|
|
|
c.textContent = v;
|
2021-09-06 15:27:11 +00:00
|
|
|
c.id = mkid(ft, rels[i]);
|
2021-09-06 14:21:07 +00:00
|
|
|
rows.appendChild(c);
|
2021-09-06 15:27:11 +00:00
|
|
|
i++;
|
2021-09-06 14:21:07 +00:00
|
|
|
});
|
|
|
|
return rows;
|
|
|
|
}
|
2021-09-06 13:37:20 +00:00
|
|
|
|
2021-09-06 15:27:11 +00:00
|
|
|
function devcard(devname,cellid){
|
2021-09-06 14:21:07 +00:00
|
|
|
var devdiv = document.createElement('div');
|
|
|
|
devdiv.classList.add(devname);
|
|
|
|
devdiv.classList.add('card');
|
|
|
|
devdiv.textContent = devname;
|
|
|
|
devdiv.draggable = true;
|
2021-09-06 15:27:11 +00:00
|
|
|
devdiv.id = "inner-" + devname + "-"+ cellid;
|
2021-09-06 14:21:07 +00:00
|
|
|
devdiv.style.backgroundColor = genColor(devname);
|
|
|
|
devdiv.ondragstart = drag;
|
|
|
|
return devdiv;
|
|
|
|
}
|
2021-09-06 11:50:35 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function hashcode(s){
|
|
|
|
return s.split("").reduce(
|
|
|
|
function(acc,l){
|
|
|
|
acc = acc + 10 * (l.charCodeAt(0) - 'A'.charCodeAt(0));
|
|
|
|
return (acc % 256);
|
|
|
|
},
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
function genColor(devname) {
|
|
|
|
var h = hashcode(devname);
|
|
|
|
return "hsl(" + h + ",80%, 36%)";
|
|
|
|
}
|
|
|
|
|
|
|
|
function createDev(devname){
|
2021-09-06 15:27:11 +00:00
|
|
|
var res = devcard(devname,'');
|
2021-09-06 14:21:07 +00:00
|
|
|
res.id = devname;
|
|
|
|
return res;
|
|
|
|
};
|
|
|
|
|
|
|
|
// release logic
|
2021-09-06 12:48:48 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function getWeekNumber(d) {
|
|
|
|
// Copy date so don't modify original
|
|
|
|
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
|
|
|
|
// Set to nearest Thursday: current date + 4 - current day number
|
|
|
|
// Make Sunday's day number 7
|
|
|
|
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
|
|
|
|
// Get first day of year
|
|
|
|
var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
|
|
|
|
// Calculate full weeks to nearest Thursday
|
|
|
|
var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
|
|
|
|
// Return array of year and week number
|
|
|
|
return [d.getUTCFullYear(), weekNo];
|
|
|
|
}
|
2021-09-06 13:37:20 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
// should return a list of next releases
|
|
|
|
// use the current date
|
|
|
|
function releases(previous,nexts) {
|
|
|
|
var curr = new Date; // get current date
|
|
|
|
var monday = curr.getDate() - curr.getDay() + 1;
|
|
|
|
var wed = monday + 2;
|
|
|
|
var nbDays = curr.getDay() - 3;
|
|
|
|
var afterWed = nbDays > 0;
|
|
|
|
var w = getWeekNumber(curr);
|
|
|
|
var year = w[0];
|
|
|
|
var week = w[1];
|
|
|
|
var release = "";
|
|
|
|
var releaseWeek = (week+1)%2;
|
|
|
|
var releaseNumVersion = Math.floor((week - 16)/2) + 71;
|
|
|
|
var currentVersion = "v1." + (releaseNumVersion - (1 + previous));
|
|
|
|
var size=nexts + previous + 1;
|
|
|
|
var releases = new Array(size)
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
releases [i] = "v1." + (releaseNumVersion + (i - 3));
|
2021-09-06 13:37:20 +00:00
|
|
|
}
|
2021-09-06 14:21:07 +00:00
|
|
|
return releases;
|
|
|
|
}
|
2021-09-06 13:37:20 +00:00
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
// drag n drop
|
|
|
|
function drag(ev) {
|
|
|
|
ev.dataTransfer.setData("text", ev.target.id);
|
|
|
|
}
|
|
|
|
|
2021-09-06 15:27:11 +00:00
|
|
|
function createAssignment(id, name) {
|
|
|
|
if (! state.assignments[id]) {
|
|
|
|
state.assignments[id]=[];
|
|
|
|
}
|
|
|
|
state.assignments[id].push(name);
|
2021-09-06 15:35:54 +00:00
|
|
|
debug(state.assignments);
|
2021-09-06 15:27:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function moveAssignment(id, name) {
|
|
|
|
var memberName = name.replace(/^[^-]*-/,'').replace(/-cell-.*$/,'');
|
2021-09-06 15:35:54 +00:00
|
|
|
removeAssignment(name);
|
2021-09-06 15:27:11 +00:00
|
|
|
if (! state.assignments[id]) {
|
|
|
|
state.assignments[id]=[];
|
|
|
|
}
|
|
|
|
state.assignments[id].push(memberName);
|
2021-09-06 15:35:54 +00:00
|
|
|
debug(state.assignments);
|
2021-09-06 15:27:11 +00:00
|
|
|
}
|
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function drop(ev,el) {
|
|
|
|
ev.preventDefault();
|
|
|
|
var name = ev.dataTransfer.getData("text");
|
|
|
|
if ( name.startsWith("inner-") ) {
|
2021-09-06 15:35:54 +00:00
|
|
|
debug("move: " + name);
|
2021-09-06 15:27:11 +00:00
|
|
|
document.getElementById(name).remove();
|
|
|
|
var memberName = name.replace(/^[^-]*-/,'').replace(/-cell-.*$/,'');
|
|
|
|
el.appendChild(devcard(memberName,el.id));
|
|
|
|
moveAssignment(el.id, name);
|
2021-09-06 14:21:07 +00:00
|
|
|
} else {
|
2021-09-06 15:35:54 +00:00
|
|
|
debug("create: " + name);
|
2021-09-06 15:27:11 +00:00
|
|
|
el.appendChild(devcard(name,el.id));
|
|
|
|
createAssignment(el.id, name);
|
2021-09-06 13:37:20 +00:00
|
|
|
}
|
2021-09-06 15:27:11 +00:00
|
|
|
saveState();
|
2021-09-06 14:21:07 +00:00
|
|
|
}
|
2021-09-06 13:37:20 +00:00
|
|
|
|
2021-09-06 15:35:54 +00:00
|
|
|
|
|
|
|
function removeAssignment(name) {
|
|
|
|
var memberName = name.replace(/^[^-]*-/,'').replace(/-cell-.*$/,'');
|
|
|
|
var oldid = name.replace(/^.*-cell-/,'cell-');
|
|
|
|
debug("memberName: " + memberName);
|
|
|
|
debug("OLDID: " + oldid);
|
|
|
|
var idx = state.assignments[oldid].indexOf(memberName);
|
|
|
|
if (idx !== -1) {
|
|
|
|
state.assignments[oldid].splice(idx,1);
|
|
|
|
}
|
|
|
|
debug(state.assignments);
|
|
|
|
}
|
|
|
|
|
2021-09-06 14:21:07 +00:00
|
|
|
function trash(ev) {
|
|
|
|
ev.preventDefault();
|
|
|
|
var name = ev.dataTransfer.getData("text");
|
|
|
|
if ( name.startsWith("inner-") ) {
|
2021-09-06 15:35:54 +00:00
|
|
|
debug("TRASH: " + name);
|
2021-09-06 14:21:07 +00:00
|
|
|
unhltrash(null);
|
|
|
|
document.getElementById(name).remove();
|
2021-09-06 15:35:54 +00:00
|
|
|
removeAssignment(name);
|
2021-09-06 12:48:48 +00:00
|
|
|
}
|
2021-09-06 15:27:11 +00:00
|
|
|
saveState();
|
2021-09-06 14:21:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function hltrash(ev) {
|
|
|
|
var trashel = document.getElementById('trash');
|
|
|
|
trashel.classList.add("hl");
|
|
|
|
}
|
|
|
|
|
|
|
|
function unhltrash(ev) {
|
|
|
|
var trashel = document.getElementById('trash');
|
|
|
|
trashel.classList.remove("hl");
|
|
|
|
}
|
|
|
|
window.addEventListener("load", init);
|
2021-09-06 15:27:11 +00:00
|
|
|
|
2021-09-06 13:37:20 +00:00
|
|
|
// })();
|
2021-09-06 11:50:35 +00:00
|
|
|
</script>
|
|
|
|
</html>
|