Install recharts, prepare for burndown chart

This commit is contained in:
Gordon 2021-04-15 22:04:32 +01:00
parent f7f2eebfa4
commit 0d8508dd19
9 changed files with 364 additions and 60 deletions

View File

@ -1,6 +1,7 @@
import * as path from 'path';
import * as vscode from 'vscode';
import KanbnTaskPanel from './KanbnTaskPanel';
import KanbnBurndownPanel from './KanbnBurndownPanel';
export default class KanbnBoardPanel {
public static currentPanel: KanbnBoardPanel | undefined;
@ -148,8 +149,12 @@ export default class KanbnBoardPanel {
// Open a burndown chart
case 'kanbn.burndown':
// TODO open a burndown chart webview panel
vscode.window.showErrorMessage('Not implemented yet!');
KanbnBurndownPanel.createOrShow(
this._extensionPath,
this._workspacePath,
this._kanbn
);
KanbnBurndownPanel.update();
return;
// Start a new sprint

View File

@ -1,21 +1,21 @@
import * as path from 'path';
import * as vscode from 'vscode';
import * as path from "path";
import * as vscode from "vscode";
export default class KanbnBurndownPanel {
public static currentPanel: KanbnBurndownPanel | undefined;
private static readonly viewType = 'react';
private static readonly viewType = "react";
private readonly _panel: vscode.WebviewPanel;
private readonly _extensionPath: string;
private readonly _workspacePath: string;
private readonly _kanbn: typeof import('@basementuniverse/kanbn/src/main');
private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main");
private _disposables: vscode.Disposable[] = [];
public static createOrShow(
extensionPath: string,
workspacePath: string,
kanbn: typeof import('@basementuniverse/kanbn/src/main')
kanbn: typeof import("@basementuniverse/kanbn/src/main")
) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
@ -41,10 +41,20 @@ export default class KanbnBurndownPanel {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error);
return;
}
let tasks: any[];
try {
tasks = (await KanbnBurndownPanel.currentPanel._kanbn.loadAllTrackedTasks(index)).map(
task => KanbnBurndownPanel.currentPanel!._kanbn.hydrateTask(index, task)
);
} catch (error) {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error);
return;
}
KanbnBurndownPanel.currentPanel._panel.webview.postMessage({
type: 'burndown',
type: "burndown",
index,
dateFormat: KanbnBurndownPanel.currentPanel._kanbn.getDateFormat(index)
tasks,
dateFormat: KanbnBurndownPanel.currentPanel._kanbn.getDateFormat(index),
});
}
}
@ -53,14 +63,14 @@ export default class KanbnBurndownPanel {
extensionPath: string,
workspacePath: string,
column: vscode.ViewColumn,
kanbn: typeof import('@basementuniverse/kanbn/src/main')
kanbn: typeof import("@basementuniverse/kanbn/src/main")
) {
this._extensionPath = extensionPath;
this._workspacePath = workspacePath;
this._kanbn = kanbn;
// Create and show a new webview panel
this._panel = vscode.window.createWebviewPanel(KanbnBurndownPanel.viewType, 'Burndown Chart', column, {
this._panel = vscode.window.createWebviewPanel(KanbnBurndownPanel.viewType, "Burndown Chart", column, {
// Enable javascript in the webview
enableScripts: true,
@ -69,18 +79,18 @@ export default class KanbnBurndownPanel {
// Restrict the webview to only loading content from allowed paths
localResourceRoots: [
vscode.Uri.file(path.join(this._extensionPath, 'build')),
vscode.Uri.file(path.join(this._extensionPath, "build")),
vscode.Uri.file(path.join(this._workspacePath, this._kanbn.getFolderName())),
vscode.Uri.file(path.join(this._extensionPath, 'node_modules', 'vscode-codicons', 'dist'))
]
vscode.Uri.file(path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist")),
],
});
(this._panel as any).iconPath = {
light: vscode.Uri.file(path.join(this._extensionPath, 'resources', 'burndown_light.svg')),
dark: vscode.Uri.file(path.join(this._extensionPath, 'resources', 'burndown_dark.svg'))
light: vscode.Uri.file(path.join(this._extensionPath, "resources", "burndown_light.svg")),
dark: vscode.Uri.file(path.join(this._extensionPath, "resources", "burndown_dark.svg")),
};
// Set the webview's title to the kanbn project name
this._kanbn.getIndex().then(index => {
this._kanbn.getIndex().then((index) => {
this._panel.title = index.name;
});
@ -92,15 +102,18 @@ export default class KanbnBurndownPanel {
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
// Handle messages from the webview
this._panel.webview.onDidReceiveMessage(async message => {
switch (message.command) {
// Display error message
case 'error':
vscode.window.showErrorMessage(message.text);
return;
}
}, null, this._disposables);
this._panel.webview.onDidReceiveMessage(
async (message) => {
switch (message.command) {
// Display error message
case "error":
vscode.window.showErrorMessage(message.text);
return;
}
},
null,
this._disposables
);
}
public dispose() {
@ -117,21 +130,21 @@ export default class KanbnBurndownPanel {
}
private _getHtmlForWebview() {
const manifest = require(path.join(this._extensionPath, 'build', 'asset-manifest.json'));
const mainScript = manifest['main.js'];
const mainStyle = manifest['main.css'];
const scriptUri = vscode.Uri
.file(path.join(this._extensionPath, 'build', mainScript))
.with({ scheme: 'vscode-resource' });
const styleUri = vscode.Uri
.file(path.join(this._extensionPath, 'build', mainStyle))
.with({ scheme: 'vscode-resource' });
const customStyleUri = vscode.Uri
.file(path.join(this._workspacePath, this._kanbn.getFolderName(), 'board.css'))
.with({ scheme: 'vscode-resource' });
const codiconsUri = vscode.Uri
.file(path.join(this._extensionPath, 'node_modules', 'vscode-codicons', 'dist', 'codicon.css'))
.with({ scheme: 'vscode-resource' });
const manifest = require(path.join(this._extensionPath, "build", "asset-manifest.json"));
const mainScript = manifest["main.js"];
const mainStyle = manifest["main.css"];
const scriptUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainScript)).with({
scheme: "vscode-resource",
});
const styleUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainStyle)).with({
scheme: "vscode-resource",
});
const customStyleUri = vscode.Uri.file(
path.join(this._workspacePath, this._kanbn.getFolderName(), "board.css")
).with({ scheme: "vscode-resource" });
const codiconsUri = vscode.Uri.file(
path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css")
).with({ scheme: "vscode-resource" });
// Use a nonce to whitelist which scripts can be run
const nonce = getNonce();
@ -147,7 +160,7 @@ export default class KanbnBurndownPanel {
<link rel="stylesheet" type="text/css" href="${customStyleUri}">
<link rel="stylesheet" type="text/css" href="${codiconsUri}">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-${nonce}'; font-src vscode-resource:; style-src vscode-resource: 'unsafe-inline' http: https: data:;">
<base href="${vscode.Uri.file(path.join(this._extensionPath, 'build')).with({ scheme: 'vscode-resource' })}/">
<base href="${vscode.Uri.file(path.join(this._extensionPath, "build")).with({ scheme: "vscode-resource" })}/">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,6 +1,7 @@
import * as vscode from 'vscode';
import KanbnStatusBarItem from './KanbnStatusBarItem';
import KanbnBoardPanel from './KanbnBoardPanel';
import KanbnBurndownPanel from './KanbnBurndownPanel';
import KanbnTaskPanel from './KanbnTaskPanel';
let kanbnStatusBarItem: KanbnStatusBarItem;
@ -105,8 +106,28 @@ export async function activate(context: vscode.ExtensionContext) {
// Register a command to open a burndown chart.
context.subscriptions.push(vscode.commands.registerCommand('kanbn.burndown', async () => {
// TODO open burndown chart singleton webview panel
vscode.window.showErrorMessage('Not implemented yet!');
// If no workspace folder is opened, we can't open the burndown chart
if (vscode.workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage('You need to open a workspace before viewing the burndown chart.');
return;
}
// Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import('@basementuniverse/kanbn/src/main');
// If kanbn is initialised, view the burndown chart
if (await kanbn.initialised()) {
KanbnBurndownPanel.createOrShow(
context.extensionPath,
vscode.workspace.workspaceFolders[0].uri.fsPath,
kanbn
);
KanbnBurndownPanel.update();
} else {
vscode.window.showErrorMessage('You need to initialise Kanbn before viewing the burndown chart.');
}
kanbnStatusBarItem.update();
}));
// If a workspace folder is open, add a status bar item and start watching for file changes

235
package-lock.json generated
View File

@ -1486,6 +1486,32 @@
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
"dev": true
},
"@types/d3-path": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz",
"integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ=="
},
"@types/d3-scale": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.2.2.tgz",
"integrity": "sha512-qpQe8G02tzUwt9sdWX1h8A/W0Q1+N48wMnYXVOkrzeLUkCfvzJYV9Ee3aORCS4dN4ONRLFmMvaXdziQ29XGLjQ==",
"requires": {
"@types/d3-time": "*"
}
},
"@types/d3-shape": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.0.0.tgz",
"integrity": "sha512-NLzD02m5PiD1KLEDjLN+MtqEcFYn4ZL9+Rqc9ZwARK1cpKZXd91zBETbe6wpBB6Ia0D0VZbpmbW3+BsGPGnCpA==",
"requires": {
"@types/d3-path": "^1"
}
},
"@types/d3-time": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.0.0.tgz",
"integrity": "sha512-Abz8bTzy8UWDeYs9pCa3D37i29EWDjNTjemdk0ei1ApYVNqulYlGUKip/jLOpogkPSsPz/GvZCYiC7MFlEk0iQ=="
},
"@types/dateformat": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz",
@ -1578,6 +1604,11 @@
"redux": "^4.0.0"
}
},
"@types/resize-observer-browser": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz",
"integrity": "sha512-8k/67Z95Goa6Lznuykxkfhq9YU3l1Qe6LNZmwde1u7802a3x8v44oq0j91DICclxatTr0rNnhXx7+VTIetSrSQ=="
},
"@types/scheduler": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz",
@ -4018,6 +4049,11 @@
}
}
},
"classnames": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"clean-css": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
@ -4884,6 +4920,11 @@
"source-map": "^0.6.1"
}
},
"css-unit-converter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
},
"css-what": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
@ -5106,6 +5147,73 @@
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
"d3-array": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
"integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
},
"d3-format": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
},
"d3-interpolate": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
"requires": {
"d3-color": "1 - 2"
}
},
"d3-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
"integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
},
"d3-scale": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.4.tgz",
"integrity": "sha512-PG6gtpbPCFqKbvdBEswQcJcTzHC8VEd/XzezF5e68KlkT4/ggELw/nR1tv863jY6ufKTvDlzCMZvhe06codbbA==",
"requires": {
"d3-array": "^2.3.0",
"d3-format": "1 - 2",
"d3-interpolate": "1.2.0 - 2",
"d3-time": "1 - 2",
"d3-time-format": "2 - 3"
}
},
"d3-shape": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz",
"integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==",
"requires": {
"d3-path": "1 - 2"
}
},
"d3-time": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
"integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
"requires": {
"d3-array": "2"
}
},
"d3-time-format": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
"requires": {
"d3-time": "1 - 2"
}
},
"damerau-levenshtein": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
@ -5170,6 +5278,11 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"decimal.js-light": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
},
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
@ -5565,6 +5678,14 @@
"utila": "~0.4"
}
},
"dom-helpers": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
"requires": {
"@babel/runtime": "^7.1.2"
}
},
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
@ -6529,8 +6650,7 @@
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"dev": true
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"events": {
"version": "3.3.0",
@ -6782,6 +6902,11 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-equals": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.1.tgz",
"integrity": "sha512-jIHAbyu5Txdi299DitHXr4wuvw7ajz8S4xVgShJmQOUD6TovsKzvMoHoq9G8+dO6xeKWrwH3DURT+ZDKnwjSsA=="
},
"fast-glob": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
@ -10097,6 +10222,11 @@
"ipaddr.js": "^1.5.2"
}
},
"internmap": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
},
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@ -11849,8 +11979,7 @@
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.memoize": {
"version": "4.1.2",
@ -11889,6 +12018,11 @@
"lodash._reinterpolate": "^3.0.0"
}
},
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@ -13415,8 +13549,7 @@
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"picomatch": {
"version": "2.2.3",
@ -15694,8 +15827,7 @@
"postcss-value-parser": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
},
"postcss-values-parser": {
"version": "2.0.1",
@ -15936,7 +16068,6 @@
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"dev": true,
"requires": {
"performance-now": "^2.1.0"
}
@ -16381,6 +16512,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-redux": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.3.tgz",
@ -16394,6 +16530,17 @@
"react-is": "^16.13.1"
}
},
"react-resize-detector": {
"version": "6.6.5",
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-6.6.5.tgz",
"integrity": "sha512-khKS1IpC2cfx5+6G9HkAU/9CGjDV8woE57pVeH8nP5Ji52yXz6MpQEHEzJZ2obGghWrewN4php8ArxB4yWNqZA==",
"requires": {
"@types/resize-observer-browser": "^0.1.5",
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"resize-observer-polyfill": "^1.5.1"
}
},
"react-scripts": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-2.1.8.tgz",
@ -16457,6 +16604,27 @@
}
}
},
"react-smooth": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.0.tgz",
"integrity": "sha512-wK4dBBR6P21otowgMT9toZk+GngMplGS1O5gk+2WSiHEXIrQgDvhR5IIlT74Vtu//qpTcipkgo21dD7a7AUNxw==",
"requires": {
"fast-equals": "^2.0.0",
"raf": "^3.4.0",
"react-transition-group": "2.9.0"
}
},
"react-transition-group": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
"requires": {
"dom-helpers": "^3.4.0",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@ -16865,6 +17033,41 @@
"util.promisify": "^1.0.0"
}
},
"recharts": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.0.9.tgz",
"integrity": "sha512-JNsXE80PuF3hugUCE7JqDOMSvu5xQLxtjOaqFKKZI2pCJ1PVJzhwDv4TWk0nO4AvADbeWzYEHbg8C5Hcrh42UA==",
"requires": {
"@types/d3-scale": "^3.0.0",
"@types/d3-shape": "^2.0.0",
"classnames": "^2.2.5",
"d3-interpolate": "^2.0.1",
"d3-scale": "^3.2.3",
"d3-shape": "^2.0.0",
"eventemitter3": "^4.0.1",
"lodash": "^4.17.19",
"react-is": "16.10.2",
"react-resize-detector": "^6.6.3",
"react-smooth": "^2.0.0",
"recharts-scale": "^0.4.4",
"reduce-css-calc": "^2.1.8"
},
"dependencies": {
"react-is": {
"version": "16.10.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz",
"integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA=="
}
}
},
"recharts-scale": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
"requires": {
"decimal.js-light": "^2.4.1"
}
},
"recursive-readdir": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
@ -16874,6 +17077,15 @@
"minimatch": "3.0.4"
}
},
"reduce-css-calc": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
"requires": {
"css-unit-converter": "^1.1.1",
"postcss-value-parser": "^3.3.0"
}
},
"redux": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
@ -17173,6 +17385,11 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
},
"resolve": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",

View File

@ -96,6 +96,7 @@
"react": "^16.3.2",
"react-beautiful-dnd": "12.2.0",
"react-dom": "^16.3.2",
"recharts": "^2.0.9",
"terser": "3.14.1",
"uuid": "^8.3.2",
"vscode-codicons": "^0.0.15"

View File

@ -25,7 +25,9 @@ function App() {
const [panelUuid, setPanelUuid] = useState('');
const [showBurndownButton, setShowBurndownButton] = useState(false);
const [showSprintButton, setShowSprintButton] = useState(false);
const [sprints, setSprints] = useState([]);
const [currentSprint, setCurrentSprint] = useState(null);
const [burndownData, setBurndownData] = useState({ series: [] });
window.addEventListener('message', event => {
const tasks = Object.fromEntries(event.data.tasks.map(task => [task.id, task]));
@ -60,6 +62,13 @@ function App() {
setColumnNames(Object.keys(event.data.index.columns));
setPanelUuid(event.data.panelUuid);
break;
case 'burndown':
setName(event.data.index.name);
setTasks(tasks);
setSprints(event.data.index.options.sprints || []);
setBurndownData(event.data.burndownData);
break;
}
setType(event.data.type);
setDateFormat(event.data.dateFormat);
@ -98,6 +107,10 @@ function App() {
{
type === 'burndown' &&
<Burndown
name={name}
tasks={tasks}
sprints={sprints}
burndownData={burndownData}
/>
}
</React.Fragment>

View File

@ -154,11 +154,7 @@ const Board = ({
dateFormat: string,
showBurndownButton: boolean,
showSprintButton: boolean,
currentSprint: {
start: string,
name: string,
description: string
}|null,
currentSprint: KanbnSprint|null,
vscode: VSCodeApi
}) => {
const [, setColumns] = useState(columns);

View File

@ -1,8 +1,40 @@
import React from 'react';
import { LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts';
const Burndown = ({ name, tasks, sprints, burndownData }: {
name: string,
tasks: Record<string, KanbnTask>,
sprints: KanbnSprint[],
burndownData: {
series: Array<{
sprint: KanbnSprint,
from: string,
to: string,
dataPoints: Array<{
x: string,
y: number
}>
}>
}
}) => {
const data = [
{name: 'one', uv: 20},
{name: 'two', uv: 80},
{name: 'three', uv: 45},
{name: 'four', uv: 32}
];
const Burndown = () => {
return (
<div>burndown chart</div>
<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>
</React.Fragment>
);
};

6
src/KanbnSprint.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
// Note that Date properties will be converted to strings (ISO) when a task is serialized and passed as a prop
declare type KanbnSprint = {
start: string;
name: string;
description?: string;
};