From f53db526725f0f281d373572f4996a9ece797f64 Mon Sep 17 00:00:00 2001 From: Gordon Date: Sun, 6 Jun 2021 01:16:18 +0100 Subject: [PATCH] Add column sorting --- docs/styles.md | 3 ++ ext-src/KanbnBoardPanel.ts | 84 ++++++++++++++++++++++++++++++++++++++ src/App.tsx | 3 ++ src/Board.tsx | 28 ++++++++++++- src/index.css | 38 +++++++++-------- 5 files changed, 139 insertions(+), 17 deletions(-) diff --git a/docs/styles.md b/docs/styles.md index 7220613..28bbffd 100644 --- a/docs/styles.md +++ b/docs/styles.md @@ -27,7 +27,10 @@ Various Codicon icons have been used in this extension. Check [here](https://cod - `kanbn-column-{Column name in snake-case}` - `kanbn-column-name` - `kanbn-column-count` +- `kanbn-column-button` - `kanbn-create-task-button` +- `kanbn-sort-column-button` +- `kanbn-column-sorted` - `kanbn-column-task-list-container` - `kanbn-column-task-list` - `kanbn-column-task-list.drag-over` diff --git a/ext-src/KanbnBoardPanel.ts b/ext-src/KanbnBoardPanel.ts index e58c933..6ecc88e 100644 --- a/ext-src/KanbnBoardPanel.ts +++ b/ext-src/KanbnBoardPanel.ts @@ -4,6 +4,21 @@ import getNonce from "./getNonce"; import KanbnTaskPanel from "./KanbnTaskPanel"; import KanbnBurndownPanel from "./KanbnBurndownPanel"; +const sortByFields: { [key: string]: string } = { + 'Name': 'name', + 'Created': 'created', + 'Updated': 'updated', + 'Started': 'started', + 'Completed': 'completed', + 'Due': 'due', + 'Assigned': 'assigned', + 'Count sub-tasks': 'countSubTasks', + 'Count tags': 'countTags', + 'Count relations': 'countRelations', + 'Count comments': 'countComments', + 'Workload': 'workload', +}; + export default class KanbnBoardPanel { public static currentPanel: KanbnBoardPanel | undefined; @@ -63,6 +78,7 @@ export default class KanbnBoardPanel { hiddenColumns: index.options.hiddenColumns ?? [], startedColumns: index.options.startedColumns ?? [], completedColumns: index.options.completedColumns ?? [], + columnSorting: index.options.columnSorting ?? {}, dateFormat: KanbnBoardPanel.currentPanel._kanbn.getDateFormat(index), showBurndownButton: vscode.workspace.getConfiguration("kanbn").get("showBurndownButton"), showSprintButton: vscode.workspace.getConfiguration("kanbn").get("showSprintButton"), @@ -157,6 +173,74 @@ export default class KanbnBoardPanel { ); return; + // Sort a column + case "kanbn.sortColumn": + // Load the index + const index = await this._kanbn.getIndex(); + let customFields = []; + if ('customFields' in index.options) { + customFields = index.options.customFields.map( + (customField: { name: string, type: string }) => customField.name + ); + } + // Prompt for a task property to sort by + const sortBy: string = await vscode.window.showQuickPick( + [ + 'None', + ...Object.keys(sortByFields), + ...customFields, + ], + { + placeHolder: 'Sort this column by...', + canPickMany: false, + } + ); + if (sortBy !== undefined) { + // Clear any saved sort settings for this column + if (sortBy === 'None') { + await this._kanbn.sort(message.columnName, [], false); + return; + } + + // Prompt for sort direction and save settings + const sortDirection = await vscode.window.showQuickPick( + [ + 'Ascending', + 'Descending', + ], + { + placeHolder: 'Sort direction', + canPickMany: false, + } + ); + if (sortDirection !== undefined) { + const saveSort = await vscode.window.showQuickPick( + [ + "Yes", + "No", + ], + { + placeHolder: 'Save sort settings for this column?', + canPickMany: false, + } + ); + if (saveSort !== undefined) { + await this._kanbn.sort( + message.columnName, + [ + { + field: sortBy in sortByFields ? sortByFields[sortBy] : sortBy, + order: sortDirection === 'Descending' ? 'descending' : 'ascending', + } + ], + saveSort === 'Yes' + ); + KanbnBoardPanel.update(); + } + } + } + return; + // Open a burndown chart case "kanbn.burndown": KanbnBurndownPanel.createOrShow( diff --git a/src/App.tsx b/src/App.tsx index 8eb0dac..89119e9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,6 +17,7 @@ function App() { const [hiddenColumns, setHiddenColumns] = useState([]); const [startedColumns, setStartedColumns] = useState([]); const [completedColumns, setCompletedColumns] = useState([]); + const [columnSorting, setColumnSorting] = useState({}); const [dateFormat, setDateFormat] = useState(''); const [task, setTask] = useState({}); const [tasks, setTasks] = useState({}); @@ -46,6 +47,7 @@ function App() { setHiddenColumns(event.data.hiddenColumns); setStartedColumns(event.data.startedColumns); setCompletedColumns(event.data.completedColumns); + setColumnSorting(event.data.columnSorting); setShowBurndownButton(event.data.showBurndownButton); setShowSprintButton(event.data.showSprintButton); @@ -98,6 +100,7 @@ function App() { hiddenColumns={hiddenColumns} startedColumns={startedColumns} completedColumns={completedColumns} + columnSorting={columnSorting} dateFormat={dateFormat} showBurndownButton={showBurndownButton} showSprintButton={showSprintButton} diff --git a/src/Board.tsx b/src/Board.tsx index d809115..270204c 100644 --- a/src/Board.tsx +++ b/src/Board.tsx @@ -139,6 +139,7 @@ const Board = ({ hiddenColumns, startedColumns, completedColumns, + columnSorting, dateFormat, showBurndownButton, showSprintButton, @@ -151,6 +152,7 @@ const Board = ({ hiddenColumns: string[], startedColumns: string[], completedColumns: string[], + columnSorting: { [columnName: string]: { field: string, order: 'ascending' | 'descending' }[] }, dateFormat: string, showBurndownButton: boolean, showSprintButton: boolean, @@ -274,7 +276,7 @@ const Board = ({ {column.length || ''} + {((columnIsSorted, columnSortSettings) => ( + + ))(columnName in columnSorting, columnSorting[columnName] || [])}
diff --git a/src/index.css b/src/index.css index 312dd4f..e63ae9b 100644 --- a/src/index.css +++ b/src/index.css @@ -117,36 +117,42 @@ Board styles margin-right: 0.5em; } -.kanbn-create-task-button { +.kanbn-column-button { position: relative; top: -2px; left: -4px; float: right; - border: 1px transparent solid; outline: none; - color: var(--vscode-foreground); + border: 1px transparent solid; background-color: transparent; + color: var(--vscode-button-foreground); padding: 2px; height: 16px; width: 16px; margin-right: 8px; - cursor: pointer; border-radius: 1px; } -.kanbn-create-task-button:focus { - border-color: var(--vscode-foreground); -} - -.kanbn-create-task-button:hover, .kanbn-create-task-button:active { - border: none; - outline: none; - color: var(--vscode-editor-background); - background-color: var(--vscode-foreground); -} - -.kanbn-create-task-button .codicon { +.kanbn-column-button .codicon { font-size: 11px !important; + font-weight: 900; +} + +.kanbn-column-button:focus { + border-color: var(--vscode-button-hoverBackground); +} + +.kanbn-column-button:hover, .kanbn-column-button:active { + background-color: var(--vscode-button-hoverBackground); +} + +.kanbn-column-button.kanbn-sort-column-button .codicon { + opacity: 0.5; + font-weight: normal; +} + +.kanbn-column-button.kanbn-sort-column-button.kanbn-column-sorted .codicon { + opacity: 1; } .kanbn-column-count {