ManagedProperties Added to Task

This commit is contained in:
petkir 2020-06-19 14:58:13 +02:00
parent fa41aaad50
commit b53b9a7f5f
11 changed files with 271 additions and 36 deletions

View File

@ -0,0 +1,8 @@
import {IKanbanTask} from './IKanbanTask';
import { IKanbanBucket } from './IKanbanBucket';
export interface IKanbanBoardRenderers{
task?: (task:IKanbanTask) => JSX.Element ;
bucketHeadline?: (bucket:IKanbanBucket) => JSX.Element ;
taskDetail?: (task:IKanbanTask) => JSX.Element ;
}

View File

@ -2,4 +2,5 @@ export interface IKanbanBoardTaskSettings {
showLabels: boolean;
showPriority: boolean;
showAssignedTo: boolean;
showTaskDetailsButton: boolean;
}

View File

@ -2,5 +2,26 @@ export interface IKanbanTask {
taskId: number | string;
title: string;
isCompleted?: boolean;
bucket:string;
bucket: string;
mamagedProperties?: IKanbanTaskManagedProps[];
}
export interface IKanbanTaskManagedProps {
name: string;
displayName?: string;
type: KanbanTaskMamagedPropertyType;
value: any;
renderer?: (name: string, value: object, type:KanbanTaskMamagedPropertyType) => JSX.Element;
}
export enum KanbanTaskMamagedPropertyType {
string,
number,
percent,
html,
person,
persons,
complex
}

View File

@ -20,6 +20,9 @@ export interface IKanbanBucketProps extends IKanbanBucket {
onDragLeave: (event, targetbucket: string) => void;
onDrop: (event, targetbucket: string) => void;
leavingTaskId?: number | string;
leavingBucket?: string;
overBucket?: string;

View File

@ -3,8 +3,16 @@ import styles from './KanbanComponent.module.scss';
import { IKanbanTask } from './IKanbanTask';
import { IKanbanBoardTaskSettings } from './IKanbanBoardTaskSettings';
import { IKanbanBoardTaskActions } from './IKanbanBoardTaskActions';
import { IKanbanBoardRenderers } from './IKanbanBoardRenderers';
import { IKanbanBucket } from './IKanbanBucket';
import KanbanBucket from './KanbanBucket';
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 { CommandBar } from 'office-ui-fabric-react/lib/CommandBar';
@ -14,6 +22,7 @@ export interface IKanbanComponentProps {
tasksettings: IKanbanBoardTaskSettings;
taskactions: IKanbanBoardTaskActions;
showCommandbar?: boolean;
renderers?: IKanbanBoardRenderers;
/*
showCommandbarNew: boolean;
allowDialog: boolean; TODO im mock
@ -24,6 +33,8 @@ export interface IKanbanComponentState {
leavingTaskId?: number | string;
leavingBucket?: string;
overBucket?: string;
openDialog: boolean;
openTaskId?: number | string;
}
export default class KanbanComponent extends React.Component<IKanbanComponentProps, IKanbanComponentState> {
@ -32,6 +43,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
super(props);
this.state = {
openDialog: false,
leavingTaskId: null,
leavingBucket: null,
overBucket: null
@ -40,6 +52,7 @@ 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
return (
<div>
@ -60,22 +73,92 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
buckettasks={tasks.filter((x) => x.bucket == b.bucket)}
tasksettings={tasksettings}
taskactions={taskactions}
openDetails={(x) => alert(x)}
openDetails={this.openDialog.bind(this)}
onDrop={this.onDrop.bind(this)}
onDragLeave={this.onDragLeave.bind(this)}
onDragOver={this.onDragOver.bind(this)}
onDragStart={this.onDragStart.bind(this)}
/>)
/>);
}
)}
</div>
{openDialog && (this.renderDetails())}
</div>
);
}
private renderDetails(): JSX.Element {
debugger;
const renderer = this.props.renderers && this.props.renderers.taskDetail ? this.props.renderers.taskDetail : this.internalTaskDetailRenderer;
const tasks = this.props.tasks.filter(t => t.taskId == this.state.openTaskId);
if (tasks.length == 1) {
const task = tasks[0];
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>);
}
// Error Not found or more than one
throw "Error Not found or more than one";
return (<div></div>);
}
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 (
<KanbanTaskManagedProp {...p} key={p.name + i} />
);
})
)}
</Stack>
);
}
private closeDialog(ev?: React.MouseEvent<HTMLButtonElement>) {
this.setState({
openDialog: false,
openTaskId: undefined
});
}
private openDialog(taskid: number | string) {
this.setState({
openDialog: true,
openTaskId: taskid
});
}
private onDragLeave(event): void {
console.log('onDragLeave');
/* if (this.bucketRef.current.classList.contains(styles.dragover)) {
@ -126,19 +209,19 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
}*/
if (event.dataTransfer.getData("sourcebucket") !== targetbucket) {
const sourcebucket = event.dataTransfer.getData("sourcebucket");
const source = this.props.buckets.filter(s=>s.bucket == sourcebucket)[0];
const target = this.props.buckets.filter(s=>s.bucket == targetbucket)[0];
const source = this.props.buckets.filter(s => s.bucket == sourcebucket)[0];
const target = this.props.buckets.filter(s => s.bucket == targetbucket)[0];
const taskId = event.dataTransfer.getData("taskId");
if(this.props.taskactions) {
let allowMove= true;
if(this.props.taskactions.allowMove) {
allowMove= this.props.taskactions.allowMove(taskId,
if (this.props.taskactions) {
let allowMove = true;
if (this.props.taskactions.allowMove) {
allowMove = this.props.taskactions.allowMove(taskId,
source,
target
);
}
if(allowMove && this.props.taskactions.moved) {
this.props.taskactions.moved(taskId,target);
if (allowMove && this.props.taskactions.moved) {
this.props.taskactions.moved(taskId, target);
}
}
}

View File

@ -6,11 +6,12 @@ import {IKanbanTask} from './IKanbanTask';
import {IKanbanBoardTaskSettings} from './IKanbanBoardTaskSettings';
import {IKanbanBoardTaskActions} from './IKanbanBoardTaskActions';
import classNames from 'classnames';
import { IconNames } from 'office-ui-fabric-react';
export interface IKanbanTaskProps extends IKanbanTask,IKanbanBoardTaskSettings,IKanbanBoardTaskActions {
openDetails?: (taskId: number | string) => void;
openDetails: (taskId: number | string) => void;
onDragStart:(event) => void;
isMoving:boolean;
}
@ -24,7 +25,7 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
}
public render(): React.ReactElement<IKanbanTaskProps> {
const { title, showLabels, showPriority, showAssignedTo, isCompleted,isMoving } = this.props;
const { title, showLabels, showPriority, showAssignedTo, isCompleted,isMoving,showTaskDetailsButton } = this.props;
const showCompleted = !!this.props.toggleCompleted;
const iconCompleted = { iconName: isCompleted ? 'RadioBtnOn' : 'RadioBtnOff' };
return (
@ -42,6 +43,15 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
/>)
}
<div className={styles.title}>{title}</div>
{ showTaskDetailsButton && (
<IconButton
iconProps={{iconName:'More'}}
title={strings.OpenDetails}
ariaLabel={strings.OpenDetails}
onClick={this._openDetails.bind(this)}
/>)
}
</div>
<div className={styles.membersAndLabels}>
{showAssignedTo && (<div className={styles.assignedto}></div>)}
@ -58,5 +68,13 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
}
}
private _openDetails():void {
debugger;
if(this.props.openDetails) {
this.props.openDetails(this.props.taskId);
}
}
}

View File

@ -0,0 +1,6 @@
.rowcol1{
flex-basis: 30%;
}
.rowcol2{
flex-basis: 70%;
}

View File

@ -0,0 +1,66 @@
import * as React from 'react';
import styles from './KanbanTaskManagedProp.module.scss';
import { IKanbanTaskManagedProps, KanbanTaskMamagedPropertyType } from './IKanbanTask';
import { IStackStyles, Stack } from 'office-ui-fabric-react/lib/Stack';
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
export interface IKanbanTaskManagedPropProps extends IKanbanTaskManagedProps { }
export interface IKanbanTaskManagedPropState { }
export default class KanbanTaskManagedProp extends React.Component<IKanbanTaskManagedPropProps, IKanbanTaskManagedPropState> {
public render(): React.ReactElement<IKanbanTaskManagedPropProps> {
const { displayName, name } = this.props;
return (
<Stack horizontal horizontalAlign="stretch">
<Stack.Item align="auto" className={styles.rowcol1}>
<span>{displayName ? displayName : name}</span>
</Stack.Item>
<Stack.Item align="stretch" className={styles.rowcol2}>
{this.renderValue()}
</Stack.Item>
</Stack>
);
}
private renderValue() {
const { name, type, value } = this.props;
if (this.props.renderer) {
return this.props.renderer(name, value, type);
}
switch (this.props.type) {
case KanbanTaskMamagedPropertyType.string:
return (<span>{value} </span>);
break;
case KanbanTaskMamagedPropertyType.number:
return (<span>{'' + value} </span>);
//TODO maybe Formater
break;
case KanbanTaskMamagedPropertyType.percent:
return (<span>{`${(value as any) * 100}%`} </span>);
//TODO maybe better Formater
break;
case KanbanTaskMamagedPropertyType.html:
return (<span>{ReactHtmlParser(value)}</span>);
//TODO maybe better Formater
break;
case KanbanTaskMamagedPropertyType.person:
return (<span>TODO</span>);
//TODO
break;
case KanbanTaskMamagedPropertyType.persons:
return (<span>TODO</span>);
//TODO
break;
case KanbanTaskMamagedPropertyType.complex:
return (<span>{JSON.stringify(value)}</span>);
break;
default:
throw "Unknow KanbanTaskMamagedPropertyType";
break;
}
}
}

View File

@ -1,7 +1,7 @@
import * as React from 'react';
import KanbanComponent from './KanbanComponent';
import { IKanbanBucket } from './IKanbanBucket';
import { IKanbanTask } from './IKanbanTask';
import { IKanbanTask, KanbanTaskMamagedPropertyType } from './IKanbanTask';
import { findIndex } from "lodash";
export interface IMockKanbanProps { }
@ -17,19 +17,45 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
super(props);
this.state = {
buckets:[
{bucket:'Not Started', bucketheadline:'Not Started Head',percentageComplete:0, color:'yellow' ,allowAddTask:true},
{bucket:'Test1', bucketheadline:'Test1 Head',percentageComplete:10, color:'orange',allowAddTask:true },
{bucket:'Test2', bucketheadline:'Test2 Head',percentageComplete:50, color:'green' },
{bucket:'Test3', bucketheadline:'Test3 Head',percentageComplete:50, color:'#FF0000' },
{bucket:'Test4', bucketheadline:'Test4 Head',percentageComplete:0 ,allowAddTask:true }
buckets: [
{ bucket: 'Not Started', bucketheadline: 'Not Started Head', percentageComplete: 0, color: 'yellow', allowAddTask: true },
{ bucket: 'Test1', bucketheadline: 'Test1 Head', percentageComplete: 10, color: 'orange', allowAddTask: true },
{ bucket: 'Test2', bucketheadline: 'Test2 Head', percentageComplete: 50, color: 'green' },
{ bucket: 'Test3', bucketheadline: 'Test3 Head', percentageComplete: 50, color: '#FF0000' },
{ bucket: 'Test4', bucketheadline: 'Test4 Head', percentageComplete: 0, allowAddTask: true }
],
tasks: [
{taskId: 1, title:'test1',bucket:'Not Started'},
{taskId: 2, title:'test2',bucket:'Not Started'},
{taskId: 3, title:'test3',bucket:'Not Started'},
{taskId: '4', title:'test 4',bucket:'Test4'},
{taskId: '5', title:'test 5',bucket:'Test3'},
{
taskId: 1, title: 'test1', bucket: 'Not Started',
mamagedProperties: [
{
name: 'Prop1',
displayName: 'Prop1 Display',
type: KanbanTaskMamagedPropertyType.html,
value: '<p>test<b>Bold</b></p>'
},
{
name: 'Prop2',
displayName: 'Prop2 Display',
type: KanbanTaskMamagedPropertyType.complex,
value: '<p>test<b>Bold</b></p>',
renderer: (name, value, type) => { return (<span>SampleRenderer</span>); }
},
{
name: 'Prop3',
displayName: 'String',
type: KanbanTaskMamagedPropertyType.string,
value: 'Hallo World'
}
]
},
{ taskId: 2, title: 'test2', bucket: 'Not Started' },
{ taskId: 3, title: 'test3', bucket: 'Not Started' },
{ taskId: '4', title: 'test 4', bucket: 'Test4' },
{ taskId: '5', title: 'test 5', bucket: 'Test3' },
]
};
@ -45,7 +71,8 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
tasksettings={{
showLabels: true,
showPriority: true,
showAssignedTo: true
showAssignedTo: true,
showTaskDetailsButton: true
}
}
taskactions={{
@ -62,10 +89,10 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
private _toggleCompleted(taskId: number | string): void {
//TODO
//TODO
}
private _allowMove(taskId: number | string, prevBucket: IKanbanBucket, targetBucket: IKanbanBucket): boolean {
if(prevBucket.bucket ==='Test2' && targetBucket.bucket ==='Test3') {
if (prevBucket.bucket === 'Test2' && targetBucket.bucket === 'Test3') {
return false;
}
return true;
@ -73,10 +100,10 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
private _moved(taskId: number | string, targetBucket: IKanbanBucket): void {
debugger;
const elementsIndex = findIndex( this.state.tasks ,element => element.taskId == taskId );
const elementsIndex = findIndex(this.state.tasks, element => element.taskId == taskId);
let newArray = [...this.state.tasks];
newArray[elementsIndex].bucket = targetBucket.bucket;
this.setState({tasks:newArray});
this.setState({ tasks: newArray });
}
}

View File

@ -1,8 +1,9 @@
define([], function() {
return {
"CompleteButton": "complete",
"IsCompleted": "IsCompleted",
"IsNotCompleted": "IsNotCompleted",
"AddTask": "AddTask"
"CompleteButton": "Complete",
"IsCompleted": "Is Completed",
"IsNotCompleted": "Is Not Completed",
"AddTask": "Add Task",
"OpenDetails":"Open Details"
}
});

View File

@ -3,6 +3,7 @@ declare interface IKanbanBoardStrings {
IsCompleted: string;
IsNotCompleted: string;
AddTask: string;
OpenDetails: string;
}
declare module 'KanbanBoardStrings' {