Edit and Add Actions dummy implementation
This commit is contained in:
parent
f5a3e8e9f8
commit
5a84a00f54
|
@ -5,4 +5,9 @@ export interface IKanbanBoardRenderers{
|
|||
task?: (task:IKanbanTask) => JSX.Element ;
|
||||
bucketHeadline?: (bucket:IKanbanBucket) => JSX.Element ;
|
||||
taskDetail?: (task:IKanbanTask) => JSX.Element ;
|
||||
/*
|
||||
its an action not a renderer
|
||||
taskEdit?: (task:IKanbanTask) => JSX.Element ;
|
||||
taskAdd?: (bucket?:IKanbanBucket) => JSX.Element ;
|
||||
*/
|
||||
}
|
|
@ -1,8 +1,18 @@
|
|||
import { IKanbanBucket } from "./IKanbanBucket";
|
||||
import { IKanbanTask } from "./IKanbanTask";
|
||||
|
||||
export interface IKanbanBoardTaskActions {
|
||||
|
||||
toggleCompleted?: (taskId: string) => void;
|
||||
allowMove?: (taskId: string, prevBucket: IKanbanBucket, targetBucket: IKanbanBucket) => boolean;
|
||||
moved?: (taskId: string, targetBucket: IKanbanBucket) => void;
|
||||
/* think about Await???
|
||||
*/
|
||||
addTaskSaved?: (task: IKanbanTask) => void;
|
||||
editTaskSaved?: (task: IKanbanTask) => void;
|
||||
//deleteTask?: (task: IKanbanTask) => void;
|
||||
|
||||
taskEdit?: (task:IKanbanTask) => void ;
|
||||
taskAdd?: (bucket?:IKanbanBucket) => void ;
|
||||
|
||||
}
|
|
@ -15,13 +15,16 @@ export interface IKanbanTaskManagedProps {
|
|||
renderer?: (name: string, value: object, type:KanbanTaskMamagedPropertyType) => JSX.Element;
|
||||
}
|
||||
|
||||
/* 0 is bad because
|
||||
const value = EnumType.xyz // = 0
|
||||
if(value) {is false}
|
||||
*/
|
||||
export enum KanbanTaskMamagedPropertyType {
|
||||
|
||||
string,
|
||||
number,
|
||||
percent,
|
||||
html,
|
||||
person,
|
||||
persons,
|
||||
complex
|
||||
string=1,
|
||||
number=2,
|
||||
percent=3,
|
||||
html=4,
|
||||
person=5,
|
||||
persons=6,
|
||||
complex=7
|
||||
}
|
|
@ -13,7 +13,10 @@ import * as strings from 'KanbanBoardStrings';
|
|||
export interface IKanbanBucketProps extends IKanbanBucket {
|
||||
buckettasks: IKanbanTask[];
|
||||
tasksettings: IKanbanBoardTaskSettings;
|
||||
taskactions: IKanbanBoardTaskActions;
|
||||
|
||||
|
||||
toggleCompleted?: (taskId: string) => void;
|
||||
addTask?: (bucket: string) => void;
|
||||
|
||||
onDragStart: (event, taskId: string, bucket: string) => void;
|
||||
onDragOver: (event, targetbucket: string) => void;
|
||||
|
@ -50,7 +53,7 @@ export default class KanbanBucket extends React.Component<IKanbanBucketProps, IK
|
|||
*/
|
||||
public render(): React.ReactElement<IKanbanBucketProps> {
|
||||
const { bucket, bucketheadline, color, buckettasks,
|
||||
tasksettings, taskactions, percentageComplete,
|
||||
tasksettings, percentageComplete,
|
||||
allowAddTask, overBucket, leavingTaskId, leavingBucket } = this.props;
|
||||
|
||||
return (
|
||||
|
@ -71,19 +74,20 @@ export default class KanbanBucket extends React.Component<IKanbanBucketProps, IK
|
|||
{allowAddTask && (<ActionButton
|
||||
iconProps={{ iconName: 'Add' }}
|
||||
allowDisabledFocus={true}
|
||||
|
||||
onClick={() => this.props.addTask(bucket)}
|
||||
>
|
||||
{strings.AddTask}
|
||||
</ActionButton>)}
|
||||
{
|
||||
buckettasks.map((t) => {
|
||||
const merge = { ...t, ...tasksettings, ...taskactions };
|
||||
const merge = { ...t, ...tasksettings, };
|
||||
const isMoving = (t.taskId === leavingTaskId && t.bucket === leavingBucket);
|
||||
|
||||
return (<div className={isMoving ? styles.placeholder : undefined} key={'' + t.taskId} >
|
||||
<KanbanTask
|
||||
key={'task' + t.taskId}
|
||||
{...merge}
|
||||
toggleCompleted={this.props.toggleCompleted}
|
||||
isMoving={isMoving}
|
||||
openDetails={this.props.openDetails}
|
||||
onDragStart={(event) => this.props.onDragStart(event, t.taskId, t.bucket)}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import styles from './KanbanComponent.module.scss';
|
||||
import * as strings from 'KanbanBoardStrings';
|
||||
|
||||
import { IKanbanTask } from './IKanbanTask';
|
||||
import { IKanbanBoardTaskSettings } from './IKanbanBoardTaskSettings';
|
||||
import { IKanbanBoardTaskActions } from './IKanbanBoardTaskActions';
|
||||
|
@ -11,11 +13,11 @@ import KanbanTaskManagedProp from './KanbanTaskManagedProp';
|
|||
import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
|
||||
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import { IStackStyles, Stack } from 'office-ui-fabric-react/lib/Stack';
|
||||
|
||||
|
||||
|
||||
import { clone } from '@microsoft/sp-lodash-subset';
|
||||
|
||||
import { CommandBar } from 'office-ui-fabric-react/lib/CommandBar';
|
||||
import { stringIsNullOrEmpty } from '@pnp/common';
|
||||
import { TooltipHost } from 'office-ui-fabric-react';
|
||||
|
||||
export interface IKanbanComponentProps {
|
||||
buckets: IKanbanBucket[];
|
||||
|
@ -24,6 +26,9 @@ export interface IKanbanComponentProps {
|
|||
taskactions: IKanbanBoardTaskActions;
|
||||
showCommandbar?: boolean;
|
||||
renderers?: IKanbanBoardRenderers;
|
||||
allowEdit?: boolean;
|
||||
allowAdd?: boolean;
|
||||
editSchema?: boolean;
|
||||
/*
|
||||
showCommandbarNew: boolean;
|
||||
allowDialog: boolean; TODO im mock
|
||||
|
@ -36,6 +41,15 @@ export interface IKanbanComponentState {
|
|||
overBucket?: string;
|
||||
openDialog: boolean;
|
||||
openTaskId?: string;
|
||||
dialogState?: DialogState;
|
||||
editTask?: IKanbanTask;
|
||||
addBucket?: IKanbanBucket;
|
||||
}
|
||||
|
||||
export enum DialogState {
|
||||
New = 1,
|
||||
Edit = 2,
|
||||
Display = 3
|
||||
}
|
||||
|
||||
export default class KanbanComponent extends React.Component<IKanbanComponentProps, IKanbanComponentState> {
|
||||
|
@ -55,7 +69,11 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
public render(): React.ReactElement<IKanbanComponentProps> {
|
||||
const { buckets, tasks, tasksettings, taskactions, showCommandbar } = this.props;
|
||||
const { openDialog } = this.state;
|
||||
const { leavingBucket, leavingTaskId, overBucket } = this.state
|
||||
const { leavingBucket, leavingTaskId, overBucket } = this.state;
|
||||
const wrappedTaskActions: IKanbanBoardTaskActions = {
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{showCommandbar && <CommandBar
|
||||
|
@ -74,8 +92,12 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
{...merge}
|
||||
buckettasks={tasks.filter((x) => x.bucket == b.bucket)}
|
||||
tasksettings={tasksettings}
|
||||
taskactions={taskactions}
|
||||
openDetails={this.openDialog.bind(this)}
|
||||
|
||||
toggleCompleted={this.props.taskactions && this.props.taskactions.toggleCompleted ? this.props.taskactions.toggleCompleted : undefined}
|
||||
|
||||
addTask={this.internalAddTask.bind(this)}
|
||||
openDetails={this.internalOpenDialog.bind(this)}
|
||||
|
||||
onDrop={this.onDrop.bind(this)}
|
||||
onDragLeave={this.onDragLeave.bind(this)}
|
||||
onDragOver={this.onDragOver.bind(this)}
|
||||
|
@ -87,54 +109,119 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
|
||||
)}
|
||||
</div>
|
||||
{openDialog && (this.renderDetails())}
|
||||
{openDialog && (this.renderDialog())}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderDetails(): JSX.Element {
|
||||
const renderer = this.props.renderers && this.props.renderers.taskDetail ? this.props.renderers.taskDetail : this.internalTaskDetailRenderer;
|
||||
private getTaskByID(taskId: string): IKanbanTask {
|
||||
const tasks = this.props.tasks.filter(t => t.taskId == this.state.openTaskId);
|
||||
|
||||
if (tasks.length == 1) {
|
||||
const task = tasks[0];
|
||||
return tasks[0];
|
||||
}
|
||||
throw "Error Taks not found by taskId";
|
||||
}
|
||||
|
||||
return (<Dialog
|
||||
minWidth={600}
|
||||
hidden={!this.state.openDialog}
|
||||
onDismiss={this.closeDialog.bind(this)}
|
||||
dialogContentProps={{
|
||||
type: DialogType.largeHeader,
|
||||
title: task.title,
|
||||
subText: ''
|
||||
}}
|
||||
modalProps={{
|
||||
isBlocking: false,
|
||||
styles: { main: { minWidth: 600 } }
|
||||
}}
|
||||
>
|
||||
{renderer(task)}
|
||||
</Dialog>);
|
||||
private renderDialog(): JSX.Element {
|
||||
let renderer: (task?: IKanbanTask, bucket?: IKanbanBucket) => JSX.Element = () => (<div>Dialog Renderer Not Set</div>);
|
||||
let task: IKanbanTask = undefined;
|
||||
let bucket: IKanbanBucket = undefined;
|
||||
let dialogheadline:string ='';
|
||||
switch (this.state.dialogState) {
|
||||
case DialogState.Edit:
|
||||
task = this.getTaskByID(this.state.openTaskId);
|
||||
renderer = this.internalTaskEditRenderer.bind(this);
|
||||
dialogheadline =strings.EditTaskDlgHeadline;
|
||||
break;
|
||||
case DialogState.New:
|
||||
renderer = this.internalTaskAddRenderer.bind(this);
|
||||
dialogheadline =strings.AddTaskDlgHeadline;
|
||||
break;
|
||||
default:
|
||||
task = this.getTaskByID(this.state.openTaskId);
|
||||
dialogheadline =task.title;
|
||||
renderer = (this.props.renderers && this.props.renderers.taskDetail) ? this.props.renderers.taskDetail : this.internalTaskDetailRenderer.bind(this);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return (<Dialog
|
||||
minWidth={600}
|
||||
hidden={!this.state.openDialog}
|
||||
onDismiss={this.internalCloseDialog.bind(this)}
|
||||
dialogContentProps={{
|
||||
type: DialogType.largeHeader,
|
||||
title: dialogheadline,
|
||||
subText: ''
|
||||
}}
|
||||
modalProps={{
|
||||
isBlocking: false,
|
||||
styles: { main: { minWidth: 600 } }
|
||||
}}
|
||||
>
|
||||
{renderer(task, bucket)}
|
||||
|
||||
<DialogFooter>
|
||||
{(this.props.allowEdit && this.state.dialogState === DialogState.Display) &&
|
||||
(<PrimaryButton onClick={this.clickEditTask.bind(this)} text={strings.EditTaskBtn} />)}
|
||||
{(this.props.allowEdit && this.state.dialogState === DialogState.Edit) &&
|
||||
(<PrimaryButton onClick={this.saveEditTask.bind(this)} text={strings.SaveTaskBtn} />)}
|
||||
{(this.props.allowAdd && this.state.dialogState === DialogState.New) &&
|
||||
(<PrimaryButton onClick={this.saveAddTask.bind(this)} text={strings.SaveAddTaskBtn} />)}
|
||||
<DefaultButton onClick={this.internalCloseDialog.bind(this)} text={strings.CloseTaskDialog} />
|
||||
</DialogFooter>
|
||||
|
||||
</Dialog>);
|
||||
|
||||
|
||||
// Error Not found or more than one
|
||||
throw "Error Not found or more than one";
|
||||
|
||||
return (<div></div>);
|
||||
|
||||
}
|
||||
|
||||
private clickEditTask(): void {
|
||||
const task = this.getTaskByID(this.state.openTaskId);
|
||||
if (this.props.taskactions.taskEdit) {
|
||||
|
||||
this.internalCloseDialog();
|
||||
this.props.taskactions.taskEdit(clone(task));
|
||||
} else {
|
||||
this.setState({
|
||||
dialogState: DialogState.Edit,
|
||||
editTask: clone(task)
|
||||
});
|
||||
}
|
||||
}
|
||||
private saveEditTask() {
|
||||
|
||||
if (this.props.taskactions.editTaskSaved) {
|
||||
const edittask = clone(this.state.editTask);
|
||||
//check fist state and than event or in the other way
|
||||
this.internalCloseDialog();
|
||||
this.props.taskactions.editTaskSaved(edittask);
|
||||
} else {
|
||||
throw "allowEdit is Set but no handler is set";
|
||||
|
||||
}
|
||||
}
|
||||
private saveAddTask() {
|
||||
|
||||
if (this.props.taskactions.editTaskSaved) {
|
||||
const edittask = clone(this.state.editTask);
|
||||
//check fist state and than event or in the other way
|
||||
this.internalCloseDialog();
|
||||
this.props.taskactions.editTaskSaved(edittask);
|
||||
} else {
|
||||
throw "allowAdd is Set but no handler is set";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private internalTaskDetailRenderer(task: IKanbanTask): JSX.Element {
|
||||
return (<Stack>
|
||||
{/* <Stack horizontal horizontalAlign="stretch">
|
||||
<Stack.Item align="auto" styles={rowStyle1}>
|
||||
<span>% Complete</span>
|
||||
</Stack.Item>
|
||||
<Stack.Item align="stretch" styles={rowStyle2}>
|
||||
<span>{task.bucket}</span>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<KanbanTaskManagedProp name:'person' ... key={p.name+i} />
|
||||
*/}
|
||||
|
||||
{task.mamagedProperties && (
|
||||
task.mamagedProperties.map((p, i) => {
|
||||
return (
|
||||
|
@ -146,18 +233,54 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
</Stack>
|
||||
);
|
||||
}
|
||||
private closeDialog(ev?: React.MouseEvent<HTMLButtonElement>) {
|
||||
|
||||
|
||||
private internalTaskEditRenderer(task: IKanbanTask): JSX.Element {
|
||||
const schema = this.props.editSchema; //TODO
|
||||
return (<div>Edit</div>);
|
||||
}
|
||||
private internalTaskAddRenderer(task?: IKanbanTask, bucket?: IKanbanBucket): JSX.Element {
|
||||
const schema = this.props.editSchema; //TODO
|
||||
return (<div>New</div>);
|
||||
}
|
||||
|
||||
private internalCloseDialog(ev?: React.MouseEvent<HTMLButtonElement>) {
|
||||
this.setState({
|
||||
openDialog: false,
|
||||
openTaskId: undefined
|
||||
openTaskId: undefined,
|
||||
dialogState: undefined,
|
||||
editTask: undefined,
|
||||
addBucket: undefined
|
||||
});
|
||||
}
|
||||
private openDialog(taskid: string) {
|
||||
private internalOpenDialog(taskid: string) {
|
||||
this.setState({
|
||||
openDialog: true,
|
||||
openTaskId: taskid
|
||||
openTaskId: taskid,
|
||||
dialogState: DialogState.Display
|
||||
});
|
||||
}
|
||||
private internalAddTask(targetbucket?: string) {
|
||||
let bucket: IKanbanBucket = undefined;
|
||||
if (bucket) {
|
||||
const buckets = this.props.buckets.filter((p) => p.bucket === targetbucket)
|
||||
if (buckets.length === 1) {
|
||||
bucket = clone(buckets[0]);
|
||||
} else {
|
||||
throw "Bucket not Found in addDialog";
|
||||
|
||||
}
|
||||
}
|
||||
if (this.props.taskactions && this.props.taskactions.taskAdd) {
|
||||
this.props.taskactions.taskAdd(bucket);
|
||||
} else {
|
||||
this.setState({
|
||||
openDialog: true,
|
||||
openTaskId: '',
|
||||
dialogState: DialogState.New,
|
||||
addBucket: bucket
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private onDragLeave(event): void {
|
||||
|
@ -170,7 +293,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
|
||||
private onDragEnd(event): void {
|
||||
console.log('onDragEnd');
|
||||
this.dragelement=undefined;
|
||||
this.dragelement = undefined;
|
||||
}
|
||||
|
||||
private onDragStart(event, taskId: string, bucket: string): void {
|
||||
|
@ -204,7 +327,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
event.preventDefault();
|
||||
console.log('onDragOver this.dragelement');
|
||||
console.log(this.dragelement);
|
||||
|
||||
|
||||
if (this.dragelement.bucket !== targetbucket) {
|
||||
/* if (!this.bucketRef.current.classList.contains(styles.dragover)) {
|
||||
this.bucketRef.current.classList.add(styles.dragover)
|
||||
|
@ -225,7 +348,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
const taskId = this.dragelement.taskId;
|
||||
const source = this.props.buckets.filter(s => s.bucket == this.dragelement.bucket)[0];
|
||||
const target = this.props.buckets.filter(s => s.bucket == targetbucket)[0];
|
||||
|
||||
|
||||
if (this.props.taskactions) {
|
||||
let allowMove = true;
|
||||
if (this.props.taskactions.allowMove) {
|
||||
|
@ -249,15 +372,21 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
|
|||
}
|
||||
|
||||
private getItems = () => {
|
||||
return [
|
||||
{
|
||||
key: 'newItem',
|
||||
name: 'New',
|
||||
cacheKey: 'myCacheKey', // changing this key will invalidate this items cache
|
||||
iconProps: {
|
||||
iconName: 'Add'
|
||||
}
|
||||
}]
|
||||
if (this.props.allowAdd) {
|
||||
//TODO
|
||||
return [
|
||||
{
|
||||
key: 'newItem',
|
||||
name: 'New',
|
||||
cacheKey: 'myAddBtnKey',
|
||||
iconProps: {
|
||||
iconName: 'Add'
|
||||
},
|
||||
onClick: () => this.internalAddTask.bind(this)
|
||||
}];
|
||||
}
|
||||
return [];
|
||||
|
||||
}
|
||||
|
||||
private getFarItems = () => {
|
||||
|
|
|
@ -8,9 +8,9 @@ import { IKanbanBoardTaskActions } from './IKanbanBoardTaskActions';
|
|||
import classNames from 'classnames';
|
||||
import { IconNames } from 'office-ui-fabric-react';
|
||||
|
||||
export interface IKanbanTaskProps extends IKanbanTask, IKanbanBoardTaskSettings, IKanbanBoardTaskActions {
|
||||
|
||||
export interface IKanbanTaskProps extends IKanbanTask, IKanbanBoardTaskSettings {
|
||||
|
||||
toggleCompleted?: (taskId: string) => void;
|
||||
openDetails: (taskId: string) => void;
|
||||
onDragStart: (event) => void;
|
||||
onDragEnd: (event) => void;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Thinking about Kanban component with Fluent Ui Components
|
||||
|
||||
# current
|
||||
## current
|
||||
allowMove from one Bucket to the Other tested
|
||||
move task to other Bucket works
|
||||
|
||||
|
@ -38,7 +38,8 @@ Something like this sould come out, but styling is currently bad
|
|||
Something like this sould come out, but styling is currently bad
|
||||
![prototype](./sample.gif "prototype on 2nd day")
|
||||
|
||||
IMPORTANT
|
||||
# IMPORTANT
|
||||
|
||||
```
|
||||
IKanbanTask {
|
||||
taskId: string;
|
||||
|
@ -55,3 +56,21 @@ event.dataTransfer.setData('xyz','1')
|
|||
Unexpected call to method or property access.
|
||||
```
|
||||
|
||||
|
||||
# Next Steps Component:
|
||||
* think about Promise Task Actions, because actions are async
|
||||
* internalDislplayRenderer: Person / Persons
|
||||
* EditSchema To support Edit and New PNP Controls :)
|
||||
* BucketEdit Component (can be used in CustomPropertyPane)
|
||||
|
||||
|
||||
# Webpart Steps
|
||||
|
||||
* PNP Placeholder Control for Config
|
||||
* PNP WebpartTitle Control
|
||||
* DataConnection
|
||||
* Usage of BucketEdit in pane
|
||||
* PNP Order pane Control
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
define([], function() {
|
||||
define([], function () {
|
||||
return {
|
||||
"CompleteButton": "Complete",
|
||||
"IsCompleted": "Is Completed",
|
||||
"IsNotCompleted": "Is Not Completed",
|
||||
"AddTask": "Add Task",
|
||||
"OpenDetails":"Open Details"
|
||||
"IsCompleted": "Is Completed",
|
||||
"IsNotCompleted": "Is Not Completed",
|
||||
"AddTask": "Add Task",
|
||||
"OpenDetails": "Open Details",
|
||||
"EditTaskBtn": "Edit",
|
||||
"SaveTaskBtn": "Save and Close",
|
||||
"SaveAddTaskBtn": "Add and Close",
|
||||
"CloseTaskDialog": "Close",
|
||||
"AddTaskDlgHeadline":"Add Task",
|
||||
"EditTaskDlgHeadline":"Edit Task",
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,6 +4,12 @@ declare interface IKanbanBoardStrings {
|
|||
IsNotCompleted: string;
|
||||
AddTask: string;
|
||||
OpenDetails: string;
|
||||
EditTaskBtn:string;
|
||||
SaveTaskBtn:string;
|
||||
SaveAddTaskBtn:string;
|
||||
CloseTaskDialog:string;
|
||||
AddTaskDlgHeadline:string;
|
||||
EditTaskDlgHeadline:string;
|
||||
}
|
||||
|
||||
declare module 'KanbanBoardStrings' {
|
||||
|
|
Loading…
Reference in New Issue