diff --git a/samples/react-kanban-board/README.md b/samples/react-kanban-board/README.md index 66789d697..a51c122fc 100644 --- a/samples/react-kanban-board/README.md +++ b/samples/react-kanban-board/README.md @@ -2,7 +2,8 @@ ## Summary -This solution contains an SPFx webpart which shows a Kanban board using jqxKanban ReactJS component (from [JQWidgets](https://www.jqwidgets.com/jquery-widgets-documentation/documentation/jqxkanban/jquery-kanban-getting-started.htm?search=kanban)). + +This solution contains an SPFx webpart which shows a Kanban board using Fluent UI components ([FluentUI](https://developer.microsoft.com/fluentui/)). The webpart uses the default columns of the SharePoint Tasks list for showing the board's columns and the tasks. ![picture of the web part in action](assets/kanban-board.gif) @@ -26,7 +27,7 @@ This webpart reads the information from a Tasks list and uses the following OOB * Priority * Task Status -The Task list can be chosen using the webpart properties +The Task list can be chosen using the webpart properties (BaseTemplate 171 or 107) ## Solution @@ -34,6 +35,7 @@ Solution|Author(s) --------|--------- react-kanban-board | [Ram](https://twitter.com/ram_meenavalli) react-kanban-board | Daniel Westerdale ([Westerdale Solutions Ltd.](https://westerdale.blog), [@westerdaled](https://twitter.com/westerdaled?s=20)) +react-kanban-board | Peter Paul Kirschner ([@petkir_at](https://twitter.com/)) ## Version history @@ -41,11 +43,31 @@ Version|Date|Comments -------|----|-------- 1.0.0.0|July 17, 2019|Initial release 1.0.1.0|April 21, 2020|Added support for Teams hosts +2.0.0.0|July 10, 2020| jqwidgets replaced with a custom FluentUI Component and IE11 Support +[Read More about the implementation of this Board](./src/kanban/Readme.md) + +## Usage +* PNP Placeholder Control if not Configured +* PNP WebpartTitle Control (Toggle Show/Hide in PropertyPane) +* PNP Order PropertyPane Control (Change Position of Buckets) +* PNP List Selection PropertyPane Control (including Filter on BaseTemplateId) +* Usage of BucketEdit in Pane (Use an Component in PropertyPane (Custom Field)) +* Fluent UI +* PNP JS DataConnection to SharePoint + + +Thanks form @petkir to: +Daniel Westerdale for Testing and inspiration (everytime again) +Hugo Bernier for Inspiration to use Office UI Fabric +Jean-Philippe CIVADE for Bug Report IE11 (initiator of rewrite of this Sample) + + ## Disclaimer **THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** +### only For Version 1 **THIS WEBPART USES jQWidgets FOR SHOWING THE KANBAN BOARD. jQWidgets IS FREE TO USE UNDER THE CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL 3.0 LICENSE. FOR COMMERCIAL USE, PLEASE CHECK THE [LICENSING TERMS](https://www.jqwidgets.com/license/) FOR jQWidgets** --- @@ -60,8 +82,8 @@ Version|Date|Comments ## Features This sample highlights the following concepts -* Binding SharePoint list data to jqxKanban React Component -* Updating SharePoint List Items based on events from the jqxKanban board +* Binding SharePoint list data to an custom Kanban-Control +* Updating SharePoint List Items based on events from the custom Kanban-Control When a task is moved to different columns in the Kanban Board, the status of the respective SharePoint list item is updated using PnP JS diff --git a/samples/react-kanban-board/config/package-solution.json b/samples/react-kanban-board/config/package-solution.json index 0a5224057..c8ce7fb66 100644 --- a/samples/react-kanban-board/config/package-solution.json +++ b/samples/react-kanban-board/config/package-solution.json @@ -3,7 +3,7 @@ "solution": { "name": "react-kanban-board-client-side-solution", "id": "cccbd72b-7b89-4128-9348-0a4850ded8fd", - "version": "1.0.1.0", + "version": "2.0.0.0", "includeClientSideAssets": true, "skipFeatureDeployment": true, "isDomainIsolated": false diff --git a/samples/react-kanban-board/src/kanban/KanbanBucket.module.scss b/samples/react-kanban-board/src/kanban/KanbanBucket.module.scss index 23f021917..66475c8f1 100644 --- a/samples/react-kanban-board/src/kanban/KanbanBucket.module.scss +++ b/samples/react-kanban-board/src/kanban/KanbanBucket.module.scss @@ -1,8 +1,7 @@ .bucket { - display: table-cell; - + - border-right: 1px solid gray; + // border-right: 1px solid gray; .headline { padding: 2px 10px; line-height: 2em; @@ -19,11 +18,27 @@ right: 0px; } } - &.dragover{ - background-color: lightgray; + .taskArea{ + padding: 5px; } - .placeholder{ - background-color: rgb(180, 180, 180); + .placeholder { + position: relative; + } + .taskplaceholder { + position: relative; + background-color: transparent; + cursor: move; + } + /* + .placeholder::after { + content:'x'; + position:absolute; + top:0; + width:100%; + height:100%; + background-color:blue; + } + */ } diff --git a/samples/react-kanban-board/src/kanban/KanbanBucket.tsx b/samples/react-kanban-board/src/kanban/KanbanBucket.tsx index 0fe7931e1..bcdd7088b 100644 --- a/samples/react-kanban-board/src/kanban/KanbanBucket.tsx +++ b/samples/react-kanban-board/src/kanban/KanbanBucket.tsx @@ -11,6 +11,7 @@ import classNames from 'classnames'; import * as strings from 'KanbanBoardStrings'; export interface IKanbanBucketProps extends IKanbanBucket { + buckettasks: IKanbanTask[]; tasksettings: IKanbanBoardTaskSettings; @@ -19,12 +20,10 @@ export interface IKanbanBucketProps extends IKanbanBucket { addTask?: (bucket: string) => void; onDragStart: (event, taskId: string, bucket: string) => void; - onDragOver: (event, targetbucket: string) => void; - onDragLeave: (event, targetbucket: string) => void; - onDrop: (event, targetbucket: string) => void; + onDragEnd: (event, taskId: string, bucket: string) => void; - + leavingTaskId?: string; leavingBucket?: string; @@ -52,16 +51,16 @@ export default class KanbanBucket extends React.Component { - const { bucket, bucketheadline, color, buckettasks, + const { bucket, bucketheadline, color, buckettasks, tasksettings, percentageComplete, allowAddTask, overBucket, leavingTaskId, leavingBucket } = this.props; + return (
this.props.onDragOver(event, bucket)} - onDragLeave={(event) => this.props.onDragLeave(event, bucket)} - onDrop={(event) => this.props.onDrop(event, bucket)} + >
{strings.AddTask} )} +
{ buckettasks.map((t) => { const merge = { ...t, ...tasksettings, }; const isMoving = (t.taskId === leavingTaskId && t.bucket === leavingBucket); - return (
+ return (
); } diff --git a/samples/react-kanban-board/src/kanban/KanbanComponent.module.scss b/samples/react-kanban-board/src/kanban/KanbanComponent.module.scss index 14b7b83bf..f9ee55473 100644 --- a/samples/react-kanban-board/src/kanban/KanbanComponent.module.scss +++ b/samples/react-kanban-board/src/kanban/KanbanComponent.module.scss @@ -1,4 +1,11 @@ .kanbanBoard { display: table; width: 100%; -} \ No newline at end of file + .bucketwrapper { + border: 1px solid transparent; + display: table-cell; + } + .dragover { + border-color: "[theme: themePrimary, default: #0078d7]"; + } +} diff --git a/samples/react-kanban-board/src/kanban/KanbanComponent.tsx b/samples/react-kanban-board/src/kanban/KanbanComponent.tsx index 2c0a34917..ad02c3812 100644 --- a/samples/react-kanban-board/src/kanban/KanbanComponent.tsx +++ b/samples/react-kanban-board/src/kanban/KanbanComponent.tsx @@ -17,7 +17,7 @@ import { clone } from '@microsoft/sp-lodash-subset'; import { CommandBar } from 'office-ui-fabric-react/lib/CommandBar'; -import { TooltipHost } from 'office-ui-fabric-react'; +import { TooltipHost, findIndex } from 'office-ui-fabric-react'; export interface IKanbanComponentProps { buckets: IKanbanBucket[]; @@ -38,7 +38,6 @@ export interface IKanbanComponentProps { export interface IKanbanComponentState { leavingTaskId?: string; leavingBucket?: string; - overBucket?: string; openDialog: boolean; openTaskId?: string; dialogState?: DialogState; @@ -54,6 +53,7 @@ export enum DialogState { export default class KanbanComponent extends React.Component { private dragelement?: IKanbanTask; + private bucketsref: any[]; constructor(props: IKanbanComponentProps) { super(props); @@ -61,15 +61,16 @@ export default class KanbanComponent extends React.Component { const { buckets, tasks, tasksettings, taskactions, showCommandbar } = this.props; const { openDialog } = this.state; - const { leavingBucket, leavingTaskId, overBucket } = this.state; + const bucketwidth: number = buckets.length > 0 ? 100 / buckets.length : 100; + const { leavingBucket, leavingTaskId } = this.state; const wrappedTaskActions: IKanbanBoardTaskActions = { }; @@ -85,25 +86,34 @@ export default class KanbanComponent extends React.Component { - buckets.map((b) => { + buckets.map((b, i) => { const merge = { ...b, ...this.state }; - return ( x.bucket == b.bucket)} - tasksettings={tasksettings} + return (
this.bucketsref[i] = bucketContent} + key={'BucketWrapper'+b.bucket+i} + onDragOver={(event) => this.onDragOver(event, b.bucket)} + onDragLeave={(event) => this.onDragLeave(event, b.bucket)} + onDrop={(event) => this.onDrop(event, b.bucket)} + > + x.bucket == b.bucket)} + tasksettings={tasksettings} - toggleCompleted={this.props.taskactions && this.props.taskactions.toggleCompleted ? this.props.taskactions.toggleCompleted : undefined} + toggleCompleted={this.props.taskactions && this.props.taskactions.toggleCompleted ? this.props.taskactions.toggleCompleted : undefined} - addTask={this.internalAddTask.bind(this)} - openDetails={this.internalOpenDialog.bind(this)} + 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)} - onDragStart={this.onDragStart.bind(this)} - onDragEnd={this.onDragEnd.bind(this)} - />); + + onDragStart={this.onDragStart.bind(this)} + onDragEnd={this.onDragEnd.bind(this)} + /> +
); } @@ -211,30 +221,30 @@ export default class KanbanComponent extends React.Component - {tasksettings && tasksettings.showPriority && ( - - )} - {tasksettings && tasksettings.showAssignedTo && ( - )} - - + {tasksettings && tasksettings.showPriority && ( + + )} + {tasksettings && tasksettings.showAssignedTo && ( + )} + + {task.mamagedProperties && ( task.mamagedProperties.map((p, i) => { return ( @@ -295,17 +305,24 @@ export default class KanbanComponent extends React.Component element.bucket == bucket); + if (index != -1 && this.bucketsref.length > index ){ + + //&& this.bucketsref[index].classList.contains(styles.dragover)) { + this.bucketsref[index].classList.remove(styles.dragover); + } } private onDragEnd(event): void { console.log('onDragEnd'); this.dragelement = undefined; + this.setState({ + leavingTaskId: null, + leavingBucket: null, + + }); } private onDragStart(event, taskId: string, bucket: string): void { @@ -316,6 +333,7 @@ export default class KanbanComponent extends React.Component element.bucket == targetbucket); + if (index > -1 && this.bucketsref.length > index ){ + console.log(this.bucketsref[index]); + console.log(this.bucketsref[index].classList); + //&& this.bucketsref[index].classList.contains(styles.dragover)) { + this.bucketsref[index].classList.add(styles.dragover); + } } } private onDrop(event, targetbucket: string): void { console.log('onDrop'); - /* if (this.bucketRef.current.classList.contains(styles.dragover)) { - this.bucketRef.current.classList.remove(styles.dragover) - }*/ + if (this.bucketsref && this.bucketsref.length>0) { + this.bucketsref.forEach(x=> {x.classList.remove(styles.dragover);}); + } if (this.dragelement.bucket !== targetbucket) { //event.dataTransfer.getData("text"); const taskId = this.dragelement.taskId; @@ -378,7 +396,7 @@ export default class KanbanComponent extends React.Component
{showCompleted && ( - ) + />
) }
{title}
{showTaskDetailsButton && ( - ) + />
) }
diff --git a/samples/react-kanban-board/src/kanban/Readme.md b/samples/react-kanban-board/src/kanban/Readme.md index 720175be0..dcc754ae2 100644 --- a/samples/react-kanban-board/src/kanban/Readme.md +++ b/samples/react-kanban-board/src/kanban/Readme.md @@ -1,15 +1,43 @@ -# its only Prototyping -Thinking about Kanban component with Fluent Ui Components +# Next Steps Component: +* think about Promise Task Actions, because actions are async +* EditSchema To support Edit +------------------------------- +# KanbanComponent Control -## current -allowMove from one Bucket to the Other tested -move task to other Bucket works -internalDislplayRenderer: Person / Persons -BucketEdit Component (can be used in CustomPropertyPane) +This control renders a KanbanBoard which can be used to show Tasks and move it from one State to an Other. -playing with drag visibility +**Control in Action** +![KanbanBoard control](../assets/KanbanBoard.gif) + + +## How to use this control in your solutions + + this component is not Extracted as an NPM Package + Copy this Folder +In the Files ```MockKanban.tsx``` you can find many Configuration Options + + +```typescript + + +``` Bucket ``` buckets:[ @@ -21,10 +49,6 @@ Bucket ], ``` -with such a structure its possible to use -PropertyFieldOrder -PropertyFieldColorPicker -or a wrapper to warp PropertyFieldColorPicker with some other in a Custom Control Task ``` @@ -34,14 +58,81 @@ Task {taskId: '4', title:'test 4',bucket:'Test4'}, {taskId: '5', title:'test 5',bucket:'Test3'}, ``` -Something like this sould come out, but styling is currently bad -![prototype](./img1.PNG "prototype") -Something like this sould come out, but styling is currently bad -![prototype](./sample.gif "prototype on 2nd day") -# IMPORTANT +## Implementation +The KanbanBoard control can be configured with the following properties: + +### IKanbanBucket +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | + + bucket:string; + bucketheadline:string; + percentageComplete: number; + color?:string; + allowAddTask?:boolean; +### IKanbanTask +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | + taskId: string; + title: string; + isCompleted?: boolean; + assignedTo?: IPersonaProps; + htmlDescription?:string; + priority?:string; + bucket: string; + mamagedProperties?: IKanbanTaskManagedProps[]; + +### IKanbanComponentProps + +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | + + + +#### IKanbanBoardTaskSettings +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | +#### IKanbanBoardTaskActions +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | +#### IKanbanBoardRenderers +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | +#### IKanbanTaskManagedProps +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | + +IPersonaProps reference to Fluent UI + +## Samples + +### Custom Detail View Renderer +```typescript + +``` + +### Use SharePoint New and Edit Form +this is the Classic Form on the ListItems +```typescript + +``` + +### Use EditSchema to Configure New and Edit Form in this Component + this functionality supports only some Field Types +```typescript + +``` + +### Disallow Move from One Bucket to an Other + this functionality supports only some Field Types +```typescript + +``` + +## Leanings ``` IKanbanTask { taskId: string; @@ -56,25 +147,4 @@ The second big thing is IE allows only to set the value 'text' event.dataTransfe ``` event.dataTransfer.setData('xyz','1') Unexpected call to method or property access. -``` - - -# Next Steps Component: -* think about Promise Task Actions, because actions are async -* EditSchema To support Edit and New PNP Controls :) - - - -# Webpart Steps - - -* DataConnection - ** Task missing -* BucketEdit Does not refresh Component - - -# Webpart Steps Done -* PNP Placeholder Control for Config -* PNP WebpartTitle Control -* Usage of BucketEdit in pane -* PNP Order pane Control \ No newline at end of file +``` \ No newline at end of file diff --git a/samples/react-kanban-board/src/kanban/img1.PNG b/samples/react-kanban-board/src/kanban/img1.PNG deleted file mode 100644 index 15067edb2..000000000 Binary files a/samples/react-kanban-board/src/kanban/img1.PNG and /dev/null differ diff --git a/samples/react-kanban-board/src/kanban/index.ts b/samples/react-kanban-board/src/kanban/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/samples/react-kanban-board/src/kanban/sample.gif b/samples/react-kanban-board/src/kanban/sample.gif deleted file mode 100644 index b1763b383..000000000 Binary files a/samples/react-kanban-board/src/kanban/sample.gif and /dev/null differ diff --git a/samples/react-kanban-board/src/webparts/kanbanBoard/KanbanBoardWebPart.ts b/samples/react-kanban-board/src/webparts/kanbanBoard/KanbanBoardWebPart.ts index b0938d21c..fe21a81d6 100644 --- a/samples/react-kanban-board/src/webparts/kanbanBoard/KanbanBoardWebPart.ts +++ b/samples/react-kanban-board/src/webparts/kanbanBoard/KanbanBoardWebPart.ts @@ -58,19 +58,6 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart = React.createElement( - KanbanBoard, - { - listTitle: this.properties.listTitle, - webUrl: this.context.pageContext.web.absoluteUrl - } - ); - */ - /* - const element: React.ReactElement = React.createElement( - MockKanban,{}); - */ console.log('bucket render webpart'); console.log(this.properties.buckets); const element: React.ReactElement = React.createElement( diff --git a/samples/react-kanban-board/src/webparts/kanbanBoard/components/IKanbanBoardProps.ts b/samples/react-kanban-board/src/webparts/kanbanBoard/components/IKanbanBoardProps.ts deleted file mode 100644 index 143b1321f..000000000 --- a/samples/react-kanban-board/src/webparts/kanbanBoard/components/IKanbanBoardProps.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface IKanbanBoardProps { - listTitle: string; - webUrl: string; -} diff --git a/samples/react-kanban-board/src/webparts/kanbanBoard/components/KanbanBoard.module.scss b/samples/react-kanban-board/src/webparts/kanbanBoard/components/KanbanBoard.module.scss deleted file mode 100644 index a3a7e6c30..000000000 --- a/samples/react-kanban-board/src/webparts/kanbanBoard/components/KanbanBoard.module.scss +++ /dev/null @@ -1,74 +0,0 @@ -@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; - -.kanbanBoard { - .container { - max-width: 700px; - margin: 0px auto; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); - } - - .row { - @include ms-Grid-row; - @include ms-fontColor-white; - background-color: $ms-color-themeDark; - padding: 20px; - } - - .column { - @include ms-Grid-col; - @include ms-lg10; - @include ms-xl8; - @include ms-xlPush2; - @include ms-lgPush1; - } - - .title { - @include ms-font-xl; - @include ms-fontColor-white; - } - - .subTitle { - @include ms-font-l; - @include ms-fontColor-white; - } - - .description { - @include ms-font-l; - @include ms-fontColor-white; - } - - .button { - // Our button - text-decoration: none; - height: 32px; - - // Primary Button - min-width: 80px; - background-color: $ms-color-themePrimary; - border-color: $ms-color-themePrimary; - color: $ms-color-white; - - // Basic Button - outline: transparent; - position: relative; - font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; - -webkit-font-smoothing: antialiased; - font-size: $ms-font-size-m; - font-weight: $ms-font-weight-regular; - border-width: 0; - text-align: center; - cursor: pointer; - display: inline-block; - padding: 0 16px; - - .label { - font-weight: $ms-font-weight-semibold; - font-size: $ms-font-size-m; - height: 32px; - line-height: 32px; - margin: 0 4px; - vertical-align: top; - display: inline-block; - } - } -} \ No newline at end of file diff --git a/samples/react-kanban-board/src/webparts/kanbanBoard/components/KanbanBoard.tsx b/samples/react-kanban-board/src/webparts/kanbanBoard/components/KanbanBoard.tsx deleted file mode 100644 index 0172a05a7..000000000 --- a/samples/react-kanban-board/src/webparts/kanbanBoard/components/KanbanBoard.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import * as React from 'react'; -import styles from './KanbanBoard.module.scss'; -import { IKanbanBoardProps } from './IKanbanBoardProps'; -import {sp} from '@pnp/sp'; -import { Spinner } from 'office-ui-fabric-react/lib/Spinner'; -import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react/lib/Dialog'; -import { DefaultButton } from 'office-ui-fabric-react/lib/Button'; -import { IStackStyles, Stack } from 'office-ui-fabric-react/lib/Stack'; - -import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser'; - -import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css'; -import 'jqwidgets-scripts/jqwidgets/styles/jqx.metro.css'; -import JqxKanban, { IKanbanProps, jqx, IKanbanSource } from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxkanban'; - -const rowStyle1: IStackStyles = { - root:{ - flexBasis:"30%" - } -}; -const rowStyle2: IStackStyles = { - root:{ - flexBasis:"70%" - } -}; - -export interface ICustomKanbanProps extends IKanbanProps{ - listTitle: string; - showBoard: boolean; - noItems: boolean; - taskDetails: IKanbanSource; - hideDialog: boolean; -} - -export default class KanbanBoard extends React.Component { - - private sourceFields: any[] = [ - { name: 'id', map:'Id', type: 'string' }, - { name: 'status', map: 'Status', type: 'string' }, - { name: 'text', map: 'Title', type: 'string' }, - { name: 'tags',map:'Priority', type: 'string' }, - { name: 'color',map:'PercentComplete', type: 'string' }, - { name: 'resourceId', map: 'AssignedToId', type: 'number' }, - { name: 'content', map:'Body', type: 'string'}, - { name: 'percent', map:'PercentComplete', type: 'number'}, - { name: 'priority', map:'Priority', type: 'string'} - ]; - - private resourceFields : any[] = [ - { name: 'id', map:'Id', type: 'number' }, - { name: 'name', map:'Title', type: 'string' }, - { name: 'image', type: 'string' }, - { name: 'common', type: 'boolean' }, - { name: 'email', type: 'string', map: 'Email' } - ]; - - constructor(props: IKanbanBoardProps) { - super(props); - - const template: string = - '
' - + '
' - + '
' - + '
' - + '
'; - const itemRenderer = (element: any, item: any, resource: any): void => { - let precentComplete = item.color as Number; - let style = ""; - if(precentComplete <= .3) - { - style = "background-color:red"; - } - else if(precentComplete <= .7) - { - style = "background-color:orange"; - } - element[0].getElementsByClassName('jqx-kanban-item-color-status')[0].style = style; - if(!resource.common) - element[0].getElementsByClassName('jqx-kanban-item-avatar-image')[0].src = this.props.webUrl + "/_layouts/15/userphoto.aspx?size=M&username=" + resource.email; - }; - - this.state = { - template: template, - itemRenderer, - width: "100%", - listTitle: this.props.listTitle, - showBoard: false, - noItems: true, - taskDetails: {}, - hideDialog:true - }; - } - - public render(): React.ReactElement { - const el = this.state.showBoard ? - !this.state.noItems ? :
No tasks found!
: ; - const selectlist = !(this.state.listTitle && this.state.listTitle.length > 0) ?
Please choose a list
: null; - return (<> - {selectlist} - {el} - - - - ); - } - - public static getDerivedStateFromProps(nextProps, prevState){ - if(nextProps.listTitle!==prevState.listTitle){ - return { listTitle: nextProps.listTitle}; - } - else return null; - } - - public componentDidUpdate(prevProps, prevState) { - if (prevState.listTitle !== this.state.listTitle) { - this.setState({ listTitle: this.props.listTitle,showBoard:false }); - this._getData(this.props.listTitle); - } - } - - public componentDidMount(){ - this._getData(this.props.listTitle); - } - - private _getData = (listTitle) => { - if(listTitle && listTitle.length > 0) - { - sp.web.lists.getByTitle(listTitle).fields.getByInternalNameOrTitle("Status").get() - .then(status => { - - const cols = status.Choices.map((val,index) => { - return { text: val, dataField: val }; - }); - - sp.web.lists.getByTitle(listTitle).items.getAll().then(res => { - - const source = { - dataFields: this.sourceFields, - dataType: 'array', - localData: [ ...res ] - }; - - sp.web.siteUsers.get().then(users => { - const resourcesAdapterFunc = (): any => { - const resourcesSource = { - dataFields: this.resourceFields, - dataType: 'array', - localData: [...users] - }; - const resourcesDataAdapter = new jqx.dataAdapter(resourcesSource); - return resourcesDataAdapter; - }; - - this.setState({ - width: "100%", - columns: cols, - resources: resourcesAdapterFunc(), - source: new jqx.dataAdapter(source), - showBoard: true, - noItems: source.localData.length <= 0 - }); - }); - }); - }); - } else { - this.setState({ - showBoard:true - }); - } - } - - private _updateTask = (event: any): void => { - let args = event.args; - // let itemId = args.itemId; - // let oldParentId = args.oldParentId; - // let newParentId = args.newParentId; - // let itemData = args.itemData; - // let oldColumn = args.oldColumn; - // let newColumn = args.newColumn; - sp.web.lists.getByTitle(this.props.listTitle).items.getById(args.itemId).update({ - Status: args.newColumn.dataField - }).then(res => { - console.log("Task updated"); - }); - } - - private _showTask = (event:any): void => { - if(event.args.attribute === "template") - { - this.setState({ - taskDetails : { - ...event.args.item - }, - hideDialog: false - }); - } - } - - private _closeDialog = (): void => { - this.setState({ hideDialog: true }); - } -} diff --git a/samples/react-kanban-board/src/webparts/kanbanBoard/services/MockKanbanService.ts b/samples/react-kanban-board/src/webparts/kanbanBoard/services/MockKanbanService.ts index 294e2aa61..72db6e4c0 100644 --- a/samples/react-kanban-board/src/webparts/kanbanBoard/services/MockKanbanService.ts +++ b/samples/react-kanban-board/src/webparts/kanbanBoard/services/MockKanbanService.ts @@ -2,7 +2,7 @@ import { ISPKanbanService } from "./ISPKanbanService"; import "@pnp/polyfill-ie11"; import { sp } from '@pnp/sp'; import { IKanbanTask, KanbanTaskMamagedPropertyType } from "../../../kanban/IKanbanTask"; -import * as strings from 'KanbanBoardWebPartStrings' +import * as strings from 'KanbanBoardWebPartStrings'; export default class MockKanbanService implements ISPKanbanService { diff --git a/samples/react-kanban-board/src/webparts/kanbanBoard/services/SPKanbanService.ts b/samples/react-kanban-board/src/webparts/kanbanBoard/services/SPKanbanService.ts index 16850b378..029e94253 100644 --- a/samples/react-kanban-board/src/webparts/kanbanBoard/services/SPKanbanService.ts +++ b/samples/react-kanban-board/src/webparts/kanbanBoard/services/SPKanbanService.ts @@ -2,7 +2,7 @@ import { ISPKanbanService } from "./ISPKanbanService"; import "@pnp/polyfill-ie11"; import { sp } from '@pnp/sp'; import { IKanbanTask, KanbanTaskMamagedPropertyType } from "../../../kanban/IKanbanTask"; -import * as strings from 'KanbanBoardWebPartStrings' +import * as strings from 'KanbanBoardWebPartStrings'; export default class SPKanbanService implements ISPKanbanService { @@ -10,7 +10,7 @@ export default class SPKanbanService implements ISPKanbanService { public updateTaskBucketMove(listid: string, taskId: number, bucket: string): Promise { return sp.web.lists.getById(listid).items.getById(+taskId).update({ Status: bucket - }).then(() => { return true; }) + }).then(() => { return true; }); } public getAllTasks(listId: string, ): Promise {