diff --git a/ext-src/KanbnBoardPanel.ts b/ext-src/KanbnBoardPanel.ts
index c7302f7..9dbe12b 100644
--- a/ext-src/KanbnBoardPanel.ts
+++ b/ext-src/KanbnBoardPanel.ts
@@ -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
diff --git a/ext-src/KanbnBurndownPanel.ts b/ext-src/KanbnBurndownPanel.ts
index 291b68c..72c883f 100644
--- a/ext-src/KanbnBurndownPanel.ts
+++ b/ext-src/KanbnBurndownPanel.ts
@@ -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 {
-
+
You need to enable JavaScript to run this app.
diff --git a/ext-src/extension.ts b/ext-src/extension.ts
index dc40884..1618854 100644
--- a/ext-src/extension.ts
+++ b/ext-src/extension.ts
@@ -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
diff --git a/package-lock.json b/package-lock.json
index 800071d..f4646bc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index aac1868..491d2c2 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/src/App.tsx b/src/App.tsx
index 7709526..7143b9a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -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' &&
}
diff --git a/src/Board.tsx b/src/Board.tsx
index e45e565..b918b29 100644
--- a/src/Board.tsx
+++ b/src/Board.tsx
@@ -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);
diff --git a/src/Burndown.tsx b/src/Burndown.tsx
index 0f98159..8bdf6c2 100644
--- a/src/Burndown.tsx
+++ b/src/Burndown.tsx
@@ -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,
+ 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 (
- burndown chart
+
+ burndown chart
+
+
+
+
+
+
+
+
);
};
diff --git a/src/KanbnSprint.d.ts b/src/KanbnSprint.d.ts
new file mode 100644
index 0000000..19f9ccd
--- /dev/null
+++ b/src/KanbnSprint.d.ts
@@ -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;
+};