* First release with the following changes
This commit is contained in:
Mike Phares 2023-05-25 13:09:54 -06:00
parent f85619450f
commit c0930f4780
24 changed files with 32430 additions and 198 deletions

29
.kanbn/index.md Normal file
View File

@ -0,0 +1,29 @@
---
startedColumns:
- 'In Progress'
completedColumns:
- Done
---
# VSCode-Kanbn
## Backlog
- [review-save-options](tasks/review-save-options.md)
- [review-adding-more-on-item-card](tasks/review-adding-more-on-item-card.md)
- [can-this-run-in-the-browser](tasks/can-this-run-in-the-browser.md)
## Todo
- [shrink-app-size](tasks/shrink-app-size.md)
## In Progress
- [fix-relations-bug](tasks/fix-relations-bug.md)
## Done
- [add-link-to-raw-in-panel-view](tasks/add-link-to-raw-in-panel-view.md)
- [add-raw-button-in-create-new-task](tasks/add-raw-button-in-create-new-task.md)
- [make-tags-linkable](tasks/make-tags-linkable.md)
- [show-relations-on-the-item-card](tasks/show-relations-on-the-item-card.md)

View File

@ -0,0 +1,14 @@
---
created: 2023-05-25T04:00:46.616Z
updated: 2023-05-25T04:50:52.235Z
assigned: ""
progress: 0
tags: []
started: 2023-05-25T04:41:03.902Z
completed: 2023-05-25T04:50:44.587Z
---
# Add link to raw in panel view
- Double click event
- Extra button

View File

@ -0,0 +1,11 @@
---
created: 2023-05-25T04:00:30.417Z
updated: 2023-05-25T04:50:46.136Z
assigned: ""
progress: 0
tags: []
started: 2023-05-22T00:00:00.000Z
completed: 2023-05-25T04:50:46.136Z
---
# Add raw button in Create new task

View File

@ -0,0 +1,9 @@
---
created: 2023-05-25T04:04:06.760Z
updated: 2023-05-25T04:04:06.753Z
assigned: ""
progress: 0
tags: []
---
# Can this run in the browser?

View File

@ -0,0 +1,19 @@
---
created: 2023-05-25T18:54:00.309Z
updated: 2023-05-25T18:55:32.671Z
assigned: ""
progress: 0
tags: []
started: 2023-05-25T18:55:32.671Z
---
# Fix relations bug
I started to look at th kanbn project all in javascript but I don't know how to reference it
## Comments
- date: 2023-05-25T18:54:44.808Z
```bash
node bin\kanbn add -n Mike
```

View File

@ -0,0 +1,9 @@
---
created: 2023-05-25T04:05:13.848Z
updated: 2023-05-25T04:05:33.759Z
assigned: ""
progress: 0
column: Backlog
---
# Make tags linkable

View File

@ -0,0 +1,13 @@
---
created: 2023-05-25T04:01:15.185Z
updated: 2023-05-25T04:02:20.638Z
assigned: ""
progress: 0
tags:
- Maybe
---
# Review adding more on item card
- Maybe not needed because that is what tags are meant for
- Buy maybe so because I don't like tags in the metadata

View File

@ -0,0 +1,9 @@
---
created: 2023-05-25T04:01:05.154Z
updated: 2023-05-25T04:01:05.146Z
assigned: ""
progress: 0
tags: []
---
# Review save options

View File

@ -0,0 +1,15 @@
---
created: 2023-05-25T04:59:37.306Z
updated: 2023-05-25T18:52:55.747Z
assigned: ""
progress: 0
tags: []
started: 2023-05-24T00:00:00.000Z
completed: 2023-05-25T18:52:55.747Z
---
# Show relations on the item card
## Sub-tasks
- [ ] make clickable

View File

@ -0,0 +1,9 @@
---
created: 2023-05-25T04:03:54.530Z
updated: 2023-05-25T18:55:36.452Z
assigned: ""
progress: 0
tags: []
---
# Shrink app size

View File

@ -8,5 +8,6 @@
}, },
"typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version
"typescript.tsc.autoDetect": "off", "typescript.tsc.autoDetect": "off",
"todo-tree.tree.scanMode": "workspace only" // Turn off tsc task auto detection since we have the necessary task as npm scripts "todo-tree.tree.scanMode": "workspace only",
"cSpell.enabled": false // Turn off tsc task auto detection since we have the necessary task as npm scripts
} }

View File

@ -1,3 +1,15 @@
# 0.13.0
* See board ...
# 0.12.0
* First release with the following changes
- [add-link-to-raw-in-panel-view](.kanbn/tasks/add-link-to-raw-in-panel-view.md)
- [add-raw-button-in-create-new-task](.kanbn/tasks/add-raw-button-in-create-new-task.md)
- [make-tags-linkable](.kanbn/tasks/make-tags-linkable.md)
- [show-relations-on-the-item-card](.kanbn/tasks/show-relations-on-the-item-card.md)
# 0.11.0 # 0.11.0
* KaTeX support in task markdown (description and comments) using `$$...$$` for blocks and `$...$` for inline * KaTeX support in task markdown (description and comments) using `$$...$$` for blocks and `$...$` for inline

View File

@ -1,7 +1,5 @@
# Kanbn Extension for Visual Studio Code # Kanbn Extension for Visual Studio Code
![Marketplace version](https://vsmarketplacebadge.apphb.com/version-short/gordonlarrigan.vscode-kanbn.svg?color=lightblue) ![Marketplace installs](https://vsmarketplacebadge.apphb.com/installs-short/gordonlarrigan.vscode-kanbn.svg?color=lightblue) ![Marketplace rating](https://vsmarketplacebadge.apphb.com/rating-short/gordonlarrigan.vscode-kanbn.svg?color=lightblue) [![MIT License](https://img.shields.io/github/license/basementuniverse/vscode-kanbn?color=orange)](https://opensource.org/licenses/MIT)
This extension adds a [Kanbn](https://www.npmjs.com/package/@basementuniverse/kanbn)-powered kanban board to Visual Studio Code. This extension adds a [Kanbn](https://www.npmjs.com/package/@basementuniverse/kanbn)-powered kanban board to Visual Studio Code.
![Kanbn](docs/preview.gif "Kanbn") ![Kanbn](docs/preview.gif "Kanbn")

View File

@ -1,5 +1,5 @@
import * as path from "path"; import { join } from "path";
import * as vscode from "vscode"; import { WebviewPanel, Disposable, window, ViewColumn, workspace, Uri, commands } from "vscode";
import getNonce from "./getNonce"; import getNonce from "./getNonce";
import KanbnTaskPanel from "./KanbnTaskPanel"; import KanbnTaskPanel from "./KanbnTaskPanel";
import KanbnBurndownPanel from "./KanbnBurndownPanel"; import KanbnBurndownPanel from "./KanbnBurndownPanel";
@ -24,12 +24,12 @@ export default class KanbnBoardPanel {
private static readonly viewType = "react"; private static readonly viewType = "react";
private readonly _panel: vscode.WebviewPanel; private readonly _panel: WebviewPanel;
private readonly _extensionPath: string; private readonly _extensionPath: string;
private readonly _workspacePath: string; private readonly _workspacePath: string;
private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main"); private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main");
private readonly _kanbnFolderName: string; private readonly _kanbnFolderName: string;
private _disposables: vscode.Disposable[] = []; private _disposables: Disposable[] = [];
public static createOrShow( public static createOrShow(
extensionPath: string, extensionPath: string,
@ -37,7 +37,7 @@ export default class KanbnBoardPanel {
kanbn: typeof import("@basementuniverse/kanbn/src/main"), kanbn: typeof import("@basementuniverse/kanbn/src/main"),
kanbnFolderName: string kanbnFolderName: string
) { ) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; const column = window.activeTextEditor ? window.activeTextEditor.viewColumn : undefined;
// If we already have a panel, show it, otherwise create a new panel // If we already have a panel, show it, otherwise create a new panel
if (KanbnBoardPanel.currentPanel) { if (KanbnBoardPanel.currentPanel) {
@ -46,7 +46,7 @@ export default class KanbnBoardPanel {
KanbnBoardPanel.currentPanel = new KanbnBoardPanel( KanbnBoardPanel.currentPanel = new KanbnBoardPanel(
extensionPath, extensionPath,
workspacePath, workspacePath,
column || vscode.ViewColumn.One, column || ViewColumn.One,
kanbn, kanbn,
kanbnFolderName kanbnFolderName
); );
@ -59,7 +59,7 @@ export default class KanbnBoardPanel {
try { try {
index = await KanbnBoardPanel.currentPanel._kanbn.getIndex(); index = await KanbnBoardPanel.currentPanel._kanbn.getIndex();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error); window.showErrorMessage(error instanceof Error ? error.message : error);
return; return;
} }
let tasks: any[]; let tasks: any[];
@ -68,7 +68,7 @@ export default class KanbnBoardPanel {
KanbnBoardPanel.currentPanel!._kanbn.hydrateTask(index, task) KanbnBoardPanel.currentPanel!._kanbn.hydrateTask(index, task)
); );
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error); window.showErrorMessage(error instanceof Error ? error.message : error);
return; return;
} }
KanbnBoardPanel.currentPanel._panel.webview.postMessage({ KanbnBoardPanel.currentPanel._panel.webview.postMessage({
@ -81,8 +81,8 @@ export default class KanbnBoardPanel {
columnSorting: index.options.columnSorting ?? {}, columnSorting: index.options.columnSorting ?? {},
customFields: index.options.customFields ?? [], customFields: index.options.customFields ?? [],
dateFormat: KanbnBoardPanel.currentPanel._kanbn.getDateFormat(index), dateFormat: KanbnBoardPanel.currentPanel._kanbn.getDateFormat(index),
showBurndownButton: vscode.workspace.getConfiguration("kanbn").get("showBurndownButton"), showBurndownButton: workspace.getConfiguration("kanbn").get("showBurndownButton"),
showSprintButton: vscode.workspace.getConfiguration("kanbn").get("showSprintButton"), showSprintButton: workspace.getConfiguration("kanbn").get("showSprintButton"),
}); });
} }
} }
@ -90,7 +90,7 @@ export default class KanbnBoardPanel {
private constructor( private constructor(
extensionPath: string, extensionPath: string,
workspacePath: string, workspacePath: string,
column: vscode.ViewColumn, column: ViewColumn,
kanbn: typeof import("@basementuniverse/kanbn/src/main"), kanbn: typeof import("@basementuniverse/kanbn/src/main"),
kanbnFolderName: string kanbnFolderName: string
) { ) {
@ -100,7 +100,7 @@ export default class KanbnBoardPanel {
this._kanbnFolderName = kanbnFolderName; this._kanbnFolderName = kanbnFolderName;
// Create and show a new webview panel // Create and show a new webview panel
this._panel = vscode.window.createWebviewPanel(KanbnBoardPanel.viewType, "Kanbn Board", column, { this._panel = window.createWebviewPanel(KanbnBoardPanel.viewType, "Kanbn Board", column, {
// Enable javascript in the webview // Enable javascript in the webview
enableScripts: true, enableScripts: true,
@ -109,14 +109,14 @@ export default class KanbnBoardPanel {
// Restrict the webview to only loading content from allowed paths // Restrict the webview to only loading content from allowed paths
localResourceRoots: [ localResourceRoots: [
vscode.Uri.file(path.join(this._extensionPath, "build")), Uri.file(join(this._extensionPath, "build")),
vscode.Uri.file(path.join(this._workspacePath, this._kanbnFolderName)), Uri.file(join(this._workspacePath, this._kanbnFolderName)),
vscode.Uri.file(path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist")), Uri.file(join(this._extensionPath, "node_modules", "vscode-codicons", "dist")),
], ],
}); });
(this._panel as any).iconPath = { (this._panel as any).iconPath = {
light: vscode.Uri.file(path.join(this._extensionPath, "resources", "project_light.svg")), light: Uri.file(join(this._extensionPath, "resources", "project_light.svg")),
dark: vscode.Uri.file(path.join(this._extensionPath, "resources", "project_dark.svg")), dark: Uri.file(join(this._extensionPath, "resources", "project_dark.svg")),
}; };
// Set the webview's title to the kanbn project name // Set the webview's title to the kanbn project name
@ -138,7 +138,7 @@ export default class KanbnBoardPanel {
// Display error message // Display error message
case "error": case "error":
vscode.window.showErrorMessage(message.text); window.showErrorMessage(message.text);
return; return;
// Open a task in the editor // Open a task in the editor
@ -153,12 +153,18 @@ export default class KanbnBoardPanel {
); );
return; return;
// Go to raw task in the editor
case "kanbn.goToRaw":
let uri = Uri.file(join(this._workspacePath, ".kanbn", "tasks", message.taskId + ".md"));
await commands.executeCommand('vscode.open', uri);
return;
// Move a task // Move a task
case "kanbn.move": case "kanbn.move":
try { try {
await kanbn.moveTask(message.task, message.columnName, message.position); await kanbn.moveTask(message.task, message.columnName, message.position);
} catch (e) { } catch (e) {
vscode.window.showErrorMessage(e.message); window.showErrorMessage(e.message);
} }
return; return;
@ -185,7 +191,7 @@ export default class KanbnBoardPanel {
); );
} }
// Prompt for a task property to sort by // Prompt for a task property to sort by
const sortBy: string = await vscode.window.showQuickPick( const sortBy = await window.showQuickPick(
[ [
'None', 'None',
...Object.keys(sortByFields), ...Object.keys(sortByFields),
@ -204,7 +210,7 @@ export default class KanbnBoardPanel {
} }
// Prompt for sort direction and save settings // Prompt for sort direction and save settings
const sortDirection = await vscode.window.showQuickPick( const sortDirection = await window.showQuickPick(
[ [
'Ascending', 'Ascending',
'Descending', 'Descending',
@ -215,7 +221,7 @@ export default class KanbnBoardPanel {
} }
); );
if (sortDirection !== undefined) { if (sortDirection !== undefined) {
const saveSort = await vscode.window.showQuickPick( const saveSort = await window.showQuickPick(
[ [
"Yes", "Yes",
"No", "No",
@ -256,7 +262,7 @@ export default class KanbnBoardPanel {
// Start a new sprint // Start a new sprint
case "kanbn.sprint": case "kanbn.sprint":
// Prompt for a sprint name // Prompt for a sprint name
const newSprintName = await vscode.window.showInputBox({ const newSprintName = await window.showInputBox({
placeHolder: "The sprint name.", placeHolder: "The sprint name.",
}); });
@ -265,7 +271,7 @@ export default class KanbnBoardPanel {
try { try {
await kanbn.sprint(newSprintName, "", new Date()); await kanbn.sprint(newSprintName, "", new Date());
} catch (e) { } catch (e) {
vscode.window.showErrorMessage(e.message); window.showErrorMessage(e.message);
} }
} }
KanbnBurndownPanel.update(); KanbnBurndownPanel.update();
@ -291,20 +297,20 @@ export default class KanbnBoardPanel {
} }
private _getHtmlForWebview() { private _getHtmlForWebview() {
const manifest = require(path.join(this._extensionPath, "build", "asset-manifest.json")); const manifest = require(join(this._extensionPath, "build", "asset-manifest.json"));
const mainScript = manifest["main.js"]; const mainScript = manifest["main.js"];
const mainStyle = manifest["main.css"]; const mainStyle = manifest["main.css"];
const scriptUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainScript)).with({ const scriptUri = Uri.file(join(this._extensionPath, "build", mainScript)).with({
scheme: "vscode-resource", scheme: "vscode-resource",
}); });
const styleUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainStyle)).with({ const styleUri = Uri.file(join(this._extensionPath, "build", mainStyle)).with({
scheme: "vscode-resource", scheme: "vscode-resource",
}); });
const customStyleUri = vscode.Uri.file( const customStyleUri = Uri.file(
path.join(this._workspacePath, this._kanbnFolderName, "board.css") join(this._workspacePath, this._kanbnFolderName, "board.css")
).with({ scheme: "vscode-resource" }); ).with({ scheme: "vscode-resource" });
const codiconsUri = vscode.Uri.file( const codiconsUri = Uri.file(
path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css") join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css")
).with({ scheme: "vscode-resource" }); ).with({ scheme: "vscode-resource" });
// Use a nonce to whitelist which scripts can be run // Use a nonce to whitelist which scripts can be run
@ -321,7 +327,7 @@ export default class KanbnBoardPanel {
<link rel="stylesheet" type="text/css" href="${customStyleUri}"> <link rel="stylesheet" type="text/css" href="${customStyleUri}">
<link rel="stylesheet" type="text/css" href="${codiconsUri}"> <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:;"> <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="${Uri.file(join(this._extensionPath, "build")).with({ scheme: "vscode-resource" })}/">
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,5 +1,5 @@
import * as path from "path"; import { join } from "path";
import * as vscode from "vscode"; import { WebviewPanel, Disposable, window, ViewColumn, Uri } from "vscode";
import getNonce from "./getNonce"; import getNonce from "./getNonce";
export default class KanbnBurndownPanel { export default class KanbnBurndownPanel {
@ -7,7 +7,7 @@ export default class KanbnBurndownPanel {
private static readonly viewType = "react"; private static readonly viewType = "react";
private readonly _panel: vscode.WebviewPanel; private readonly _panel: WebviewPanel;
private readonly _extensionPath: string; private readonly _extensionPath: string;
private readonly _workspacePath: string; private readonly _workspacePath: string;
private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main"); private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main");
@ -16,7 +16,7 @@ export default class KanbnBurndownPanel {
private sprint: string = ''; private sprint: string = '';
private startDate: string = ''; private startDate: string = '';
private endDate: string = ''; private endDate: string = '';
private _disposables: vscode.Disposable[] = []; private _disposables: Disposable[] = [];
public static async createOrShow( public static async createOrShow(
extensionPath: string, extensionPath: string,
@ -24,7 +24,7 @@ export default class KanbnBurndownPanel {
kanbn: typeof import("@basementuniverse/kanbn/src/main"), kanbn: typeof import("@basementuniverse/kanbn/src/main"),
kanbnFolderName: string kanbnFolderName: string
) { ) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; const column = window.activeTextEditor ? window.activeTextEditor.viewColumn : undefined;
// If we already have a panel, show it, otherwise create a new panel // If we already have a panel, show it, otherwise create a new panel
if (KanbnBurndownPanel.currentPanel) { if (KanbnBurndownPanel.currentPanel) {
@ -33,7 +33,7 @@ export default class KanbnBurndownPanel {
KanbnBurndownPanel.currentPanel = new KanbnBurndownPanel( KanbnBurndownPanel.currentPanel = new KanbnBurndownPanel(
extensionPath, extensionPath,
workspacePath, workspacePath,
column || vscode.ViewColumn.One, column || ViewColumn.One,
kanbn, kanbn,
kanbnFolderName kanbnFolderName
); );
@ -46,7 +46,7 @@ export default class KanbnBurndownPanel {
try { try {
index = await KanbnBurndownPanel.currentPanel._kanbn.getIndex(); index = await KanbnBurndownPanel.currentPanel._kanbn.getIndex();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error); window.showErrorMessage(error instanceof Error ? error.message : error);
return; return;
} }
KanbnBurndownPanel.currentPanel._panel.webview.postMessage({ KanbnBurndownPanel.currentPanel._panel.webview.postMessage({
@ -78,7 +78,7 @@ export default class KanbnBurndownPanel {
private constructor( private constructor(
extensionPath: string, extensionPath: string,
workspacePath: string, workspacePath: string,
column: vscode.ViewColumn, column: ViewColumn,
kanbn: typeof import("@basementuniverse/kanbn/src/main"), kanbn: typeof import("@basementuniverse/kanbn/src/main"),
kanbnFolderName: string kanbnFolderName: string
) { ) {
@ -88,7 +88,7 @@ export default class KanbnBurndownPanel {
this._kanbnFolderName = kanbnFolderName; this._kanbnFolderName = kanbnFolderName;
// Create and show a new webview panel // Create and show a new webview panel
this._panel = vscode.window.createWebviewPanel(KanbnBurndownPanel.viewType, "Burndown Chart", column, { this._panel = window.createWebviewPanel(KanbnBurndownPanel.viewType, "Burndown Chart", column, {
// Enable javascript in the webview // Enable javascript in the webview
enableScripts: true, enableScripts: true,
@ -97,14 +97,14 @@ export default class KanbnBurndownPanel {
// Restrict the webview to only loading content from allowed paths // Restrict the webview to only loading content from allowed paths
localResourceRoots: [ localResourceRoots: [
vscode.Uri.file(path.join(this._extensionPath, "build")), Uri.file(join(this._extensionPath, "build")),
vscode.Uri.file(path.join(this._workspacePath, this._kanbnFolderName)), Uri.file(join(this._workspacePath, this._kanbnFolderName)),
vscode.Uri.file(path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist")), Uri.file(join(this._extensionPath, "node_modules", "vscode-codicons", "dist")),
], ],
}); });
(this._panel as any).iconPath = { (this._panel as any).iconPath = {
light: vscode.Uri.file(path.join(this._extensionPath, "resources", "burndown_light.svg")), light: Uri.file(join(this._extensionPath, "resources", "burndown_light.svg")),
dark: vscode.Uri.file(path.join(this._extensionPath, "resources", "burndown_dark.svg")), dark: Uri.file(join(this._extensionPath, "resources", "burndown_dark.svg")),
}; };
// Set the webview's title to the kanbn project name // Set the webview's title to the kanbn project name
@ -126,7 +126,7 @@ export default class KanbnBurndownPanel {
// Display error message // Display error message
case "error": case "error":
vscode.window.showErrorMessage(message.text); window.showErrorMessage(message.text);
return; return;
// Refresh the kanbn chart // Refresh the kanbn chart
@ -158,20 +158,20 @@ export default class KanbnBurndownPanel {
} }
private _getHtmlForWebview() { private _getHtmlForWebview() {
const manifest = require(path.join(this._extensionPath, "build", "asset-manifest.json")); const manifest = require(join(this._extensionPath, "build", "asset-manifest.json"));
const mainScript = manifest["main.js"]; const mainScript = manifest["main.js"];
const mainStyle = manifest["main.css"]; const mainStyle = manifest["main.css"];
const scriptUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainScript)).with({ const scriptUri = Uri.file(join(this._extensionPath, "build", mainScript)).with({
scheme: "vscode-resource", scheme: "vscode-resource",
}); });
const styleUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainStyle)).with({ const styleUri = Uri.file(join(this._extensionPath, "build", mainStyle)).with({
scheme: "vscode-resource", scheme: "vscode-resource",
}); });
const customStyleUri = vscode.Uri.file( const customStyleUri = Uri.file(
path.join(this._workspacePath, this._kanbnFolderName, "board.css") join(this._workspacePath, this._kanbnFolderName, "board.css")
).with({ scheme: "vscode-resource" }); ).with({ scheme: "vscode-resource" });
const codiconsUri = vscode.Uri.file( const codiconsUri = Uri.file(
path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css") join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css")
).with({ scheme: "vscode-resource" }); ).with({ scheme: "vscode-resource" });
// Use a nonce to whitelist which scripts can be run // Use a nonce to whitelist which scripts can be run
@ -188,7 +188,7 @@ export default class KanbnBurndownPanel {
<link rel="stylesheet" type="text/css" href="${customStyleUri}"> <link rel="stylesheet" type="text/css" href="${customStyleUri}">
<link rel="stylesheet" type="text/css" href="${codiconsUri}"> <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:;"> <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="${Uri.file(join(this._extensionPath, "build")).with({ scheme: "vscode-resource" })}/">
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,15 +1,15 @@
import { status } from '@basementuniverse/kanbn/src/main'; import { status } from '@basementuniverse/kanbn/src/main';
import * as vscode from 'vscode'; import { StatusBarItem, ExtensionContext, window, StatusBarAlignment, workspace } from 'vscode';
export default class KanbnStatusBarItem { export default class KanbnStatusBarItem {
private readonly _statusBarItem: vscode.StatusBarItem; private readonly _statusBarItem: StatusBarItem;
private readonly _kanbn: typeof import('@basementuniverse/kanbn/src/main'); private readonly _kanbn: typeof import('@basementuniverse/kanbn/src/main');
constructor( constructor(
context: vscode.ExtensionContext, context: ExtensionContext,
kanbn: typeof import('@basementuniverse/kanbn/src/main') kanbn: typeof import('@basementuniverse/kanbn/src/main')
) { ) {
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0); this._statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left, 0);
context.subscriptions.push(this._statusBarItem); context.subscriptions.push(this._statusBarItem);
this._kanbn = kanbn; this._kanbn = kanbn;
} }
@ -28,7 +28,7 @@ export default class KanbnStatusBarItem {
const text = [ const text = [
`$(project) ${status.tasks}` `$(project) ${status.tasks}`
]; ];
let tooltip = []; let tooltip: any = [];
if (status.tasks > 0) { if (status.tasks > 0) {
tooltip = [ tooltip = [
`${status.tasks} task${status.tasks === 1 ? '' : 's'}` `${status.tasks} task${status.tasks === 1 ? '' : 's'}`
@ -52,7 +52,7 @@ export default class KanbnStatusBarItem {
this._statusBarItem.text = '$(project)'; this._statusBarItem.text = '$(project)';
this._statusBarItem.tooltip = 'Initialise Kanbn'; this._statusBarItem.tooltip = 'Initialise Kanbn';
this._statusBarItem.command = 'kanbn.init'; this._statusBarItem.command = 'kanbn.init';
if (vscode.workspace.getConfiguration('kanbn').get('showUninitialisedStatusBarItem')) { if (workspace.getConfiguration('kanbn').get('showUninitialisedStatusBarItem')) {
this._statusBarItem.show(); this._statusBarItem.show();
} else { } else {
this._statusBarItem.hide(); this._statusBarItem.hide();

View File

@ -1,11 +1,11 @@
import * as path from "path"; import { join } from "path";
import * as vscode from "vscode"; import { WebviewPanel, Disposable, window, ViewColumn, Uri, workspace, commands } from "vscode";
import getNonce from "./getNonce"; import getNonce from "./getNonce";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
function transformTaskData( function transformTaskData(
taskData: any, taskData: any,
customFields: { name: string, type: 'boolean' | 'date' | 'number' | 'string'}[] customFields: { name: string, type: 'boolean' | 'date' | 'number' | 'string' }[]
) { ) {
const result = { const result = {
id: taskData.id, id: taskData.id,
@ -71,7 +71,7 @@ export default class KanbnTaskPanel {
private static readonly viewType = "react"; private static readonly viewType = "react";
private static panels: Record<string, KanbnTaskPanel> = {}; private static panels: Record<string, KanbnTaskPanel> = {};
private readonly _panel: vscode.WebviewPanel; private readonly _panel: WebviewPanel;
private readonly _extensionPath: string; private readonly _extensionPath: string;
private readonly _workspacePath: string; private readonly _workspacePath: string;
private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main"); private readonly _kanbn: typeof import("@basementuniverse/kanbn/src/main");
@ -79,7 +79,7 @@ export default class KanbnTaskPanel {
private readonly _panelUuid: string; private readonly _panelUuid: string;
private _taskId: string | null; private _taskId: string | null;
private _columnName: string | null; private _columnName: string | null;
private _disposables: vscode.Disposable[] = []; private _disposables: Disposable[] = [];
public static async show( public static async show(
extensionPath: string, extensionPath: string,
@ -89,14 +89,14 @@ export default class KanbnTaskPanel {
taskId: string | null, taskId: string | null,
columnName: string | null columnName: string | null
) { ) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; const column = window.activeTextEditor ? window.activeTextEditor.viewColumn : undefined;
// Create a new panel // Create a new panel
const panelUuid = uuidv4(); const panelUuid = uuidv4();
const taskPanel = new KanbnTaskPanel( const taskPanel = new KanbnTaskPanel(
extensionPath, extensionPath,
workspacePath, workspacePath,
column || vscode.ViewColumn.One, column || ViewColumn.One,
kanbn, kanbn,
kanbnFolderName, kanbnFolderName,
taskId, taskId,
@ -110,7 +110,7 @@ export default class KanbnTaskPanel {
private constructor( private constructor(
extensionPath: string, extensionPath: string,
workspacePath: string, workspacePath: string,
column: vscode.ViewColumn, column: ViewColumn,
kanbn: typeof import("@basementuniverse/kanbn/src/main"), kanbn: typeof import("@basementuniverse/kanbn/src/main"),
kanbnFolderName: string, kanbnFolderName: string,
taskId: string | null, taskId: string | null,
@ -126,7 +126,7 @@ export default class KanbnTaskPanel {
this._panelUuid = panelUuid; this._panelUuid = panelUuid;
// Create and show a new webview panel // Create and show a new webview panel
this._panel = vscode.window.createWebviewPanel(KanbnTaskPanel.viewType, "New task", column, { this._panel = window.createWebviewPanel(KanbnTaskPanel.viewType, "New task", column, {
// Enable javascript in the webview // Enable javascript in the webview
enableScripts: true, enableScripts: true,
@ -135,14 +135,14 @@ export default class KanbnTaskPanel {
// Restrict the webview to only loading content from allowed paths // Restrict the webview to only loading content from allowed paths
localResourceRoots: [ localResourceRoots: [
vscode.Uri.file(path.join(this._extensionPath, "build")), Uri.file(join(this._extensionPath, "build")),
vscode.Uri.file(path.join(this._workspacePath, this._kanbnFolderName)), Uri.file(join(this._workspacePath, this._kanbnFolderName)),
vscode.Uri.file(path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist")), Uri.file(join(this._extensionPath, "node_modules", "vscode-codicons", "dist")),
], ],
}); });
(this._panel as any).iconPath = { (this._panel as any).iconPath = {
light: vscode.Uri.file(path.join(this._extensionPath, "resources", "task_light.svg")), light: Uri.file(join(this._extensionPath, "resources", "task_light.svg")),
dark: vscode.Uri.file(path.join(this._extensionPath, "resources", "task_dark.svg")), dark: Uri.file(join(this._extensionPath, "resources", "task_dark.svg")),
}; };
// Set the webview's title to the kanbn task name // Set the webview's title to the kanbn task name
@ -166,7 +166,7 @@ export default class KanbnTaskPanel {
// Display error message // Display error message
case "error": case "error":
vscode.window.showErrorMessage(message.text); window.showErrorMessage(message.text);
return; return;
// Update the task webview panel title // Update the task webview panel title
@ -183,8 +183,8 @@ export default class KanbnTaskPanel {
KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id; KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id;
KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column; KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column;
KanbnTaskPanel.panels[message.panelUuid].update(); KanbnTaskPanel.panels[message.panelUuid].update();
if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { if (workspace.getConfiguration("kanbn").get("showTaskNotifications")) {
vscode.window.showInformationMessage(`Created task '${message.taskData.name}'.`); window.showInformationMessage(`Created task '${message.taskData.name}'.`);
} }
return; return;
@ -198,34 +198,42 @@ export default class KanbnTaskPanel {
KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id; KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id;
KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column; KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column;
KanbnTaskPanel.panels[message.panelUuid].update(); KanbnTaskPanel.panels[message.panelUuid].update();
if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { if (workspace.getConfiguration("kanbn").get("showTaskNotifications")) {
vscode.window.showInformationMessage(`Updated task '${message.taskData.name}'.`); window.showInformationMessage(`Updated task '${message.taskData.name}'.`);
} }
return; return;
// Delete a task and close the webview panel // Delete a task and close the webview panel
case "kanbn.delete": case "kanbn.delete":
vscode.window window
.showInformationMessage(`Delete task '${message.taskData.name}'?`, "Yes", "No") .showInformationMessage(`Delete task '${message.taskData.name}'?`, "Yes", "No")
.then(async (value) => { .then(async (value) => {
if (value === "Yes") { if (value === "Yes") {
await this._kanbn.deleteTask(message.taskId, true); await this._kanbn.deleteTask(message.taskId, true);
KanbnTaskPanel.panels[message.panelUuid].dispose(); KanbnTaskPanel.panels[message.panelUuid].dispose();
delete KanbnTaskPanel.panels[message.panelUuid]; delete KanbnTaskPanel.panels[message.panelUuid];
if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { if (workspace.getConfiguration("kanbn").get("showTaskNotifications")) {
vscode.window.showInformationMessage(`Deleted task '${message.taskData.name}'.`); window.showInformationMessage(`Deleted task '${message.taskData.name}'.`);
} }
} }
}); });
return; return;
// Go to raw task and close the webview panel
case "kanbn.goToRaw":
KanbnTaskPanel.panels[message.panelUuid].dispose();
delete KanbnTaskPanel.panels[message.panelUuid];
let uri = Uri.file(join(this._workspacePath, ".kanbn", "tasks", message.taskId + ".md"));
await commands.executeCommand('vscode.open', uri);
return;
// Archive a task and close the webview panel // Archive a task and close the webview panel
case 'kanbn.archive': case 'kanbn.archive':
await this._kanbn.archiveTask(message.taskId); await this._kanbn.archiveTask(message.taskId);
KanbnTaskPanel.panels[message.panelUuid].dispose(); KanbnTaskPanel.panels[message.panelUuid].dispose();
delete KanbnTaskPanel.panels[message.panelUuid]; delete KanbnTaskPanel.panels[message.panelUuid];
if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { if (workspace.getConfiguration("kanbn").get("showTaskNotifications")) {
vscode.window.showInformationMessage(`Archived task '${message.taskData.name}'.`); window.showInformationMessage(`Archived task '${message.taskData.name}'.`);
} }
return; return;
} }
@ -250,7 +258,7 @@ export default class KanbnTaskPanel {
try { try {
index = await this._kanbn.getIndex(); index = await this._kanbn.getIndex();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error); window.showErrorMessage(error instanceof Error ? error.message : error);
return; return;
} }
let tasks: any[]; let tasks: any[];
@ -260,7 +268,7 @@ export default class KanbnTaskPanel {
...this._kanbn.hydrateTask(index, task), ...this._kanbn.hydrateTask(index, task),
})); }));
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(error instanceof Error ? error.message : error); window.showErrorMessage(error instanceof Error ? error.message : error);
return; return;
} }
let task = null; let task = null;
@ -287,20 +295,20 @@ export default class KanbnTaskPanel {
} }
private _getHtmlForWebview() { private _getHtmlForWebview() {
const manifest = require(path.join(this._extensionPath, "build", "asset-manifest.json")); const manifest = require(join(this._extensionPath, "build", "asset-manifest.json"));
const mainScript = manifest["main.js"]; const mainScript = manifest["main.js"];
const mainStyle = manifest["main.css"]; const mainStyle = manifest["main.css"];
const scriptUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainScript)).with({ const scriptUri = Uri.file(join(this._extensionPath, "build", mainScript)).with({
scheme: "vscode-resource", scheme: "vscode-resource",
}); });
const styleUri = vscode.Uri.file(path.join(this._extensionPath, "build", mainStyle)).with({ const styleUri = Uri.file(join(this._extensionPath, "build", mainStyle)).with({
scheme: "vscode-resource", scheme: "vscode-resource",
}); });
const customStyleUri = vscode.Uri.file( const customStyleUri = Uri.file(
path.join(this._workspacePath, this._kanbnFolderName, "board.css") join(this._workspacePath, this._kanbnFolderName, "board.css")
).with({ scheme: "vscode-resource" }); ).with({ scheme: "vscode-resource" });
const codiconsUri = vscode.Uri.file( const codiconsUri = Uri.file(
path.join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css") join(this._extensionPath, "node_modules", "vscode-codicons", "dist", "codicon.css")
).with({ scheme: "vscode-resource" }); ).with({ scheme: "vscode-resource" });
// Use a nonce to whitelist which scripts can be run // Use a nonce to whitelist which scripts can be run
@ -317,7 +325,7 @@ export default class KanbnTaskPanel {
<link rel="stylesheet" type="text/css" href="${customStyleUri}"> <link rel="stylesheet" type="text/css" href="${customStyleUri}">
<link rel="stylesheet" type="text/css" href="${codiconsUri}"> <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:;"> <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="${Uri.file(join(this._extensionPath, "build")).with({ scheme: "vscode-resource" })}/">
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,4 +1,4 @@
import * as vscode from "vscode"; import { ExtensionContext, commands, workspace, window, RelativePattern } from "vscode";
import KanbnStatusBarItem from "./KanbnStatusBarItem"; import KanbnStatusBarItem from "./KanbnStatusBarItem";
import KanbnBoardPanel from "./KanbnBoardPanel"; import KanbnBoardPanel from "./KanbnBoardPanel";
import KanbnBurndownPanel from "./KanbnBurndownPanel"; import KanbnBurndownPanel from "./KanbnBurndownPanel";
@ -6,19 +6,19 @@ import KanbnTaskPanel from "./KanbnTaskPanel";
let kanbnStatusBarItem: KanbnStatusBarItem; let kanbnStatusBarItem: KanbnStatusBarItem;
export async function activate(context: vscode.ExtensionContext) { export async function activate(context: ExtensionContext) {
// Register a command to initialise Kanbn in the current workspace. This command will be invoked when the status // Register a command to initialise Kanbn in the current workspace. This command will be invoked when the status
// bar item is clicked in a workspace where Kanbn isn't already initialised. // bar item is clicked in a workspace where Kanbn isn't already initialised.
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("kanbn.init", async () => { commands.registerCommand("kanbn.init", async () => {
// If no workspace folder is opened, we can't initialise kanbn // If no workspace folder is opened, we can't initialise kanbn
if (vscode.workspace.workspaceFolders === undefined) { if (workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage("You need to open a workspace before initialising Kanbn."); window.showErrorMessage("You need to open a workspace before initialising Kanbn.");
return; return;
} }
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// If kanbn is already initialised, get the project name // If kanbn is already initialised, get the project name
@ -28,7 +28,7 @@ export async function activate(context: vscode.ExtensionContext) {
} }
// Prompt for a new project name // Prompt for a new project name
const newProjectName = await vscode.window.showInputBox({ const newProjectName = await window.showInputBox({
value: projectName, value: projectName,
placeHolder: "The project name.", placeHolder: "The project name.",
validateInput: (text) => { validateInput: (text) => {
@ -41,7 +41,7 @@ export async function activate(context: vscode.ExtensionContext) {
await kanbn.initialise({ await kanbn.initialise({
name: newProjectName, name: newProjectName,
}); });
vscode.window.showInformationMessage(`Initialised Kanbn project '${newProjectName}'.`); window.showInformationMessage(`Initialised Kanbn project '${newProjectName}'.`);
KanbnBoardPanel.update(); KanbnBoardPanel.update();
} }
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
@ -51,28 +51,28 @@ export async function activate(context: vscode.ExtensionContext) {
// Register a command to open the kanbn board. This command will be invoked when the status bar item is clicked // Register a command to open the kanbn board. This command will be invoked when the status bar item is clicked
// in a workspace where kanbn has already been initialised. // in a workspace where kanbn has already been initialised.
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("kanbn.board", async () => { commands.registerCommand("kanbn.board", async () => {
// If no workspace folder is opened, we can't open the kanbn board // If no workspace folder is opened, we can't open the kanbn board
if (vscode.workspace.workspaceFolders === undefined) { if (workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage("You need to open a workspace before viewing the Kanbn board."); window.showErrorMessage("You need to open a workspace before viewing the Kanbn board.");
return; return;
} }
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// If kanbn is initialised, view the kanbn board // If kanbn is initialised, view the kanbn board
if (await kanbn.initialised()) { if (await kanbn.initialised()) {
KanbnBoardPanel.createOrShow( KanbnBoardPanel.createOrShow(
context.extensionPath, context.extensionPath,
vscode.workspace.workspaceFolders[0].uri.fsPath, workspace.workspaceFolders[0].uri.fsPath,
kanbn, kanbn,
await kanbn.getFolderName() await kanbn.getFolderName()
); );
KanbnBoardPanel.update(); KanbnBoardPanel.update();
} else { } else {
vscode.window.showErrorMessage("You need to initialise Kanbn before viewing the Kanbn board."); window.showErrorMessage("You need to initialise Kanbn before viewing the Kanbn board.");
} }
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
}) })
@ -80,57 +80,57 @@ export async function activate(context: vscode.ExtensionContext) {
// Register a command to add a new kanbn task. // Register a command to add a new kanbn task.
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("kanbn.addTask", async () => { commands.registerCommand("kanbn.addTask", async () => {
// If no workspace folder is opened, we can't add a new task // If no workspace folder is opened, we can't add a new task
if (vscode.workspace.workspaceFolders === undefined) { if (workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage("You need to open a workspace before adding a new task."); window.showErrorMessage("You need to open a workspace before adding a new task.");
return; return;
} }
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// If kanbn is initialised, open the task webview // If kanbn is initialised, open the task webview
if (await kanbn.initialised()) { if (await kanbn.initialised()) {
KanbnTaskPanel.show( KanbnTaskPanel.show(
context.extensionPath, context.extensionPath,
vscode.workspace.workspaceFolders[0].uri.fsPath, workspace.workspaceFolders[0].uri.fsPath,
kanbn, kanbn,
await kanbn.getFolderName(), await kanbn.getFolderName(),
null, null,
null null
); );
} else { } else {
vscode.window.showErrorMessage("You need to initialise Kanbn before adding a new task."); window.showErrorMessage("You need to initialise Kanbn before adding a new task.");
} }
}) })
); );
// Register a command to open a burndown chart. // Register a command to open a burndown chart.
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("kanbn.burndown", async () => { commands.registerCommand("kanbn.burndown", async () => {
// If no workspace folder is opened, we can't open the burndown chart // If no workspace folder is opened, we can't open the burndown chart
if (vscode.workspace.workspaceFolders === undefined) { if (workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage("You need to open a workspace before viewing the burndown chart."); window.showErrorMessage("You need to open a workspace before viewing the burndown chart.");
return; return;
} }
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// If kanbn is initialised, view the burndown chart // If kanbn is initialised, view the burndown chart
if (await kanbn.initialised()) { if (await kanbn.initialised()) {
KanbnBurndownPanel.createOrShow( KanbnBurndownPanel.createOrShow(
context.extensionPath, context.extensionPath,
vscode.workspace.workspaceFolders[0].uri.fsPath, workspace.workspaceFolders[0].uri.fsPath,
kanbn, kanbn,
await kanbn.getFolderName() await kanbn.getFolderName()
); );
KanbnBurndownPanel.update(); KanbnBurndownPanel.update();
} else { } else {
vscode.window.showErrorMessage("You need to initialise Kanbn before viewing the burndown chart."); window.showErrorMessage("You need to initialise Kanbn before viewing the burndown chart.");
} }
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
}) })
@ -138,15 +138,15 @@ export async function activate(context: vscode.ExtensionContext) {
// Register a command to archive tasks. // Register a command to archive tasks.
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("kanbn.archiveTasks", async () => { commands.registerCommand("kanbn.archiveTasks", async () => {
// If no workspace folder is opened, we can't archive tasks // If no workspace folder is opened, we can't archive tasks
if (vscode.workspace.workspaceFolders === undefined) { if (workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage("You need to open a workspace before sending tasks to the archive."); window.showErrorMessage("You need to open a workspace before sending tasks to the archive.");
return; return;
} }
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// Get a list of tracked tasks // Get a list of tracked tasks
@ -155,12 +155,12 @@ export async function activate(context: vscode.ExtensionContext) {
tasks = [...(await kanbn.findTrackedTasks())]; tasks = [...(await kanbn.findTrackedTasks())];
} catch (e) {} } catch (e) {}
if (tasks.length === 0) { if (tasks.length === 0) {
vscode.window.showInformationMessage("There are no tasks to archive."); window.showInformationMessage("There are no tasks to archive.");
return; return;
} }
// Prompt for a selection of tasks to archive // Prompt for a selection of tasks to archive
const archiveTaskIds = await vscode.window.showQuickPick( const archiveTaskIds = await window.showQuickPick(
tasks, tasks,
{ {
placeHolder: 'Select tasks to archive...', placeHolder: 'Select tasks to archive...',
@ -173,8 +173,8 @@ export async function activate(context: vscode.ExtensionContext) {
} }
KanbnBoardPanel.update(); KanbnBoardPanel.update();
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { if (workspace.getConfiguration("kanbn").get("showTaskNotifications")) {
vscode.window.showInformationMessage( window.showInformationMessage(
`Archived ${archiveTaskIds.length} task${archiveTaskIds.length === 1 ? '' : 's'}.` `Archived ${archiveTaskIds.length} task${archiveTaskIds.length === 1 ? '' : 's'}.`
); );
} }
@ -184,15 +184,15 @@ export async function activate(context: vscode.ExtensionContext) {
// Register a command to restore a task from the archive. // Register a command to restore a task from the archive.
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("kanbn.restoreTasks", async () => { commands.registerCommand("kanbn.restoreTasks", async () => {
// If no workspace folder is opened, we can't restore tasks from the archive // If no workspace folder is opened, we can't restore tasks from the archive
if (vscode.workspace.workspaceFolders === undefined) { if (workspace.workspaceFolders === undefined) {
vscode.window.showErrorMessage("You need to open a workspace before restoring tasks from the archive."); window.showErrorMessage("You need to open a workspace before restoring tasks from the archive.");
return; return;
} }
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// Get a list of archived tasks // Get a list of archived tasks
@ -201,12 +201,12 @@ export async function activate(context: vscode.ExtensionContext) {
archivedTasks = await kanbn.listArchivedTasks(); archivedTasks = await kanbn.listArchivedTasks();
} catch (e) {} } catch (e) {}
if (archivedTasks.length === 0) { if (archivedTasks.length === 0) {
vscode.window.showInformationMessage("There are no archived tasks to restore."); window.showInformationMessage("There are no archived tasks to restore.");
return; return;
} }
// Prompt for a selection of tasks to restore // Prompt for a selection of tasks to restore
const restoreTaskIds = await vscode.window.showQuickPick( const restoreTaskIds = await window.showQuickPick(
archivedTasks, archivedTasks,
{ {
placeHolder: 'Select tasks to restore...', placeHolder: 'Select tasks to restore...',
@ -219,7 +219,7 @@ export async function activate(context: vscode.ExtensionContext) {
const index = await kanbn.getIndex(); const index = await kanbn.getIndex();
// Prompt for a column to restore the tasks into // Prompt for a column to restore the tasks into
const restoreColumn = await vscode.window.showQuickPick( const restoreColumn = await window.showQuickPick(
[ [
'None (use original)', 'None (use original)',
...Object.keys(index.columns) ...Object.keys(index.columns)
@ -234,8 +234,8 @@ export async function activate(context: vscode.ExtensionContext) {
} }
KanbnBoardPanel.update(); KanbnBoardPanel.update();
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { if (workspace.getConfiguration("kanbn").get("showTaskNotifications")) {
vscode.window.showInformationMessage( window.showInformationMessage(
`Restored ${restoreTaskIds.length} task${restoreTaskIds.length === 1 ? '' : 's'}.` `Restored ${restoreTaskIds.length} task${restoreTaskIds.length === 1 ? '' : 's'}.`
); );
} }
@ -245,9 +245,9 @@ export async function activate(context: vscode.ExtensionContext) {
); );
// If a workspace folder is open, add a status bar item and start watching for file changes // If a workspace folder is open, add a status bar item and start watching for file changes
if (vscode.workspace.workspaceFolders !== undefined) { if (workspace.workspaceFolders !== undefined) {
// Set the node process directory and import kanbn // Set the node process directory and import kanbn
process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); process.chdir(workspace.workspaceFolders[0].uri.fsPath);
const kanbn = await import("@basementuniverse/kanbn/src/main"); const kanbn = await import("@basementuniverse/kanbn/src/main");
// Create status bar item // Create status bar item
@ -256,10 +256,10 @@ export async function activate(context: vscode.ExtensionContext) {
KanbnBoardPanel.update(); KanbnBoardPanel.update();
// Initialise file watcher // Initialise file watcher
const uri = vscode.workspace.workspaceFolders[0].uri.fsPath; const uri = workspace.workspaceFolders[0].uri.fsPath;
const kanbnFolderName = await kanbn.getFolderName(); const kanbnFolderName = await kanbn.getFolderName();
const fileWatcher = vscode.workspace.createFileSystemWatcher( const fileWatcher = workspace.createFileSystemWatcher(
new vscode.RelativePattern(uri, `${kanbnFolderName}/**.*`) new RelativePattern(uri, `${kanbnFolderName}/**/*.md`)
); );
fileWatcher.onDidChange(() => { fileWatcher.onDidChange(() => {
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
@ -269,7 +269,7 @@ export async function activate(context: vscode.ExtensionContext) {
} }
// Handle configuration changes // Handle configuration changes
vscode.workspace.onDidChangeConfiguration((e) => { workspace.onDidChangeConfiguration((e) => {
kanbnStatusBarItem.update(); kanbnStatusBarItem.update();
KanbnBoardPanel.update(); KanbnBoardPanel.update();
}); });

32096
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,13 +7,13 @@
"color": "#72abdd", "color": "#72abdd",
"theme": "dark" "theme": "dark"
}, },
"version": "0.11.0", "version": "0.13.0",
"engines": { "engines": {
"vscode": "^1.23.0" "vscode": "^1.23.0"
}, },
"author": "Gordon Larrigan", "author": "Gordon Larrigan",
"license": "MIT", "license": "MIT",
"publisher": "gordonlarrigan", "publisher": "phares",
"keywords": [ "keywords": [
"kanbn", "kanbn",
"kanban", "kanban",
@ -118,10 +118,12 @@
"vscode-codicons": "^0.0.15" "vscode-codicons": "^0.0.15"
}, },
"scripts": { "scripts": {
"vscode:prepublish": "./scripts/build-non-split.js && tsc -p tsconfig.extension.json", "vscode:prepublish": "node ./scripts/build-non-split.js && tsc -p tsconfig.extension.json",
"postinstall": "node ./node_modules/vscode/bin/install", "postinstall": "node ./node_modules/vscode/bin/install",
"start": "react-scripts start", "start": "react-scripts start",
"build": "./scripts/build-non-split.js && tsc -p tsconfig.extension.json", "react:build": "node ./scripts/build-non-split.js",
"tsc:build": "tsc -p tsconfig.extension.json",
"build": "node ./scripts/build-non-split.js && tsc -p tsconfig.extension.json",
"test": "react-scripts test --env=jsdom", "test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },

View File

@ -139,6 +139,16 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, customFields, dateFo
setSubmitting(false); setSubmitting(false);
}; };
// Called when the go to raw task button is clicked
const handleGoToRawTask = values => {
vscode.postMessage({
command: 'kanbn.goToRaw',
taskId: task!.id,
taskData: values,
panelUuid
});
};
// Called when the delete task button is clicked // Called when the delete task button is clicked
const handleRemoveTask = values => { const handleRemoveTask = values => {
vscode.postMessage({ vscode.postMessage({
@ -243,6 +253,16 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, customFields, dateFo
{dirty && <span className="kanbn-task-editor-dirty">*</span>} {dirty && <span className="kanbn-task-editor-dirty">*</span>}
</h1> </h1>
<div className="kanbn-task-editor-buttons kanbn-task-editor-main-buttons"> <div className="kanbn-task-editor-buttons kanbn-task-editor-main-buttons">
{editing && <button
type="button"
className="kanbn-task-editor-button kanbn-task-editor-button-go-to"
title="Go to raw task"
onClick={() => {
handleGoToRawTask(values);
}}
>
<i className="codicon codicon-file-code"></i>Go to raw
</button>}
{editing && <button {editing && <button
type="button" type="button"
className="kanbn-task-editor-button kanbn-task-editor-button-delete" className="kanbn-task-editor-button kanbn-task-editor-button-delete"

View File

@ -71,16 +71,41 @@ const TaskItem = ({ task, columnName, customFields, position, dateFormat, vscode
<div className="kanbn-task-data kanbn-task-data-tags"> <div className="kanbn-task-data kanbn-task-data-tags">
{task.metadata.tags!.map(tag => { {task.metadata.tags!.map(tag => {
return ( return (
<span className={[ <span onClick={() => {
'kanbn-task-tag', vscode.postMessage({
`kanbn-task-tag-${paramCase(tag)}` command: 'kanbn.goToRaw',
].join(' ')}> taskId: task.id,
columnName: task.column
});
}}
className={[
'kanbn-task-tag',
`kanbn-task-tag-${paramCase(tag)}`
].join(' ')}>
{tag} {tag}
</span> </span>
); );
})} })}
</div> </div>
} }
{
task.relations.length > 0 &&
<div className="kanbn-task-data kanbn-task-data-tags">
{task.relations.map(relation => {
return (
<span onClick={() => {
vscode.postMessage({
command: 'kanbn.goToRaw',
taskId: task.id,
columnName: task.column
});
}}>
<u>{relation.task}</u>
</span>
);
})}
</div>
}
{ {
customFields.map(customField => { customFields.map(customField => {
if (customField.name in task.metadata) { if (customField.name in task.metadata) {
@ -168,7 +193,14 @@ const TaskItem = ({ task, columnName, customFields, position, dateFormat, vscode
{ {
task.workload !== undefined && task.workload !== undefined &&
<div className="kanbn-task-data kanbn-task-data-workload"> <div className="kanbn-task-data kanbn-task-data-workload">
<i className="codicon codicon-run"></i>{task.workload} <i className="codicon codicon-tools"
onClick={() => {
vscode.postMessage({
command: 'kanbn.goToRaw',
taskId: task.id,
columnName: task.column
});
}}></i>{task.workload}
</div> </div>
} }
{ {

View File

@ -1,9 +1,9 @@
import * as React from 'react'; import * as React from 'react';
import * as ReactDOM from 'react-dom'; import { render } from 'react-dom';
import App from './App'; import App from './App';
import './index.css'; import './index.css';
ReactDOM.render( render(
<App />, <App />,
document.getElementById('root') as HTMLElement document.getElementById('root') as HTMLElement
); );

BIN
vscode-kanbn-0.12.0.vsix Normal file

Binary file not shown.