Add column sorting
This commit is contained in:
		| @ -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-{Column name in snake-case}` | ||||||
| - `kanbn-column-name` | - `kanbn-column-name` | ||||||
| - `kanbn-column-count` | - `kanbn-column-count` | ||||||
|  | - `kanbn-column-button` | ||||||
| - `kanbn-create-task-button` | - `kanbn-create-task-button` | ||||||
|  | - `kanbn-sort-column-button` | ||||||
|  | - `kanbn-column-sorted` | ||||||
| - `kanbn-column-task-list-container` | - `kanbn-column-task-list-container` | ||||||
| - `kanbn-column-task-list` | - `kanbn-column-task-list` | ||||||
| - `kanbn-column-task-list.drag-over` | - `kanbn-column-task-list.drag-over` | ||||||
|  | |||||||
| @ -4,6 +4,21 @@ import getNonce from "./getNonce"; | |||||||
| import KanbnTaskPanel from "./KanbnTaskPanel"; | import KanbnTaskPanel from "./KanbnTaskPanel"; | ||||||
| import KanbnBurndownPanel from "./KanbnBurndownPanel"; | 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 { | export default class KanbnBoardPanel { | ||||||
|   public static currentPanel: KanbnBoardPanel | undefined; |   public static currentPanel: KanbnBoardPanel | undefined; | ||||||
|  |  | ||||||
| @ -63,6 +78,7 @@ export default class KanbnBoardPanel { | |||||||
|         hiddenColumns: index.options.hiddenColumns ?? [], |         hiddenColumns: index.options.hiddenColumns ?? [], | ||||||
|         startedColumns: index.options.startedColumns ?? [], |         startedColumns: index.options.startedColumns ?? [], | ||||||
|         completedColumns: index.options.completedColumns ?? [], |         completedColumns: index.options.completedColumns ?? [], | ||||||
|  |         columnSorting: index.options.columnSorting ?? {}, | ||||||
|         dateFormat: KanbnBoardPanel.currentPanel._kanbn.getDateFormat(index), |         dateFormat: KanbnBoardPanel.currentPanel._kanbn.getDateFormat(index), | ||||||
|         showBurndownButton: vscode.workspace.getConfiguration("kanbn").get("showBurndownButton"), |         showBurndownButton: vscode.workspace.getConfiguration("kanbn").get("showBurndownButton"), | ||||||
|         showSprintButton: vscode.workspace.getConfiguration("kanbn").get("showSprintButton"), |         showSprintButton: vscode.workspace.getConfiguration("kanbn").get("showSprintButton"), | ||||||
| @ -157,6 +173,74 @@ export default class KanbnBoardPanel { | |||||||
|             ); |             ); | ||||||
|             return; |             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 |           // Open a burndown chart | ||||||
|           case "kanbn.burndown": |           case "kanbn.burndown": | ||||||
|             KanbnBurndownPanel.createOrShow( |             KanbnBurndownPanel.createOrShow( | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ function App() { | |||||||
|   const [hiddenColumns, setHiddenColumns] = useState([]); |   const [hiddenColumns, setHiddenColumns] = useState([]); | ||||||
|   const [startedColumns, setStartedColumns] = useState([]); |   const [startedColumns, setStartedColumns] = useState([]); | ||||||
|   const [completedColumns, setCompletedColumns] = useState([]); |   const [completedColumns, setCompletedColumns] = useState([]); | ||||||
|  |   const [columnSorting, setColumnSorting] = useState({}); | ||||||
|   const [dateFormat, setDateFormat] = useState(''); |   const [dateFormat, setDateFormat] = useState(''); | ||||||
|   const [task, setTask] = useState({}); |   const [task, setTask] = useState({}); | ||||||
|   const [tasks, setTasks] = useState({}); |   const [tasks, setTasks] = useState({}); | ||||||
| @ -46,6 +47,7 @@ function App() { | |||||||
|         setHiddenColumns(event.data.hiddenColumns); |         setHiddenColumns(event.data.hiddenColumns); | ||||||
|         setStartedColumns(event.data.startedColumns); |         setStartedColumns(event.data.startedColumns); | ||||||
|         setCompletedColumns(event.data.completedColumns); |         setCompletedColumns(event.data.completedColumns); | ||||||
|  |         setColumnSorting(event.data.columnSorting); | ||||||
|         setShowBurndownButton(event.data.showBurndownButton); |         setShowBurndownButton(event.data.showBurndownButton); | ||||||
|         setShowSprintButton(event.data.showSprintButton); |         setShowSprintButton(event.data.showSprintButton); | ||||||
|  |  | ||||||
| @ -98,6 +100,7 @@ function App() { | |||||||
|           hiddenColumns={hiddenColumns} |           hiddenColumns={hiddenColumns} | ||||||
|           startedColumns={startedColumns} |           startedColumns={startedColumns} | ||||||
|           completedColumns={completedColumns} |           completedColumns={completedColumns} | ||||||
|  |           columnSorting={columnSorting} | ||||||
|           dateFormat={dateFormat} |           dateFormat={dateFormat} | ||||||
|           showBurndownButton={showBurndownButton} |           showBurndownButton={showBurndownButton} | ||||||
|           showSprintButton={showSprintButton} |           showSprintButton={showSprintButton} | ||||||
|  | |||||||
| @ -139,6 +139,7 @@ const Board = ({ | |||||||
|   hiddenColumns, |   hiddenColumns, | ||||||
|   startedColumns, |   startedColumns, | ||||||
|   completedColumns, |   completedColumns, | ||||||
|  |   columnSorting, | ||||||
|   dateFormat, |   dateFormat, | ||||||
|   showBurndownButton, |   showBurndownButton, | ||||||
|   showSprintButton, |   showSprintButton, | ||||||
| @ -151,6 +152,7 @@ const Board = ({ | |||||||
|   hiddenColumns: string[], |   hiddenColumns: string[], | ||||||
|   startedColumns: string[], |   startedColumns: string[], | ||||||
|   completedColumns: string[], |   completedColumns: string[], | ||||||
|  |   columnSorting: { [columnName: string]: { field: string, order: 'ascending' | 'descending' }[] }, | ||||||
|   dateFormat: string, |   dateFormat: string, | ||||||
|   showBurndownButton: boolean, |   showBurndownButton: boolean, | ||||||
|   showSprintButton: boolean, |   showSprintButton: boolean, | ||||||
| @ -274,7 +276,7 @@ const Board = ({ | |||||||
|                   <span className="kanbn-column-count">{column.length || ''}</span> |                   <span className="kanbn-column-count">{column.length || ''}</span> | ||||||
|                   <button |                   <button | ||||||
|                     type="button" |                     type="button" | ||||||
|                     className="kanbn-create-task-button" |                     className="kanbn-column-button kanbn-create-task-button" | ||||||
|                     title={`Create task in ${columnName}`} |                     title={`Create task in ${columnName}`} | ||||||
|                     onClick={() => { |                     onClick={() => { | ||||||
|                       vscode.postMessage({ |                       vscode.postMessage({ | ||||||
| @ -285,6 +287,30 @@ const Board = ({ | |||||||
|                   > |                   > | ||||||
|                     <i className="codicon codicon-add"></i> |                     <i className="codicon codicon-add"></i> | ||||||
|                   </button> |                   </button> | ||||||
|  |                   {((columnIsSorted, columnSortSettings) => ( | ||||||
|  |                     <button | ||||||
|  |                       type="button" | ||||||
|  |                       className={[ | ||||||
|  |                         'kanbn-column-button', | ||||||
|  |                         'kanbn-sort-column-button', | ||||||
|  |                         columnIsSorted ? 'kanbn-column-sorted' : null | ||||||
|  |                       ].filter(i => i).join(' ')} | ||||||
|  |                       title={`Sort ${columnName}${columnIsSorted | ||||||
|  |                         ? `\nCurrently sorted by:\n${columnSortSettings.map( | ||||||
|  |                           sorter => `${sorter.field} (${sorter.order})` | ||||||
|  |                         ).join('\n')}` | ||||||
|  |                         : '' | ||||||
|  |                       }`} | ||||||
|  |                       onClick={() => { | ||||||
|  |                         vscode.postMessage({ | ||||||
|  |                           command: 'kanbn.sortColumn', | ||||||
|  |                           columnName | ||||||
|  |                         }); | ||||||
|  |                       }} | ||||||
|  |                     > | ||||||
|  |                       <i className="codicon codicon-list-filter"></i> | ||||||
|  |                     </button> | ||||||
|  |                   ))(columnName in columnSorting, columnSorting[columnName] || [])} | ||||||
|                 </h2> |                 </h2> | ||||||
|                 <div className="kanbn-column-task-list-container"> |                 <div className="kanbn-column-task-list-container"> | ||||||
|                   <Droppable droppableId={columnName} key={columnName}> |                   <Droppable droppableId={columnName} key={columnName}> | ||||||
|  | |||||||
| @ -117,36 +117,42 @@ Board styles | |||||||
|     margin-right: 0.5em; |     margin-right: 0.5em; | ||||||
| } | } | ||||||
|  |  | ||||||
| .kanbn-create-task-button { | .kanbn-column-button { | ||||||
|     position: relative; |     position: relative; | ||||||
|     top: -2px; |     top: -2px; | ||||||
|     left: -4px; |     left: -4px; | ||||||
|     float: right; |     float: right; | ||||||
|     border: 1px transparent solid; |  | ||||||
|     outline: none; |     outline: none; | ||||||
|     color: var(--vscode-foreground); |     border: 1px transparent solid; | ||||||
|     background-color: transparent; |     background-color: transparent; | ||||||
|  |     color: var(--vscode-button-foreground); | ||||||
|     padding: 2px; |     padding: 2px; | ||||||
|     height: 16px; |     height: 16px; | ||||||
|     width: 16px; |     width: 16px; | ||||||
|     margin-right: 8px; |     margin-right: 8px; | ||||||
|     cursor: pointer; |  | ||||||
|     border-radius: 1px; |     border-radius: 1px; | ||||||
| } | } | ||||||
|  |  | ||||||
| .kanbn-create-task-button:focus { | .kanbn-column-button .codicon { | ||||||
|     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 { |  | ||||||
|     font-size: 11px !important; |     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 { | .kanbn-column-count { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user