Skip to content

Commit

Permalink
Added completion dates and status updates
Browse files Browse the repository at this point in the history
  • Loading branch information
christos-h committed Feb 3, 2020
1 parent 92978e5 commit db88819
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 22 deletions.
23 changes: 23 additions & 0 deletions src/components/node-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,28 @@ class NodeText extends React.Component<INodeTextProps> {
}
}

completionDateIn(days) {
let today = new Date();
let endDate = "", count = 0;
if(days === 0) return today;
while(count < days) {
endDate = new Date(today.setDate(today.getDate() + 1));
if (endDate.getDay() !== 0 && endDate.getDay() !== 6) {
//Date.getDay() gives weekday starting from 0(Sunday) to 6(Saturday)
count++;
}
}
return endDate;
}

render() {
const { data, nodeTypes, isSelected, maxTitleChars } = this.props;
const lineOffset = 18;
const title = data.title;
const description = data.description;
const timeEstimate = data.timeEstimate;
const completionDate = this.completionDateIn(data.totalTimeEstimate);
let formatted_date = completionDate.getFullYear() + "-" + (completionDate.getMonth() + 1) + "-" + completionDate.getDate()

const className = GraphUtils.classNames('node-text', {
selected: isSelected,
Expand All @@ -58,6 +74,13 @@ class NodeText extends React.Component<INodeTextProps> {
: description}
</tspan>
)}
<tspan opacity={0.8} x={0} dy={lineOffset} fontSize="10px">
{title && (
<tspan opacity={0.8} x={0} dy={lineOffset} fontSize="10px">
Completion Date: {formatted_date}
</tspan>
)}
</tspan>
<tspan opacity={0.8} x={0} dy={lineOffset} fontSize="10px">
{title && timeEstimate > 0 && (
<tspan opacity={0.8} x={0} dy={lineOffset} fontSize="10px">
Expand Down
1 change: 1 addition & 0 deletions src/components/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type INode = {
description: string,
timeEstimate: number,
status: string,
totalTimeEstimate? : number | null,
x?: number | null,
y?: number | null,
type?: string | null,
Expand Down
118 changes: 96 additions & 22 deletions src/examples/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
}

componentDidMount() {
// Get the latest graph from the server
fetch('http://localhost:3001/state').then(res => {
if (res.status === 200) {
return res.json()
Expand All @@ -75,21 +76,9 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
}).then(res => {
if (res != null) {
this.setState({graph: res});
this.calculateDateEstimates();
}
});
}

getLatestGraph() {
// const xhr = new XMLHttpRequest();
//
// xhr.open('GET', 'http://localhost:3001/state');
// xhr.send();
//
// xhr.onload = function () {
// this.setState({"graph": JSON.parse(xhr.responseText)});
// console.log("Got here");
// };


}

Expand Down Expand Up @@ -145,6 +134,14 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
);
};

handleStatusChange = (event: any) => {
const selected = this.state.selected;
selected.status = event.target.value;
this.setState({
selected: selected
}, this.redrawAndSave())
};

/*
* Handlers/Interaction
*/
Expand Down Expand Up @@ -208,6 +205,89 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
this.setState({graph, selected: null}, this.redrawAndSave());
};

calculateDateEstimates() {
// We estimate the predicted time of completion of root nodes,
// By summing the time of their dependencies recursively.
// Lot's of features need to be added here, such as having capacity,
// Node type (technical, business and so on)

// For that we need to add the concept of a 'team' to the project


// 1) Find root nodes
// 2) Find the total number of days
// 3) Convert that to a date, so omit weekends. This should be done at the presentation layer
// 4) Also we need to disallow cycles, or things will exprode

let rootNodes = this.findRootNodes();
let graph = this.updateGraphTotalTimeEstimates(rootNodes, this.state.graph);

this.setState({graph: graph});
}

findRootNodes() {
// Gets the root nodes of the graph
// O(n^2) for now. Can be made faster but meh.
let rootNodes = [];
this.state.graph.nodes.forEach(node => {
let isRoot = true;
this.state.graph.edges.forEach(edge => {
if (edge.source === node.id) {
isRoot = false;
}
});

if (isRoot) {
rootNodes.push(node);
}
});

return rootNodes;
}

updateGraphTotalTimeEstimates(rootNodes, graph) {
// Update the total estimates for the entire graph
rootNodes.forEach(node => {
this.updateTotalTimeEstimate(node, graph);
});

return graph;
}

updateTotalTimeEstimate(node, graph) {
if (node === undefined || node.status === 'Done') return 0;
// Update the total time estimates for a node recursively
node.totalTimeEstimate = parseFloat(node.timeEstimate);

// Get children Ids
let childrenIds = [];
graph.edges.forEach(edge => {
if (edge.target === node.id) {
childrenIds.push(edge.source);
}
});

// Get children ids as nodes
let children = childrenIds.map(id => {
for (let i = 0; i < graph.nodes.length; i++) {
if (graph.nodes[i].id === id) {
return graph.nodes[i];
}
}
});

// Add their time estimate to the parents
let max = 0;
children.forEach(child => {
max = Math.max(this.updateTotalTimeEstimate(child, graph), max);
});

node.totalTimeEstimate += max;

return node.totalTimeEstimate;
}


// Creates a new node between two edges
onCreateEdge = (sourceViewNode: INode, targetViewNode: INode) => {
const graph = this.state.graph;
Expand Down Expand Up @@ -309,6 +389,8 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
};

redrawAndSave = () => {
this.calculateDateEstimates();

this.setState({
layoutEngineType: 'None',
});
Expand All @@ -328,23 +410,14 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
// get a callback when the server responds
xhr.addEventListener('load', () => {
// update the state of the component with the result here
console.log(xhr);
});

xhr.setRequestHeader('Content-Type', 'application/json');

// send the request
xhr.send(JSON.stringify(this.state.graph));

// TODO
}

onSelectPanNode = (event: any) => {
if (this.GraphView) {
this.GraphView.panToNode(event.target.value, true);
}
};

/*
* Render
*/
Expand Down Expand Up @@ -384,6 +457,7 @@ class Graph extends React.Component<IGraphProps, IGraphState> {
<select
className="node-status"
onChange={this.handleStatusChange}
value={this.state.selected.status}
>
<option value={'ToDo'}>To Do</option>
<option value={'InProgress'}>In Progress</option>
Expand Down

0 comments on commit db88819

Please sign in to comment.