Add filter field, fix validation
This commit is contained in:
parent
7ea93c6290
commit
63bf065331
@ -137,21 +137,29 @@ export default class KanbnTaskPanel {
|
|||||||
|
|
||||||
// Create a task
|
// Create a task
|
||||||
case 'kanbn.create':
|
case 'kanbn.create':
|
||||||
// TODO create task
|
// TODO convert dates
|
||||||
vscode.window.showInformationMessage('create task');
|
// await this._kanbn.createTask(message.taskData, message.taskData.column);
|
||||||
|
vscode.window.showInformationMessage(`Created task ${message.taskData.name}.`);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Update a task
|
// Update a task
|
||||||
case 'kanbn.update':
|
case 'kanbn.update':
|
||||||
// TODO update task
|
// TODO convert dates
|
||||||
vscode.window.showInformationMessage('update task');
|
// await this._kanbn.updateTask(message.taskData.id, message.taskData, message.taskData.column);
|
||||||
|
vscode.window.showInformationMessage(`Updated task ${message.taskData.name}.`);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Delete a task
|
// Delete a task
|
||||||
case 'kanbn.delete':
|
case 'kanbn.delete':
|
||||||
// TODO delete task
|
vscode.window.showInformationMessage(`Delete task ${message.taskData.name}?`, 'Yes', 'No').then(
|
||||||
// TODO add yes/no confirmation buttons to information message, then delete task and close task panel
|
async value => {
|
||||||
vscode.window.showInformationMessage('delete task');
|
if (value === 'Yes') {
|
||||||
|
// await this._kanbn.deleteTask(message.taskId, true);
|
||||||
|
vscode.window.showInformationMessage(`Deleted task ${message.taskData.name}.`);
|
||||||
|
// TODO close panel, will need to generate uuid for each panel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, null, this._disposables);
|
}, null, this._disposables);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import Header from './Header';
|
|
||||||
import Board from './Board';
|
import Board from './Board';
|
||||||
import TaskEditor from './TaskEditor';
|
import TaskEditor from './TaskEditor';
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
@ -53,19 +52,15 @@ function App() {
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{
|
{
|
||||||
type === 'index' &&
|
type === 'index' &&
|
||||||
<React.Fragment>
|
<Board
|
||||||
<Header
|
|
||||||
name={name}
|
name={name}
|
||||||
description={description}
|
description={description}
|
||||||
/>
|
|
||||||
<Board
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
startedColumns={startedColumns}
|
startedColumns={startedColumns}
|
||||||
completedColumns={completedColumns}
|
completedColumns={completedColumns}
|
||||||
dateFormat={dateFormat}
|
dateFormat={dateFormat}
|
||||||
vscode={vscode}
|
vscode={vscode}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
type === 'task' &&
|
type === 'task' &&
|
||||||
|
@ -55,7 +55,9 @@ const onDragEnd = (result, columns, setColumns, vscode: VSCodeApi) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode }: {
|
const Board = ({ name, description, columns, startedColumns, completedColumns, dateFormat, vscode }: {
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
columns: Record<string, KanbnTask[]>,
|
columns: Record<string, KanbnTask[]>,
|
||||||
startedColumns: string[],
|
startedColumns: string[],
|
||||||
completedColumns: string[],
|
completedColumns: string[],
|
||||||
@ -63,7 +65,34 @@ const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode }
|
|||||||
vscode: VSCodeApi
|
vscode: VSCodeApi
|
||||||
}) => {
|
}) => {
|
||||||
const [, setColumns] = useState(columns);
|
const [, setColumns] = useState(columns);
|
||||||
|
|
||||||
|
const filterTasks = () => {
|
||||||
|
console.log();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className="kanbn-header">
|
||||||
|
<h1 className="kanbn-header-name">
|
||||||
|
<p>{name}</p>
|
||||||
|
<div className="kanbn-filter">
|
||||||
|
<input
|
||||||
|
className="kanbn-filter-input"
|
||||||
|
placeholder="Filter tasks"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="kanbn-filter-button"
|
||||||
|
onClick={filterTasks}
|
||||||
|
>
|
||||||
|
<i className="codicon codicon-filter"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</h1>
|
||||||
|
<p className="kanbn-header-description">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div className="kanbn-board">
|
<div className="kanbn-board">
|
||||||
<DragDropContext
|
<DragDropContext
|
||||||
onDragEnd={result => onDragEnd(result, columns, setColumns, vscode)}
|
onDragEnd={result => onDragEnd(result, columns, setColumns, vscode)}
|
||||||
@ -131,6 +160,7 @@ const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode }
|
|||||||
})}
|
})}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
</div>
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
const Header = ({ name, description }: { name: string, description: string }) => {
|
|
||||||
return (
|
|
||||||
<div className="kanbn-header">
|
|
||||||
<h1 className="kanbn-header-name">{name}</h1>
|
|
||||||
<p className="kanbn-header-description">
|
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Header;
|
|
@ -46,11 +46,27 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, vscode }
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Called when the form is submitted
|
||||||
|
const handleSubmit = values => {
|
||||||
|
if (editing) {
|
||||||
|
vscode.postMessage({
|
||||||
|
command: 'kanbn.update',
|
||||||
|
taskData: values
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
vscode.postMessage({
|
||||||
|
command: 'kanbn.create',
|
||||||
|
taskData: values
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Called when the delete task button is clicked
|
// Called when the delete task button is clicked
|
||||||
const handleRemoveTask = () => {
|
const handleRemoveTask = values => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
command: 'kanbn.delete',
|
command: 'kanbn.delete',
|
||||||
taskId: task!.id
|
taskId: task!.id,
|
||||||
|
taskData: values
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,7 +110,8 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, vscode }
|
|||||||
subTasks: task ? task.subTasks : [],
|
subTasks: task ? task.subTasks : [],
|
||||||
comments: task ? task.comments : []
|
comments: task ? task.comments : []
|
||||||
}}
|
}}
|
||||||
validate={(values: KanbnTaskValidationInput): KanbnTaskValidationOutput => {
|
validate={(values: KanbnTaskValidationInput): KanbnTaskValidationOutput|{} => {
|
||||||
|
let hasErrors = false;
|
||||||
const errors: KanbnTaskValidationOutput = {
|
const errors: KanbnTaskValidationOutput = {
|
||||||
name: '',
|
name: '',
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -107,17 +124,20 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, vscode }
|
|||||||
// Task name cannot be empty
|
// Task name cannot be empty
|
||||||
if (!values.name) {
|
if (!values.name) {
|
||||||
errors.name = 'Task name is required.';
|
errors.name = 'Task name is required.';
|
||||||
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the id is already in use
|
// Check if the id is already in use
|
||||||
if (values.id in tasks && tasks[values.id].uuid !== values.uuid) {
|
if (values.id in tasks && tasks[values.id].uuid !== values.uuid) {
|
||||||
errors.name = 'There is already a task with the same name or id.';
|
errors.name = 'There is already a task with the same name or id.';
|
||||||
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag names cannot be empty
|
// Tag names cannot be empty
|
||||||
for (let i = 0; i < values.metadata.tags.length; i++) {
|
for (let i = 0; i < values.metadata.tags.length; i++) {
|
||||||
if (!values.metadata.tags[i]) {
|
if (!values.metadata.tags[i]) {
|
||||||
errors.metadata.tags[i] = 'Tag cannot be empty.';
|
errors.metadata.tags[i] = 'Tag cannot be empty.';
|
||||||
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +147,7 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, vscode }
|
|||||||
errors.subTasks[i] = {
|
errors.subTasks[i] = {
|
||||||
text: 'Sub-task text cannot be empty.'
|
text: 'Sub-task text cannot be empty.'
|
||||||
};
|
};
|
||||||
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,22 +157,14 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, vscode }
|
|||||||
errors.comments[i] = {
|
errors.comments[i] = {
|
||||||
text: 'Comment text cannot be empty.'
|
text: 'Comment text cannot be empty.'
|
||||||
};
|
};
|
||||||
|
hasErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
return hasErrors ? errors : {};
|
||||||
}}
|
}}
|
||||||
onSubmit={(values, { setSubmitting }) => {
|
onSubmit={(values, { setSubmitting }) => {
|
||||||
if (editing) {
|
handleSubmit(values);
|
||||||
vscode.postMessage({
|
|
||||||
command: 'kanbn.update'
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
vscode.postMessage({
|
|
||||||
command: 'kanbn.create'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log(values);
|
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -385,7 +398,9 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, vscode }
|
|||||||
type="button"
|
type="button"
|
||||||
className="kanbn-task-editor-button kanbn-task-editor-button-delete"
|
className="kanbn-task-editor-button kanbn-task-editor-button-delete"
|
||||||
title="Delete task"
|
title="Delete task"
|
||||||
onClick={handleRemoveTask}
|
onClick={() => {
|
||||||
|
handleRemoveTask(values);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<i className="codicon codicon-trash"></i>Delete
|
<i className="codicon codicon-trash"></i>Delete
|
||||||
</button>}
|
</button>}
|
||||||
|
@ -12,6 +12,51 @@ body {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
padding-bottom: 0.5em;
|
padding-bottom: 0.5em;
|
||||||
border-bottom: 1px var(--vscode-activityBar-inactiveForeground) solid;
|
border-bottom: 1px var(--vscode-activityBar-inactiveForeground) solid;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-header-name p {
|
||||||
|
display: inline-block;
|
||||||
|
flex: 1;
|
||||||
|
margin: 0;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-filter {
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-filter-input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 80%;
|
||||||
|
padding: 8px;
|
||||||
|
background-color: var(--vscode-input-background);
|
||||||
|
color: var(--vscode-input-foreground);
|
||||||
|
border: 1px transparent solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-filter-input:hover, .kanbn-filter-input:focus {
|
||||||
|
border-color: var(--vscode-input-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-filter-button {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
background-color: var(--vscode-button-background);
|
||||||
|
color: var(--vscode-button-foreground);
|
||||||
|
padding: 9px 1em;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-filter-button .codicon {
|
||||||
|
font-size: 11px !important;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kanbn-filter-button:hover, .kanbn-filter-button:focus {
|
||||||
|
background-color: var(--vscode-button-hoverBackground);
|
||||||
}
|
}
|
||||||
|
|
||||||
.kanbn-board {
|
.kanbn-board {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user