Add task archive and restore
This commit is contained in:
		| @ -1,3 +1,8 @@ | ||||
| # 0.10.0 | ||||
|  | ||||
| * Added task archive, tasks can now be sent to the archive folder and restored from the archive folder | ||||
| * Fixed debounced updates on burndown chart | ||||
|  | ||||
| # 0.9.3 | ||||
|  | ||||
| * Fixed performance issue where React app would keep adding event listeners every time the board was re-rendered | ||||
|  | ||||
| @ -54,6 +54,7 @@ The following commands are available: | ||||
| - `Kanbn: Open board` will open open the Kanbn board. | ||||
| - `Kanbn: Open burndown chart` will open a burndown chart. | ||||
| - `Kanbn: Add task` will open the task editor. | ||||
| - `Kanbn: Restore task` will restore tasks from the archive. | ||||
|  | ||||
| ## Configuration settings | ||||
|  | ||||
|  | ||||
| @ -91,6 +91,7 @@ Various Codicon icons have been used in this extension. Check [here](https://cod | ||||
| - `kanbn-task-editor-comment-text` | ||||
| - `kanbn-task-editor-column-right` | ||||
| - `kanbn-task-editor-button-submit` | ||||
| - `kanbn-task-editor-button-archive` | ||||
| - `kanbn-task-editor-field-column` | ||||
| - `kanbn-task-editor-field-assigned` | ||||
| - `kanbn-task-editor-field-started` | ||||
|  | ||||
| @ -197,6 +197,16 @@ export default class KanbnTaskPanel { | ||||
|                 } | ||||
|               }); | ||||
|             return; | ||||
|  | ||||
|           // Archive a task and close the webview panel | ||||
|           case 'kanbn.archive': | ||||
|             await this._kanbn.archiveTask(message.taskId); | ||||
|             KanbnTaskPanel.panels[message.panelUuid].dispose(); | ||||
|             delete KanbnTaskPanel.panels[message.panelUuid]; | ||||
|             if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { | ||||
|               vscode.window.showInformationMessage(`Archived task '${message.taskData.name}'.`); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|       }, | ||||
|       null, | ||||
|  | ||||
| @ -136,6 +136,68 @@ export async function activate(context: vscode.ExtensionContext) { | ||||
|     }) | ||||
|   ); | ||||
|  | ||||
|   // Register a command to restore a task from the archive. | ||||
|   context.subscriptions.push( | ||||
|     vscode.commands.registerCommand("kanbn.restoreTask", async () => { | ||||
|       // If no workspace folder is opened, we can't restore tasks from the archive | ||||
|       if (vscode.workspace.workspaceFolders === undefined) { | ||||
|         vscode.window.showErrorMessage("You need to open a workspace before restoring tasks from the archive."); | ||||
|         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"); | ||||
|  | ||||
|       // Get a list of archived tasks | ||||
|       let archivedTasks: string[] = []; | ||||
|       try { | ||||
|         archivedTasks = await kanbn.listArchivedTasks(); | ||||
|       } catch (e) {} | ||||
|       if (archivedTasks.length === 0) { | ||||
|         vscode.window.showInformationMessage("There are no archived tasks to restore."); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       // Prompt for a selection of tasks to restore | ||||
|       const restoreTaskIds = await vscode.window.showQuickPick( | ||||
|         archivedTasks, | ||||
|         { | ||||
|           placeHolder: 'Select tasks to restore...', | ||||
|           canPickMany: true, | ||||
|         } | ||||
|       ); | ||||
|       if (restoreTaskIds !== undefined && restoreTaskIds.length > 0) { | ||||
|  | ||||
|         // Load index | ||||
|         const index = await kanbn.getIndex(); | ||||
|  | ||||
|         // Prompt for a column to restore the tasks into | ||||
|         const restoreColumn = await vscode.window.showQuickPick( | ||||
|           [ | ||||
|             'None (use original)', | ||||
|             ...Object.keys(index.columns) | ||||
|           ], | ||||
|           { | ||||
|             canPickMany: false | ||||
|           } | ||||
|         ); | ||||
|         if (restoreColumn !== undefined) { | ||||
|           for (let restoreTaskId of restoreTaskIds) { | ||||
|             await kanbn.restoreTask(restoreTaskId, restoreColumn === 'None (use original)' ? null : restoreColumn); | ||||
|           } | ||||
|           KanbnBoardPanel.update(); | ||||
|           kanbnStatusBarItem.update(); | ||||
|           if (vscode.workspace.getConfiguration("kanbn").get("showTaskNotifications")) { | ||||
|             vscode.window.showInformationMessage( | ||||
|               `Restored ${restoreTaskIds.length} task${restoreTaskIds.length === 1 ? '' : 's'}.` | ||||
|             ); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
|  | ||||
|   // If a workspace folder is open, add a status bar item and start watching for file changes | ||||
|   if (vscode.workspace.workspaceFolders !== undefined) { | ||||
|     // Set the node process directory and import kanbn | ||||
|  | ||||
							
								
								
									
										2178
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2178
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -59,6 +59,11 @@ | ||||
|         "command": "kanbn.burndown", | ||||
|         "title": "Open burndown chart", | ||||
|         "category": "Kanbn" | ||||
|       }, | ||||
|       { | ||||
|         "command": "kanbn.restoreTask", | ||||
|         "title": "Restore task", | ||||
|         "category": "Kanbn" | ||||
|       } | ||||
|     ], | ||||
|     "configuration": { | ||||
| @ -88,7 +93,7 @@ | ||||
|     } | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@basementuniverse/kanbn": "^0.8.2", | ||||
|     "@basementuniverse/kanbn": "file:~/Projects/kanbn", | ||||
|     "dateformat": "^4.5.1", | ||||
|     "formik": "^2.2.6", | ||||
|     "git-user-name": "^2.0.0", | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| import React, { useState, useRef } from 'react'; | ||||
| import { ResponsiveContainer, LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts'; | ||||
| import VSCodeApi from "./VSCodeApi"; | ||||
| import formatDate from 'dateformat'; | ||||
| @ -40,44 +40,96 @@ const Burndown = ({ name, sprints, burndownData, dateFormat, vscode }: { | ||||
|       : formatDate(burndownData.series[0].to, 'yyyy-mm-dd') | ||||
|   ); | ||||
|  | ||||
|   const refreshBurndownData = debounce(500, settings => { | ||||
|   const refreshBurndownData = useRef(debounce(500, settings => { | ||||
|     vscode.postMessage({ | ||||
|       command: 'kanbn.refreshBurndownData', | ||||
|       ...Object.assign( | ||||
|       ...settings | ||||
|     }); | ||||
|   })).current; | ||||
|  | ||||
|   const handleChangeSprint = ({ target: { value }}) => { | ||||
|     setSprint(value); | ||||
|     refreshBurndownData( | ||||
|       Object.assign( | ||||
|         { | ||||
|           sprintMode, | ||||
|           sprint, | ||||
|           startDate, | ||||
|           endDate | ||||
|         }, | ||||
|         settings | ||||
|         { | ||||
|           sprint: value | ||||
|         } | ||||
|       ) | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   const handleChangeSprint = ({ target: { value }}) => { | ||||
|     setSprint(value); | ||||
|     refreshBurndownData({ sprint: value }); | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
|   const handleChangeStartDate = ({ target: { value }}) => { | ||||
|     setStartDate(value); | ||||
|     refreshBurndownData({ startDate: value }); | ||||
|     refreshBurndownData( | ||||
|       Object.assign( | ||||
|         { | ||||
|           sprintMode, | ||||
|           sprint, | ||||
|           startDate, | ||||
|           endDate | ||||
|         }, | ||||
|         { | ||||
|           startDate: value | ||||
|         } | ||||
|       ) | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
|   const handleChangeEndDate = ({ target: { value }}) => { | ||||
|     setEndDate(value); | ||||
|     refreshBurndownData({ endDate: value }); | ||||
|     refreshBurndownData( | ||||
|       Object.assign( | ||||
|         { | ||||
|           sprintMode, | ||||
|           sprint, | ||||
|           startDate, | ||||
|           endDate | ||||
|         }, | ||||
|         { | ||||
|           endDate: value | ||||
|         } | ||||
|       ) | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
|   const handleClickSprintMode = () => { | ||||
|     setSprintMode(true); | ||||
|     refreshBurndownData({ sprintMode: true }); | ||||
|     refreshBurndownData( | ||||
|       Object.assign( | ||||
|         { | ||||
|           sprintMode, | ||||
|           sprint, | ||||
|           startDate, | ||||
|           endDate | ||||
|         }, | ||||
|         { | ||||
|           sprintMode: true | ||||
|         } | ||||
|       ) | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
|   const handleClickDateMode = () => { | ||||
|     setSprintMode(false); | ||||
|     refreshBurndownData({ sprintMode: false }); | ||||
|     refreshBurndownData( | ||||
|       Object.assign( | ||||
|         { | ||||
|           sprintMode, | ||||
|           sprint, | ||||
|           startDate, | ||||
|           endDate | ||||
|         }, | ||||
|         { | ||||
|           sprintMode: false | ||||
|         } | ||||
|       ) | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
|   const chartData = burndownData.series.length > 0 | ||||
|  | ||||
| @ -107,6 +107,16 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   // Called when the archive task button is clicked | ||||
|   const handleArchiveTask = values => { | ||||
|     vscode.postMessage({ | ||||
|       command: 'kanbn.archive', | ||||
|       taskId: task!.id, | ||||
|       taskData: values, | ||||
|       panelUuid | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   // Check if a task's due date is in the past | ||||
|   const checkOverdue = (values: { metadata: { due?: string } }) => { | ||||
|     if ('due' in values.metadata && values.metadata.due !== undefined) { | ||||
| @ -487,6 +497,16 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui | ||||
|                     > | ||||
|                       <i className="codicon codicon-trash"></i>Delete | ||||
|                     </button>} | ||||
|                     {editing && <button | ||||
|                       type="button" | ||||
|                       className="kanbn-task-editor-button kanbn-task-editor-button-archive" | ||||
|                       title="Archive task" | ||||
|                       onClick={() => { | ||||
|                         handleArchiveTask(values); | ||||
|                       }} | ||||
|                     > | ||||
|                       <i className="codicon codicon-archive"></i>Archive | ||||
|                     </button>} | ||||
|                     <button | ||||
|                       type="submit" | ||||
|                       className="kanbn-task-editor-button kanbn-task-editor-button-submit" | ||||
|  | ||||
		Reference in New Issue
	
	Block a user