Moving tasks
This commit is contained in:
parent
d2234485f4
commit
fcb90c6e27
@ -8,43 +8,52 @@ export default class KanbnBoardPanel {
|
|||||||
|
|
||||||
private readonly _panel: vscode.WebviewPanel;
|
private readonly _panel: vscode.WebviewPanel;
|
||||||
private readonly _extensionPath: string;
|
private readonly _extensionPath: string;
|
||||||
|
private readonly _kanbn: typeof import('@basementuniverse/kanbn/src/main');
|
||||||
private _disposables: vscode.Disposable[] = [];
|
private _disposables: vscode.Disposable[] = [];
|
||||||
|
|
||||||
public static createOrShow(extensionPath: string) {
|
public static createOrShow(
|
||||||
|
extensionPath: string,
|
||||||
|
kanbn: typeof import('@basementuniverse/kanbn/src/main')
|
||||||
|
) {
|
||||||
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
|
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
|
||||||
|
|
||||||
// If we already have a panel, show it.
|
// If we already have a panel, show it, otherwise create a new panel
|
||||||
// Otherwise, create a new panel.
|
|
||||||
if (KanbnBoardPanel.currentPanel) {
|
if (KanbnBoardPanel.currentPanel) {
|
||||||
KanbnBoardPanel.currentPanel._panel.reveal(column);
|
KanbnBoardPanel.currentPanel._panel.reveal(column);
|
||||||
} else {
|
} else {
|
||||||
KanbnBoardPanel.currentPanel = new KanbnBoardPanel(
|
KanbnBoardPanel.currentPanel = new KanbnBoardPanel(
|
||||||
extensionPath,
|
extensionPath,
|
||||||
column || vscode.ViewColumn.One
|
column || vscode.ViewColumn.One,
|
||||||
|
kanbn
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async updateBoard(kanbn: typeof import('@basementuniverse/kanbn/src/main')) {
|
public static async update() {
|
||||||
if (KanbnBoardPanel.currentPanel) {
|
if (KanbnBoardPanel.currentPanel) {
|
||||||
let index: any;
|
let index: any;
|
||||||
try {
|
try {
|
||||||
index = await kanbn.getIndex();
|
index = await KanbnBoardPanel.currentPanel._kanbn.getIndex();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vscode.window.showErrorMessage(error instanceof Error ? error.message : error);
|
vscode.window.showErrorMessage(error instanceof Error ? error.message : error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
KanbnBoardPanel.currentPanel._panel.webview.postMessage({
|
KanbnBoardPanel.currentPanel._panel.webview.postMessage({
|
||||||
index,
|
index,
|
||||||
tasks: (await kanbn.loadAllTrackedTasks(index)).map(
|
tasks: (await KanbnBoardPanel.currentPanel._kanbn.loadAllTrackedTasks(index)).map(
|
||||||
task => kanbn.hydrateTask(index, task)
|
task => KanbnBoardPanel.currentPanel!._kanbn.hydrateTask(index, task)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor(extensionPath: string, column: vscode.ViewColumn) {
|
private constructor(
|
||||||
|
extensionPath: string,
|
||||||
|
column: vscode.ViewColumn,
|
||||||
|
kanbn: typeof import('@basementuniverse/kanbn/src/main')
|
||||||
|
) {
|
||||||
this._extensionPath = extensionPath;
|
this._extensionPath = extensionPath;
|
||||||
|
this._kanbn = kanbn;
|
||||||
|
|
||||||
// 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 = vscode.window.createWebviewPanel(KanbnBoardPanel.viewType, "Kanbn Board", column, {
|
||||||
@ -68,11 +77,42 @@ export default class KanbnBoardPanel {
|
|||||||
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
|
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
|
||||||
|
|
||||||
// Handle messages from the webview
|
// Handle messages from the webview
|
||||||
this._panel.webview.onDidReceiveMessage(message => {
|
this._panel.webview.onDidReceiveMessage(async message => {
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
|
|
||||||
|
// Display error message
|
||||||
case 'error':
|
case 'error':
|
||||||
vscode.window.showErrorMessage(message.text);
|
vscode.window.showErrorMessage(message.text);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Move a task
|
||||||
|
case 'kanbn.move':
|
||||||
|
try {
|
||||||
|
await kanbn.moveTask(message.task, message.column, message.position);
|
||||||
|
} catch (e) {
|
||||||
|
vscode.window.showErrorMessage(e.message);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Create a task
|
||||||
|
case 'kanbn.create':
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update a task
|
||||||
|
case 'kanbn.update':
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Rename a task
|
||||||
|
case 'kanbn.rename':
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Delete a task
|
||||||
|
case 'kanbn.delete':
|
||||||
|
//
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}, null, this._disposables);
|
}, null, this._disposables);
|
||||||
}
|
}
|
||||||
@ -82,7 +122,6 @@ export default class KanbnBoardPanel {
|
|||||||
|
|
||||||
// Clean up our resources
|
// Clean up our resources
|
||||||
this._panel.dispose();
|
this._panel.dispose();
|
||||||
|
|
||||||
while (this._disposables.length) {
|
while (this._disposables.length) {
|
||||||
const x = this._disposables.pop();
|
const x = this._disposables.pop();
|
||||||
if (x) {
|
if (x) {
|
||||||
@ -95,11 +134,12 @@ export default class KanbnBoardPanel {
|
|||||||
const manifest = require(path.join(this._extensionPath, 'build', 'asset-manifest.json'));
|
const manifest = require(path.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
|
||||||
const scriptPathOnDisk = vscode.Uri.file(path.join(this._extensionPath, 'build', mainScript));
|
.file(path.join(this._extensionPath, 'build', mainScript))
|
||||||
const scriptUri = scriptPathOnDisk.with({ scheme: 'vscode-resource' });
|
.with({ scheme: 'vscode-resource' });
|
||||||
const stylePathOnDisk = vscode.Uri.file(path.join(this._extensionPath, 'build', mainStyle));
|
const styleUri = vscode.Uri
|
||||||
const styleUri = stylePathOnDisk.with({ scheme: 'vscode-resource' });
|
.file(path.join(this._extensionPath, 'build', mainStyle))
|
||||||
|
.with({ scheme: 'vscode-resource' });
|
||||||
|
|
||||||
// Use a nonce to whitelist which scripts can be run
|
// Use a nonce to whitelist which scripts can be run
|
||||||
const nonce = getNonce();
|
const nonce = getNonce();
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
export default class KanbnStatusBarItem {
|
export default class KanbnStatusBarItem {
|
||||||
statusBarItem: vscode.StatusBarItem;
|
private readonly _statusBarItem: vscode.StatusBarItem;
|
||||||
|
private readonly _kanbn: typeof import('@basementuniverse/kanbn/src/main');
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext) {
|
constructor(
|
||||||
this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0);
|
context: vscode.ExtensionContext,
|
||||||
context.subscriptions.push(this.statusBarItem);
|
kanbn: typeof import('@basementuniverse/kanbn/src/main')
|
||||||
|
) {
|
||||||
|
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0);
|
||||||
|
context.subscriptions.push(this._statusBarItem);
|
||||||
|
this._kanbn = kanbn;
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(kanbn: typeof import('@basementuniverse/kanbn/src/main')): Promise<void> {
|
async update(): Promise<void> {
|
||||||
if (this.statusBarItem === undefined) {
|
if (this._statusBarItem === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (await kanbn.initialised()) {
|
if (await this._kanbn.initialised()) {
|
||||||
const status = await kanbn.status(true);
|
const status = await this._kanbn.status(true);
|
||||||
const text = [
|
const text = [
|
||||||
`$(project) ${status.tasks}`
|
`$(project) ${status.tasks}`
|
||||||
];
|
];
|
||||||
@ -28,14 +33,14 @@ export default class KanbnStatusBarItem {
|
|||||||
text.push(`$(check) ${status.completedTasks}`);
|
text.push(`$(check) ${status.completedTasks}`);
|
||||||
tooltip.push(`${status.completedTasks} completed task${status.completedTasks === 1 ? '' : 's'}`);
|
tooltip.push(`${status.completedTasks} completed task${status.completedTasks === 1 ? '' : 's'}`);
|
||||||
}
|
}
|
||||||
this.statusBarItem.text = text.join(' ');
|
this._statusBarItem.text = text.join(' ');
|
||||||
this.statusBarItem.tooltip = tooltip.join('\n');
|
this._statusBarItem.tooltip = tooltip.join('\n');
|
||||||
this.statusBarItem.command = 'kanbn.board';
|
this._statusBarItem.command = 'kanbn.board';
|
||||||
} else {
|
} else {
|
||||||
this.statusBarItem.text = '$(project) Not initialised';
|
this._statusBarItem.text = '$(project) Not initialised';
|
||||||
this.statusBarItem.tooltip = 'Click to initialise';
|
this._statusBarItem.tooltip = 'Click to initialise';
|
||||||
this.statusBarItem.command = 'kanbn.init';
|
this._statusBarItem.command = 'kanbn.init';
|
||||||
}
|
}
|
||||||
this.statusBarItem.show();
|
this._statusBarItem.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||||||
name: newProjectName
|
name: newProjectName
|
||||||
});
|
});
|
||||||
vscode.window.showInformationMessage(`Initialised kanbn project '${newProjectName}'.`);
|
vscode.window.showInformationMessage(`Initialised kanbn project '${newProjectName}'.`);
|
||||||
kanbnStatusBarItem.update(kanbn);
|
kanbnStatusBarItem.update();
|
||||||
KanbnBoardPanel.updateBoard(kanbn);
|
KanbnBoardPanel.update();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -62,8 +62,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
// 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(context.extensionPath);
|
KanbnBoardPanel.createOrShow(context.extensionPath, kanbn);
|
||||||
KanbnBoardPanel.updateBoard(kanbn);
|
KanbnBoardPanel.update();
|
||||||
} else {
|
} else {
|
||||||
vscode.window.showErrorMessage('You need to initialise kanbn before viewing the kanbn board.');
|
vscode.window.showErrorMessage('You need to initialise kanbn before viewing the kanbn board.');
|
||||||
}
|
}
|
||||||
@ -77,16 +77,16 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||||||
const kanbn = await import('@basementuniverse/kanbn/src/main');
|
const kanbn = await import('@basementuniverse/kanbn/src/main');
|
||||||
|
|
||||||
// Create status bar item
|
// Create status bar item
|
||||||
kanbnStatusBarItem = new KanbnStatusBarItem(context);
|
kanbnStatusBarItem = new KanbnStatusBarItem(context, kanbn);
|
||||||
kanbnStatusBarItem.update(kanbn);
|
kanbnStatusBarItem.update();
|
||||||
KanbnBoardPanel.updateBoard(kanbn);
|
KanbnBoardPanel.update();
|
||||||
|
|
||||||
// Initialise file watcher
|
// Initialise file watcher
|
||||||
const uri = vscode.workspace.workspaceFolders[0].uri.fsPath;
|
const uri = vscode.workspace.workspaceFolders[0].uri.fsPath;
|
||||||
const fileWatcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(uri, '.kanbn/*'));
|
const fileWatcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(uri, '.kanbn/*'));
|
||||||
fileWatcher.onDidChange(() => {
|
fileWatcher.onDidChange(() => {
|
||||||
kanbnStatusBarItem.update(kanbn);
|
kanbnStatusBarItem.update();
|
||||||
KanbnBoardPanel.updateBoard(kanbn);
|
KanbnBoardPanel.update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,54 +3,94 @@ import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
|||||||
|
|
||||||
export type task = {
|
export type task = {
|
||||||
id: string,
|
id: string,
|
||||||
name: string
|
name: string,
|
||||||
}
|
description: string,
|
||||||
|
column: string,
|
||||||
|
workload?: number,
|
||||||
|
remainingWorkload?: number,
|
||||||
|
progress?: number,
|
||||||
|
metadata: {
|
||||||
|
created: Date,
|
||||||
|
updated?: Date,
|
||||||
|
completed?: Date,
|
||||||
|
assigned?: string
|
||||||
|
},
|
||||||
|
relations: Array<{
|
||||||
|
type: string,
|
||||||
|
task: string
|
||||||
|
}>,
|
||||||
|
subTasks: Array<{
|
||||||
|
text: string,
|
||||||
|
completed: boolean
|
||||||
|
}>,
|
||||||
|
comments: Array<{
|
||||||
|
author: string,
|
||||||
|
date: Date,
|
||||||
|
text: string
|
||||||
|
}>
|
||||||
|
};
|
||||||
|
|
||||||
|
declare var acquireVsCodeApi: any;
|
||||||
|
const vscode = acquireVsCodeApi();
|
||||||
|
|
||||||
const onDragEnd = (result, columns, setColumns) => {
|
const onDragEnd = (result, columns, setColumns) => {
|
||||||
if (!result.destination) return;
|
|
||||||
|
// No destination means the item was dragged to an invalid location
|
||||||
|
if (!result.destination) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the source and destination columns
|
||||||
const { source, destination } = result;
|
const { source, destination } = result;
|
||||||
|
|
||||||
|
// The item that was moved
|
||||||
|
let removed: task;
|
||||||
|
|
||||||
|
// The task was dragged from one column to another
|
||||||
if (source.droppableId !== destination.droppableId) {
|
if (source.droppableId !== destination.droppableId) {
|
||||||
const sourceColumn = columns[source.droppableId];
|
const sourceItems = columns[source.droppableId];
|
||||||
const destColumn = columns[destination.droppableId];
|
const destItems = columns[destination.droppableId];
|
||||||
const sourceItems = [...sourceColumn.items];
|
[removed] = sourceItems.splice(source.index, 1);
|
||||||
const destItems = [...destColumn.items];
|
|
||||||
const [removed] = sourceItems.splice(source.index, 1);
|
|
||||||
destItems.splice(destination.index, 0, removed);
|
destItems.splice(destination.index, 0, removed);
|
||||||
setColumns({
|
setColumns({
|
||||||
...columns,
|
...columns,
|
||||||
[source.droppableId]: {
|
[source.droppableId]: sourceItems,
|
||||||
...sourceColumn,
|
[destination.droppableId]: destItems
|
||||||
items: sourceItems
|
|
||||||
},
|
|
||||||
[destination.droppableId]: {
|
|
||||||
...destColumn,
|
|
||||||
items: destItems
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The task was dragged into the same column
|
||||||
} else {
|
} else {
|
||||||
const column = columns[source.droppableId];
|
|
||||||
const copiedItems = [...column.items];
|
// If the task was dragged to the same position that it currently occupies, don't move it (this will
|
||||||
const [removed] = copiedItems.splice(source.index, 1);
|
// prevent unnecessarily setting the task's updated date)
|
||||||
|
if (source.index === destination.index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const copiedItems = columns[source.droppableId];
|
||||||
|
[removed] = copiedItems.splice(source.index, 1);
|
||||||
copiedItems.splice(destination.index, 0, removed);
|
copiedItems.splice(destination.index, 0, removed);
|
||||||
setColumns({
|
setColumns({
|
||||||
...columns,
|
...columns,
|
||||||
[source.droppableId]: {
|
[source.droppableId]: copiedItems
|
||||||
...column,
|
|
||||||
items: copiedItems
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Post a message back to the extension so we can move the task in the index
|
||||||
|
vscode.postMessage({
|
||||||
|
command: 'kanbn.move',
|
||||||
|
task: removed.id,
|
||||||
|
column: destination.droppableId,
|
||||||
|
position: destination.index
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const Board = ({ columns }) => {
|
const Board = ({ columns }) => {
|
||||||
// const [columns, setColumns] = useState(props.columns);
|
const [, setColumns] = useState(columns);
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", justifyContent: "center", height: "100%" }}>
|
<div style={{ display: "flex", justifyContent: "center", height: "100%" }}>
|
||||||
{/* <DragDropContext
|
<DragDropContext
|
||||||
onDragEnd={result => onDragEnd(result, columns, setColumns)}
|
onDragEnd={result => onDragEnd(result, columns, setColumns)}
|
||||||
> */}
|
>
|
||||||
<DragDropContext>
|
|
||||||
{Object.entries(columns).map(([columnId, column]) => {
|
{Object.entries(columns).map(([columnId, column]) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -122,6 +162,6 @@ const Board = ({ columns }) => {
|
|||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Board;
|
export default Board;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user