Allow opening multiple burndown panels
This commit is contained in:
11
src/App.tsx
11
src/App.tsx
@ -30,7 +30,9 @@ function App() {
|
||||
const [burndownData, setBurndownData] = useState({ series: [] });
|
||||
|
||||
window.addEventListener('message', event => {
|
||||
const tasks = Object.fromEntries(event.data.tasks.map(task => [task.id, task]));
|
||||
const tasks = event.data.tasks
|
||||
? Object.fromEntries(event.data.tasks.map(task => [task.id, task]))
|
||||
: {};
|
||||
switch (event.data.type) {
|
||||
case 'index':
|
||||
setName(event.data.index.name);
|
||||
@ -66,7 +68,11 @@ function App() {
|
||||
case 'burndown':
|
||||
setName(event.data.index.name);
|
||||
setTasks(tasks);
|
||||
setSprints(event.data.index.options.sprints || []);
|
||||
setSprints(
|
||||
'sprints' in event.data.index.options
|
||||
? event.data.index.options.sprints
|
||||
: []
|
||||
);
|
||||
setBurndownData(event.data.burndownData);
|
||||
break;
|
||||
}
|
||||
@ -111,6 +117,7 @@ function App() {
|
||||
tasks={tasks}
|
||||
sprints={sprints}
|
||||
burndownData={burndownData}
|
||||
vscode={vscode}
|
||||
/>
|
||||
}
|
||||
</React.Fragment>
|
||||
|
||||
100
src/Burndown.tsx
100
src/Burndown.tsx
@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import { LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts';
|
||||
import React, { useState } from 'react';
|
||||
import { ResponsiveContainer, LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts';
|
||||
import VSCodeApi from "./VSCodeApi";
|
||||
import formatDate from 'dateformat';
|
||||
|
||||
const Burndown = ({ name, tasks, sprints, burndownData }: {
|
||||
const Burndown = ({ name, tasks, sprints, burndownData, vscode }: {
|
||||
name: string,
|
||||
tasks: Record<string, KanbnTask>,
|
||||
sprints: KanbnSprint[],
|
||||
@ -15,8 +17,14 @@ const Burndown = ({ name, tasks, sprints, burndownData }: {
|
||||
y: number
|
||||
}>
|
||||
}>
|
||||
}
|
||||
},
|
||||
vscode: VSCodeApi
|
||||
}) => {
|
||||
const [sprintMode, setSprintMode] = useState(sprints.length > 0);
|
||||
const [sprint, setSprint] = useState(null);
|
||||
const [startDate, setStartDate] = useState(null);
|
||||
const [endDate, setEndDate] = useState(null);
|
||||
|
||||
const data = [
|
||||
{name: 'one', uv: 20},
|
||||
{name: 'two', uv: 80},
|
||||
@ -26,14 +34,82 @@ const Burndown = ({ name, tasks, sprints, burndownData }: {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div>burndown chart</div>
|
||||
<LineChart width={600} height={300} data={data} margin={{ top: 5, right: 20, bottom: 5, left: 0 }}>
|
||||
<Line type="monotone" dataKey="uv" stroke="#8884d8" />
|
||||
<CartesianGrid stroke="#ccc" strokeDasharray="5 5" />
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
</LineChart>
|
||||
<div className="kanbn-header">
|
||||
<h1 className="kanbn-header-name">
|
||||
<p>{name}</p>
|
||||
<div className="kanbn-burndown-settings">
|
||||
<form>
|
||||
{
|
||||
sprintMode
|
||||
? <select className="kanbn-burndown-settings-sprint-select" onChange={e => { console.log(e); }}>
|
||||
{
|
||||
sprints.length > 0
|
||||
? sprints.map((sprint, i) => {
|
||||
return (
|
||||
<option value={i}>{sprint.name}</option>
|
||||
);
|
||||
})
|
||||
: <option disabled>No sprints</option>
|
||||
}
|
||||
</select>
|
||||
: <React.Fragment>
|
||||
<input
|
||||
type="date"
|
||||
className="kanbn-burndown-settings-input kanbn-burndown-settings-start-date"
|
||||
onChange={e => { console.log(e); }}
|
||||
/>
|
||||
<input
|
||||
type="date"
|
||||
className="kanbn-burndown-settings-input kanbn-burndown-settings-end-date"
|
||||
onChange={e => { console.log(e); }}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
<button
|
||||
type="button"
|
||||
className={[
|
||||
'kanbn-header-button',
|
||||
'kanbn-burndown-settings-sprint-mode',
|
||||
sprintMode ? 'kanbn-header-button-active' : 'kanbn-header-button-inactive'
|
||||
].join(' ')}
|
||||
onClick={() => {
|
||||
setSprintMode(true);
|
||||
// update burndown chart
|
||||
}}
|
||||
title="View sprint burndown"
|
||||
>
|
||||
<i className="codicon codicon-rocket"></i>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={[
|
||||
'kanbn-header-button',
|
||||
'kanbn-burndown-settings-date-mode',
|
||||
sprintMode ? 'kanbn-header-button-inactive' : 'kanbn-header-button-active'
|
||||
].join(' ')}
|
||||
onClick={() => {
|
||||
setSprintMode(false);
|
||||
// update burndown chart
|
||||
}}
|
||||
title="View date-range burndown"
|
||||
>
|
||||
<i className="codicon codicon-clock"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="kanbn-burndown">
|
||||
<ResponsiveContainer width="100%" height="100%" className="kanbn-burndown-chart">
|
||||
<LineChart data={data}>
|
||||
<Line type="monotone" dataKey="uv" stroke="#8884d8" />
|
||||
<CartesianGrid stroke="#ccc" strokeDasharray="5 5" />
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@ -20,7 +20,7 @@ body.vscode-high-contrast {
|
||||
|
||||
.kanbn-header-name p {
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
flex: 2;
|
||||
margin: 0;
|
||||
padding: 4px 0;
|
||||
}
|
||||
@ -42,6 +42,8 @@ body.vscode-high-contrast {
|
||||
padding: 8px;
|
||||
background-color: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
font-family: var(--vscode-font-family);
|
||||
font-size: var(--vscode-font-size);
|
||||
border: 1px transparent solid;
|
||||
}
|
||||
|
||||
@ -340,12 +342,13 @@ body.vscode-dark .kanbn-task-editor-field-input[type="date"]::-webkit-calendar-p
|
||||
margin: 8px 0;
|
||||
background-color: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
font-family: var(--vscode-font-family);
|
||||
font-size: var(--vscode-font-size);
|
||||
border: 1px transparent solid;
|
||||
}
|
||||
|
||||
.kanbn-task-editor-field-input[type=date] {
|
||||
font-family: var(--vscode-font-family);
|
||||
font-size: var(--vscode-font-size);
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.kanbn-task-editor-field-select {
|
||||
@ -477,3 +480,60 @@ body.vscode-dark .kanbn-task-editor-field-input[type="date"]::-webkit-calendar-p
|
||||
.kanbn-task-editor-field-comment-text .kanbn-task-editor-field-textarea {
|
||||
min-height: 90px;
|
||||
}
|
||||
|
||||
.kanbn-burndown-settings {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.kanbn-burndown-settings form {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.kanbn-burndown-settings-sprint-select {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 8px;
|
||||
background-color: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
border: 1px transparent solid;
|
||||
}
|
||||
|
||||
.kanbn-burndown-settings-input {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
flex: 0.5;
|
||||
padding: 8px;
|
||||
background-color: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
font-family: var(--vscode-font-family);
|
||||
font-size: var(--vscode-font-size);
|
||||
border: 1px transparent solid;
|
||||
}
|
||||
|
||||
.kanbn-burndown-settings-input[type=date] {
|
||||
padding: 6px 8px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.kanbn-burndown-settings-sprint-select:hover,
|
||||
.kanbn-burndown-settings-sprint-select:focus,
|
||||
.kanbn-burndown-settings-input:hover,
|
||||
.kanbn-burndown-settings-input:focus {
|
||||
border-color: var(--vscode-input-border);
|
||||
}
|
||||
|
||||
body.vscode-dark .kanbn-burndown-settings-input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
.kanbn-header-button-inactive {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.kanbn-burndown {
|
||||
height: 85vh;
|
||||
width: 95vw;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user