Custom field editing
This commit is contained in:
parent
0aa5776af3
commit
026fbf95cd
@ -129,6 +129,9 @@ Here's an example of a task card style using some of the above features:
|
|||||||
- `kanbn-task-editor-field-label`
|
- `kanbn-task-editor-field-label`
|
||||||
- `kanbn-task-editor-field-label-description`
|
- `kanbn-task-editor-field-label-description`
|
||||||
- `kanbn-task-editor-field-input`
|
- `kanbn-task-editor-field-input`
|
||||||
|
- `kanbn-task-editor-custom-field`
|
||||||
|
- `kanbn-task-editor-custom-field-{Custom field name in param-case}`
|
||||||
|
- `kanbn-task-editor-custom-checkbox`
|
||||||
- `kanbn-task-editor-id`
|
- `kanbn-task-editor-id`
|
||||||
- `kanbn-task-editor-description-preview`
|
- `kanbn-task-editor-description-preview`
|
||||||
- `kanbn-task-editor-button-edit-description`
|
- `kanbn-task-editor-button-edit-description`
|
||||||
@ -145,6 +148,7 @@ Here's an example of a task card style using some of the above features:
|
|||||||
- `kanbn-task-editor-button`
|
- `kanbn-task-editor-button`
|
||||||
- `kanbn-task-editor-button-delete`
|
- `kanbn-task-editor-button-delete`
|
||||||
- `kanbn-task-editor-buttons`
|
- `kanbn-task-editor-buttons`
|
||||||
|
- `kanbn-task-editor-main-buttons`
|
||||||
- `kanbn-task-editor-button-add`
|
- `kanbn-task-editor-button-add`
|
||||||
- `kanbn-task-editor-button-edit`
|
- `kanbn-task-editor-button-edit`
|
||||||
- `kanbn-task-editor-field-relations`
|
- `kanbn-task-editor-field-relations`
|
||||||
|
@ -3,7 +3,10 @@ import * as vscode from "vscode";
|
|||||||
import getNonce from "./getNonce";
|
import getNonce from "./getNonce";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
function transformTaskData(taskData: any) {
|
function transformTaskData(
|
||||||
|
taskData: any,
|
||||||
|
customFields: { name: string, type: 'boolean' | 'date' | 'number' | 'string'}[]
|
||||||
|
) {
|
||||||
const result = {
|
const result = {
|
||||||
id: taskData.id,
|
id: taskData.id,
|
||||||
name: taskData.name,
|
name: taskData.name,
|
||||||
@ -50,6 +53,17 @@ function transformTaskData(taskData: any) {
|
|||||||
result.metadata["completed"] = new Date(Date.parse(taskData.metadata.completed));
|
result.metadata["completed"] = new Date(Date.parse(taskData.metadata.completed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add custom fields
|
||||||
|
for (let customField of customFields) {
|
||||||
|
if (customField.name in taskData.metadata && taskData.metadata[customField.name] !== null) {
|
||||||
|
if (customField.type === 'date') {
|
||||||
|
result.metadata[customField.name] = new Date(Date.parse(taskData.metadata[customField.name]));
|
||||||
|
} else {
|
||||||
|
result.metadata[customField.name] = taskData.metadata[customField.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +176,10 @@ export default class KanbnTaskPanel {
|
|||||||
|
|
||||||
// Create a task
|
// Create a task
|
||||||
case "kanbn.create":
|
case "kanbn.create":
|
||||||
await this._kanbn.createTask(transformTaskData(message.taskData), message.taskData.column);
|
await this._kanbn.createTask(
|
||||||
|
transformTaskData(message.taskData, message.customFields),
|
||||||
|
message.taskData.column
|
||||||
|
);
|
||||||
KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id;
|
KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id;
|
||||||
KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column;
|
KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column;
|
||||||
KanbnTaskPanel.panels[message.panelUuid].update();
|
KanbnTaskPanel.panels[message.panelUuid].update();
|
||||||
@ -173,7 +190,11 @@ export default class KanbnTaskPanel {
|
|||||||
|
|
||||||
// Update a task
|
// Update a task
|
||||||
case "kanbn.update":
|
case "kanbn.update":
|
||||||
await this._kanbn.updateTask(message.taskId, transformTaskData(message.taskData), message.taskData.column);
|
await this._kanbn.updateTask(
|
||||||
|
message.taskId,
|
||||||
|
transformTaskData(message.taskData, message.customFields),
|
||||||
|
message.taskData.column
|
||||||
|
);
|
||||||
KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id;
|
KanbnTaskPanel.panels[message.panelUuid]._taskId = message.taskData.id;
|
||||||
KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column;
|
KanbnTaskPanel.panels[message.panelUuid]._columnName = message.taskData.column;
|
||||||
KanbnTaskPanel.panels[message.panelUuid].update();
|
KanbnTaskPanel.panels[message.panelUuid].update();
|
||||||
@ -258,6 +279,7 @@ export default class KanbnTaskPanel {
|
|||||||
index,
|
index,
|
||||||
task,
|
task,
|
||||||
tasks,
|
tasks,
|
||||||
|
customFields: index.options.customFields ?? [],
|
||||||
columnName: this._columnName,
|
columnName: this._columnName,
|
||||||
dateFormat: this._kanbn.getDateFormat(index),
|
dateFormat: this._kanbn.getDateFormat(index),
|
||||||
panelUuid: this._panelUuid,
|
panelUuid: this._panelUuid,
|
||||||
|
@ -66,6 +66,7 @@ function App() {
|
|||||||
setTasks(tasks);
|
setTasks(tasks);
|
||||||
setColumnName(event.data.columnName);
|
setColumnName(event.data.columnName);
|
||||||
setColumnNames(Object.keys(event.data.index.columns));
|
setColumnNames(Object.keys(event.data.index.columns));
|
||||||
|
setCustomFields(event.data.customFields);
|
||||||
setPanelUuid(event.data.panelUuid);
|
setPanelUuid(event.data.panelUuid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -118,6 +119,7 @@ function App() {
|
|||||||
tasks={tasks}
|
tasks={tasks}
|
||||||
columnName={columnName}
|
columnName={columnName}
|
||||||
columnNames={columnNames}
|
columnNames={columnNames}
|
||||||
|
customFields={customFields}
|
||||||
dateFormat={dateFormat}
|
dateFormat={dateFormat}
|
||||||
panelUuid={panelUuid}
|
panelUuid={panelUuid}
|
||||||
vscode={vscode}
|
vscode={vscode}
|
||||||
|
@ -53,11 +53,12 @@ const Markdown = props => (<ReactMarkdown {...{
|
|||||||
...props,
|
...props,
|
||||||
}} />);
|
}} />);
|
||||||
|
|
||||||
const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUuid, vscode }: {
|
const TaskEditor = ({ task, tasks, columnName, columnNames, customFields, dateFormat, panelUuid, vscode }: {
|
||||||
task: KanbnTask | null,
|
task: KanbnTask | null,
|
||||||
tasks: Record<string, KanbnTask>,
|
tasks: Record<string, KanbnTask>,
|
||||||
columnName: string,
|
columnName: string,
|
||||||
columnNames: string[],
|
columnNames: string[],
|
||||||
|
customFields: { name: string, type: 'boolean' | 'date' | 'number' | 'string' }[],
|
||||||
dateFormat: string,
|
dateFormat: string,
|
||||||
panelUuid: string,
|
panelUuid: string,
|
||||||
vscode: VSCodeApi
|
vscode: VSCodeApi
|
||||||
@ -76,7 +77,17 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
due: (task && 'due' in task.metadata) ? formatDate(task.metadata.due!, 'yyyy-mm-dd') : '',
|
due: (task && 'due' in task.metadata) ? formatDate(task.metadata.due!, 'yyyy-mm-dd') : '',
|
||||||
completed: (task && 'completed' in task.metadata) ? formatDate(task.metadata.completed!, 'yyyy-mm-dd') : '',
|
completed: (task && 'completed' in task.metadata) ? formatDate(task.metadata.completed!, 'yyyy-mm-dd') : '',
|
||||||
assigned: (task && 'assigned' in task.metadata) ? task.metadata.assigned : (gitUsername() || ''),
|
assigned: (task && 'assigned' in task.metadata) ? task.metadata.assigned : (gitUsername() || ''),
|
||||||
tags: (task && 'tags' in task.metadata) ? (task.metadata.tags || []) : []
|
tags: (task && 'tags' in task.metadata) ? (task.metadata.tags || []) : [],
|
||||||
|
...Object.fromEntries(
|
||||||
|
customFields.map(customField => [
|
||||||
|
customField.name,
|
||||||
|
(task && customField.name in task.metadata)
|
||||||
|
? (customField.type === 'date'
|
||||||
|
? formatDate(task.metadata[customField.name], 'yyyy-mm-dd')
|
||||||
|
: task.metadata[customField.name]
|
||||||
|
) : null,
|
||||||
|
]),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
relations: task ? task.relations : [],
|
relations: task ? task.relations : [],
|
||||||
subTasks: task ? task.subTasks : [],
|
subTasks: task ? task.subTasks : [],
|
||||||
@ -112,12 +123,14 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
command: 'kanbn.update',
|
command: 'kanbn.update',
|
||||||
taskId: task!.id,
|
taskId: task!.id,
|
||||||
taskData: values,
|
taskData: values,
|
||||||
|
customFields,
|
||||||
panelUuid
|
panelUuid
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
command: 'kanbn.create',
|
command: 'kanbn.create',
|
||||||
taskData: values,
|
taskData: values,
|
||||||
|
customFields,
|
||||||
panelUuid
|
panelUuid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -224,10 +237,41 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
handleChange,
|
handleChange,
|
||||||
isSubmitting
|
isSubmitting
|
||||||
}) => (
|
}) => (
|
||||||
<React.Fragment>
|
<Form>
|
||||||
<h1 className="kanbn-task-editor-title">
|
<h1 className="kanbn-task-editor-title">
|
||||||
{editing ? 'Update task' : 'Create new task'}
|
{editing ? 'Update task' : 'Create new task'}
|
||||||
{dirty && <span className="kanbn-task-editor-dirty">*</span>}
|
{dirty && <span className="kanbn-task-editor-dirty">*</span>}
|
||||||
|
</h1>
|
||||||
|
<div className="kanbn-task-editor-buttons kanbn-task-editor-main-buttons">
|
||||||
|
{editing && <button
|
||||||
|
type="button"
|
||||||
|
className="kanbn-task-editor-button kanbn-task-editor-button-delete"
|
||||||
|
title="Delete task"
|
||||||
|
onClick={() => {
|
||||||
|
handleRemoveTask(values);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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"
|
||||||
|
title="Save task"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
<i className="codicon codicon-save"></i>Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{editing && <span className="kanbn-task-editor-dates">
|
{editing && <span className="kanbn-task-editor-dates">
|
||||||
{
|
{
|
||||||
[
|
[
|
||||||
@ -236,8 +280,6 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
].filter(i => i).join(', ')
|
].filter(i => i).join(', ')
|
||||||
}
|
}
|
||||||
</span>}
|
</span>}
|
||||||
</h1>
|
|
||||||
<Form>
|
|
||||||
<div className="kanbn-task-editor-form">
|
<div className="kanbn-task-editor-form">
|
||||||
<div className="kanbn-task-editor-column-left">
|
<div className="kanbn-task-editor-column-left">
|
||||||
<div className="kanbn-task-editor-field kanbn-task-editor-field-name">
|
<div className="kanbn-task-editor-field kanbn-task-editor-field-name">
|
||||||
@ -511,36 +553,6 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="kanbn-task-editor-column-right">
|
<div className="kanbn-task-editor-column-right">
|
||||||
<div className="kanbn-task-editor-buttons">
|
|
||||||
{editing && <button
|
|
||||||
type="button"
|
|
||||||
className="kanbn-task-editor-button kanbn-task-editor-button-delete"
|
|
||||||
title="Delete task"
|
|
||||||
onClick={() => {
|
|
||||||
handleRemoveTask(values);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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"
|
|
||||||
title="Save task"
|
|
||||||
disabled={isSubmitting}
|
|
||||||
>
|
|
||||||
<i className="codicon codicon-save"></i>Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="kanbn-task-editor-field kanbn-task-editor-field-column">
|
<div className="kanbn-task-editor-field kanbn-task-editor-field-column">
|
||||||
<label className="kanbn-task-editor-field-label">
|
<label className="kanbn-task-editor-field-label">
|
||||||
<p>Column</p>
|
<p>Column</p>
|
||||||
@ -642,6 +654,45 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
name="progress"
|
name="progress"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{
|
||||||
|
customFields.map(customField => (
|
||||||
|
<div className={[
|
||||||
|
'kanbn-task-editor-field kanbn-task-editor-custom-field',
|
||||||
|
`kanbn-task-editor-custom-field-${paramCase(customField.name)}`
|
||||||
|
].join(' ')}>
|
||||||
|
<label className="kanbn-task-editor-field-label">
|
||||||
|
{customField.type === 'boolean'
|
||||||
|
? (
|
||||||
|
<>
|
||||||
|
<Field
|
||||||
|
className="kanbn-task-editor-field-input kanbn-task-editor-custom-checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
name={`metadata.${customField.name}`}
|
||||||
|
/><p>{customField.name}</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p>{customField.name}</p>
|
||||||
|
<Field
|
||||||
|
className="kanbn-task-editor-field-input"
|
||||||
|
type={{
|
||||||
|
date: 'date',
|
||||||
|
number: 'number',
|
||||||
|
string: 'text',
|
||||||
|
}[customField.type]}
|
||||||
|
name={`metadata.${customField.name}`}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
<ErrorMessage
|
||||||
|
className="kanbn-task-editor-field-errors"
|
||||||
|
component="div"
|
||||||
|
name={`metadata.${customField.name}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
<div className="kanbn-task-editor-field kanbn-task-editor-field-tags">
|
<div className="kanbn-task-editor-field kanbn-task-editor-field-tags">
|
||||||
<label className="kanbn-task-editor-field-label">
|
<label className="kanbn-task-editor-field-label">
|
||||||
<p>Tags</p>
|
<p>Tags</p>
|
||||||
@ -701,7 +752,6 @@ const TaskEditor = ({ task, tasks, columnName, columnNames, dateFormat, panelUui
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</React.Fragment>
|
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,7 +102,9 @@ const TaskItem = ({ task, columnName, customFields, position, dateFormat, vscode
|
|||||||
<>
|
<>
|
||||||
<i className="codicon codicon-json"></i>
|
<i className="codicon codicon-json"></i>
|
||||||
<span title={customField.name}>
|
<span title={customField.name}>
|
||||||
{task.metadata[customField.name]}
|
{customField.type === 'date'
|
||||||
|
? formatDate(task.metadata[customField.name], dateFormat)
|
||||||
|
: task.metadata[customField.name]}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -351,10 +351,9 @@ Task editor styles
|
|||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
.kanbn-task-editor-title {
|
.kanbn-task-editor-title {
|
||||||
|
display: inline-block;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
padding-bottom: 0.5em;
|
|
||||||
border-bottom: 1px var(--vscode-activityBar-inactiveForeground) solid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.kanbn-task-editor-dirty {
|
.kanbn-task-editor-dirty {
|
||||||
@ -368,10 +367,12 @@ Task editor styles
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
float: right;
|
float: right;
|
||||||
|
margin: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kanbn-task-editor-form {
|
.kanbn-task-editor-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
border-top: 1px solid var(--vscode-activityBar-inactiveForeground);
|
||||||
}
|
}
|
||||||
|
|
||||||
.kanbn-task-editor-field .kanbn-task-editor-title,
|
.kanbn-task-editor-field .kanbn-task-editor-title,
|
||||||
@ -439,6 +440,12 @@ body.vscode-dark .kanbn-task-editor-field-input[type="date"]::-webkit-calendar-p
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kanbn-task-editor-main-buttons {
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
.kanbn-task-editor-button {
|
.kanbn-task-editor-button {
|
||||||
outline: none;
|
outline: none;
|
||||||
border: 1px transparent solid;
|
border: 1px transparent solid;
|
||||||
@ -602,6 +609,14 @@ body.vscode-dark .kanbn-task-editor-field-input[type="date"]::-webkit-calendar-p
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kanbn-task-editor-custom-checkbox {
|
||||||
|
float: left;
|
||||||
|
width: auto;
|
||||||
|
position: relative;
|
||||||
|
top: -.2em;
|
||||||
|
margin: .5em 1em .5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
Burndown chart styles
|
Burndown chart styles
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user