Adde Data Connections
This commit is contained in:
parent
e073836425
commit
4b089918d8
|
@ -67,11 +67,14 @@ Unexpected call to method or property access.
|
|||
|
||||
# Webpart Steps
|
||||
|
||||
|
||||
* DataConnection
|
||||
** Task missing
|
||||
* BucketEdit Does not refresh Component
|
||||
|
||||
|
||||
# Webpart Steps Done
|
||||
* PNP Placeholder Control for Config
|
||||
* PNP WebpartTitle Control
|
||||
* DataConnection
|
||||
* Usage of BucketEdit in pane
|
||||
* PNP Order pane Control
|
||||
|
||||
|
||||
|
||||
* PNP Order pane Control
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version, Guid } from '@microsoft/sp-core-library';
|
||||
import { Version, Guid, Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
||||
import { BaseClientSideWebPart, PropertyPaneDropdown } from '@microsoft/sp-webpart-base';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
|
@ -36,221 +36,219 @@ export interface IKanbanBoardWebPartProps {
|
|||
|
||||
export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoardWebPartProps> {
|
||||
private kanbanComponent = null;
|
||||
public onInit(): Promise < void> {
|
||||
private statekey: string = Date.now().toString();
|
||||
public onInit(): Promise<void> {
|
||||
|
||||
return super.onInit().then(_ => {
|
||||
return super.onInit().then(_ => {
|
||||
|
||||
sp.setup({
|
||||
spfxContext: this.context
|
||||
});
|
||||
|
||||
sp.setup({
|
||||
spfxContext: this.context
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
|
||||
/*
|
||||
const element: React.ReactElement<IKanbanBoardProps > = React.createElement(
|
||||
KanbanBoard,
|
||||
{
|
||||
listTitle: this.properties.listTitle,
|
||||
webUrl: this.context.pageContext.web.absoluteUrl
|
||||
}
|
||||
);
|
||||
*/
|
||||
/*
|
||||
const element: React.ReactElement<IMockKanbanProps > = React.createElement(
|
||||
MockKanban,
|
||||
{
|
||||
|
||||
}
|
||||
);
|
||||
*/
|
||||
const element: React.ReactElement < IKanbanBoardV2Props > = React.createElement(
|
||||
KanbanBoardV2,
|
||||
{
|
||||
hideWPTitle: this.properties.hideWPTitle,
|
||||
title: this.properties.title,
|
||||
displayMode: this.displayMode,
|
||||
updateProperty: (value: string) => {
|
||||
this.properties.title = value;
|
||||
},
|
||||
context: this.context,
|
||||
listId: this.properties.listId,
|
||||
configuredBuckets: this.properties.buckets
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
this.kanbanComponent = ReactDom.render(element, this.domElement);
|
||||
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
const propertypages = [];
|
||||
|
||||
const generalgroups = [];
|
||||
generalgroups.push(
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneToggle('hideWPTitle', {
|
||||
label: 'Hide WP Title',
|
||||
checked: this.properties.hideWPTitle
|
||||
}),
|
||||
PropertyFieldListPicker('listId', {
|
||||
label: 'Select a list',
|
||||
selectedList: this.properties.listId,
|
||||
includeHidden: false,
|
||||
orderBy: PropertyFieldListPickerOrderBy.Title,
|
||||
disabled: false,
|
||||
onPropertyChange: this.listConfigurationChanged.bind(this),
|
||||
properties: this.properties,
|
||||
context: this.context,
|
||||
onGetErrorMessage: null,
|
||||
deferredValidationTime: 0,
|
||||
key: 'listPickerFieldId',
|
||||
onListsRetrieved: (lists) => {
|
||||
//TODO Check from TS Definition it should be a string but i get a number
|
||||
// with Typesafe equal it fails
|
||||
const alists = lists.filter((l: any) => {
|
||||
return (l.BaseTemplate === 171 || l.BaseTemplate === 107);
|
||||
}
|
||||
);
|
||||
return alists;
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
if (this.properties.listId && this.properties.buckets && this.properties.buckets.length > 1) {
|
||||
generalgroups.push(
|
||||
{
|
||||
groupName: "Order Buckets",
|
||||
groupFields: [
|
||||
PropertyFieldOrder("orderedItems", {
|
||||
key: "orderedItems",
|
||||
label: "Ordered Items",
|
||||
items: this.properties.buckets,
|
||||
properties: this.properties,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
onRenderItem: bucketOrder,
|
||||
})
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
propertypages.push({
|
||||
groups: generalgroups
|
||||
});
|
||||
|
||||
if (this.properties.buckets && this.properties.buckets.length > 0) {
|
||||
this.properties.buckets.forEach((b, i) => {
|
||||
propertypages.push({
|
||||
key: { i },
|
||||
header: {
|
||||
description: "Bucket Configuration"
|
||||
public render(): void {
|
||||
/*
|
||||
const element: React.ReactElement<IKanbanBoardProps > = React.createElement(
|
||||
KanbanBoard,
|
||||
{
|
||||
listTitle: this.properties.listTitle,
|
||||
webUrl: this.context.pageContext.web.absoluteUrl
|
||||
}
|
||||
);
|
||||
*/
|
||||
/*
|
||||
const element: React.ReactElement<IMockKanbanProps > = React.createElement(
|
||||
MockKanban,{});
|
||||
*/
|
||||
console.log('bucket render webpart');
|
||||
console.log(this.properties.buckets);
|
||||
const element: React.ReactElement<IKanbanBoardV2Props> = React.createElement(
|
||||
KanbanBoardV2,
|
||||
{
|
||||
hideWPTitle: this.properties.hideWPTitle,
|
||||
title: this.properties.title,
|
||||
displayMode: this.displayMode,
|
||||
updateProperty: (value: string) => {
|
||||
this.properties.title = value;
|
||||
},
|
||||
groups: [{
|
||||
groupName: b.bucketheadline ? b.bucketheadline : b.bucket,
|
||||
statekey: this.statekey,
|
||||
context: this.context,
|
||||
listId: this.properties.listId,
|
||||
configuredBuckets: this.properties.buckets
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
this.kanbanComponent = ReactDom.render(element, this.domElement);
|
||||
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
const propertypages = [];
|
||||
|
||||
const generalgroups = [];
|
||||
generalgroups.push(
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneToggle('hideWPTitle', {
|
||||
label: 'Hide WP Title',
|
||||
checked: this.properties.hideWPTitle
|
||||
}),
|
||||
PropertyFieldListPicker('listId', {
|
||||
label: 'Select a list',
|
||||
selectedList: this.properties.listId,
|
||||
includeHidden: false,
|
||||
orderBy: PropertyFieldListPickerOrderBy.Title,
|
||||
disabled: false,
|
||||
onPropertyChange: this.listConfigurationChanged.bind(this),
|
||||
properties: this.properties,
|
||||
context: this.context,
|
||||
onGetErrorMessage: null,
|
||||
deferredValidationTime: 0,
|
||||
key: 'listPickerFieldId',
|
||||
onListsRetrieved: (lists) => {
|
||||
//TODO Check from TS Definition it should be a string but i get a number
|
||||
// with Typesafe equal it fails
|
||||
if (Environment.type == EnvironmentType.Local || Environment.type == EnvironmentType.Test) {
|
||||
return lists;
|
||||
} else {
|
||||
const alists = lists.filter((l: any) => {
|
||||
return (l.BaseTemplate === 171 || l.BaseTemplate === 107);
|
||||
});
|
||||
return alists;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
if (this.properties.listId && this.properties.buckets && this.properties.buckets.length > 1) {
|
||||
generalgroups.push(
|
||||
{
|
||||
groupName: "Order Buckets",
|
||||
groupFields: [
|
||||
PropertyPaneBucketConfigComponent('bucket_' + i, {
|
||||
key: 'bucket_' + i,
|
||||
properties: cloneDeep(b),
|
||||
onPropertyChange: this.bucketConfigurationChanged.bind(this)
|
||||
PropertyFieldOrder("buckets", {
|
||||
key: "orderedItems",
|
||||
label: "Ordered Items",
|
||||
items: this.properties.buckets,
|
||||
properties: this.properties,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
onRenderItem: bucketOrder,
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
propertypages.push({
|
||||
groups: generalgroups
|
||||
});
|
||||
|
||||
if (this.properties.buckets && this.properties.buckets.length > 0) {
|
||||
this.properties.buckets.forEach((b, i) => {
|
||||
propertypages.push({
|
||||
key: { i },
|
||||
header: {
|
||||
description: "Bucket Configuration"
|
||||
},
|
||||
groups: [{
|
||||
groupName: b.bucketheadline ? b.bucketheadline : b.bucket,
|
||||
groupFields: [
|
||||
PropertyPaneBucketConfigComponent('bucket_' + i, {
|
||||
key: 'bucket_' + i,
|
||||
properties: cloneDeep(b),
|
||||
onPropertyChange: this.bucketConfigurationChanged.bind(this)
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
pages: propertypages
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
pages: propertypages
|
||||
};
|
||||
}
|
||||
|
||||
private listConfigurationChanged(propertyPath: string, oldValue: any, newValue: any) {
|
||||
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
|
||||
this.refreshBucket();
|
||||
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
|
||||
this.refreshBucket();
|
||||
|
||||
}
|
||||
}
|
||||
private bucketConfigurationChanged(propertyPath: string, oldValue: any, newValue: any) {
|
||||
//its an array part !!!!!
|
||||
if (propertyPath.indexOf('bucket_') !== -1) {
|
||||
const newbuckets: IKanbanBucket[] = cloneDeep(this.properties.buckets);
|
||||
const bucketindex: number = +propertyPath.split('_')[1];
|
||||
newbuckets[bucketindex] = newValue;
|
||||
//merge and every else is good
|
||||
//
|
||||
console.log('buckes updated old saved');
|
||||
console.log(oldValue);
|
||||
// this.onPropertyPaneFieldChanged('buckets', this.properties.buckets, newbuckets);
|
||||
this.properties.buckets = cloneDeep(newbuckets);
|
||||
// array child Properties change dows not trigger rerender
|
||||
// i think this is better as an Property With da DateTimeValue to force Rerender
|
||||
console.log('old');
|
||||
console.log(this.properties.buckets);
|
||||
console.log('new');
|
||||
console.log(newbuckets);
|
||||
this.kanbanComponent.forceUpdate();
|
||||
} else {
|
||||
throw "propertypath is not a bucket";
|
||||
//its an array part !!!!!
|
||||
if (propertyPath.indexOf('bucket_') !== -1) {
|
||||
const oribuckets: IKanbanBucket[] = cloneDeep(this.properties.buckets);
|
||||
const newbuckets: IKanbanBucket[] = cloneDeep(this.properties.buckets);
|
||||
const bucketindex: number = +propertyPath.split('_')[1];
|
||||
newbuckets[bucketindex] = newValue;
|
||||
//maybe better to make a array control (Update)
|
||||
|
||||
this.onPropertyPaneFieldChanged("buckets", oribuckets, newbuckets);
|
||||
this.properties.buckets = newbuckets;
|
||||
this.context.propertyPane.refresh();
|
||||
this.render();
|
||||
|
||||
} else {
|
||||
throw "propertypath is not a bucket";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private refreshBucket(): void {
|
||||
const listId = this.properties.listId;
|
||||
if(!listId || listId.length === 0) { return; }
|
||||
const listId = this.properties.listId;
|
||||
if (!listId || listId.length === 0) { return; }
|
||||
|
||||
sp.web.lists.getById(listId).fields.getByInternalNameOrTitle("Status").get()
|
||||
.then(status => {
|
||||
sp.web.lists.getById(listId).fields.getByInternalNameOrTitle("Status").get()
|
||||
.then(status => {
|
||||
|
||||
const cols: string[] = status.Choices.map((val, index) => {
|
||||
return val;
|
||||
});
|
||||
//matching with existing configured buckets
|
||||
const currentbuckets: IKanbanBucket[] = mergeBucketsWithChoices(this.properties.buckets, cols);
|
||||
if (!currentbuckets) {
|
||||
return;
|
||||
}
|
||||
this.properties.buckets = currentbuckets;
|
||||
this.context.propertyPane.refresh();
|
||||
});
|
||||
const cols: string[] = status.Choices.map((val, index) => {
|
||||
return val;
|
||||
});
|
||||
//matching with existing configured buckets
|
||||
const currentbuckets: IKanbanBucket[] = mergeBucketsWithChoices(this.properties.buckets, cols);
|
||||
if (!currentbuckets) {
|
||||
return;
|
||||
}
|
||||
this.properties.buckets = currentbuckets;
|
||||
this.context.propertyPane.refresh();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected onPropertyPaneConfigurationStart() {
|
||||
// Use the list template ID to locate both the old style task lists (107) and newer task lists (171)
|
||||
/*
|
||||
sp.web.lists.filter("BaseTemplate eq 171 or BaseTemplate eq 107").select("Title").get().then(res => {
|
||||
this.properties.lists = res.map((val, index) => {
|
||||
return {
|
||||
key: val.Title,
|
||||
text: val.Title
|
||||
};
|
||||
// Use the list template ID to locate both the old style task lists (107) and newer task lists (171)
|
||||
/*
|
||||
sp.web.lists.filter("BaseTemplate eq 171 or BaseTemplate eq 107").select("Title").get().then(res => {
|
||||
this.properties.lists = res.map((val, index) => {
|
||||
return {
|
||||
key: val.Title,
|
||||
text: val.Title
|
||||
};
|
||||
});
|
||||
this.context.propertyPane.refresh();
|
||||
});
|
||||
this.context.propertyPane.refresh();
|
||||
});
|
||||
*/
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import * as React from 'react';
|
||||
import styles from './KanbanBoardV2.module.scss';
|
||||
import * as strings from 'KanbanBoardWebPartStrings';
|
||||
import { DisplayMode, Guid } from '@microsoft/sp-core-library';
|
||||
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { Spinner } from 'office-ui-fabric-react/lib/Spinner';
|
||||
import { IKanbanBucket } from '../../../kanban/IKanbanBucket';
|
||||
import { IKanbanTask } from '../../../kanban/IKanbanTask';
|
||||
import { IKanbanTask, KanbanTaskMamagedPropertyType } from '../../../kanban/IKanbanTask';
|
||||
import KanbanComponent from '../../../kanban/KanbanComponent';
|
||||
import { findIndex, clone, isEqual } from '@microsoft/sp-lodash-subset';
|
||||
import { findIndex, clone, isEqual, cloneDeep } from '@microsoft/sp-lodash-subset';
|
||||
import { sp } from '@pnp/sp';
|
||||
import { mergeBucketsWithChoices } from './helper';
|
||||
|
||||
|
@ -20,6 +21,7 @@ export interface IKanbanBoardV2Props {
|
|||
context: WebPartContext;
|
||||
listId: string;
|
||||
configuredBuckets: IKanbanBucket[]; // need mearge with current readed
|
||||
statekey: string; // force refresh ;)
|
||||
}
|
||||
|
||||
export interface IKanbanBoardV2State {
|
||||
|
@ -47,11 +49,12 @@ export default class KanbanBoardV2 extends React.Component<IKanbanBoardV2Props,
|
|||
this._getData();
|
||||
}
|
||||
public shouldComponentUpdate(nextProps: IKanbanBoardV2Props, nextState: IKanbanBoardV2State): boolean {
|
||||
|
||||
if (!isEqual(this.state, nextState)) { return true; }
|
||||
if (!isEqual(this.props, nextProps)) {
|
||||
console.log('change in Props found')
|
||||
return true; }
|
||||
if (!isEqual(this.props, nextProps)) {
|
||||
//stateKey
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public componentDidUpdate(prevProps: IKanbanBoardV2Props) {
|
||||
|
@ -59,7 +62,11 @@ export default class KanbanBoardV2 extends React.Component<IKanbanBoardV2Props,
|
|||
if (this.props.listId !== prevProps.listId) {
|
||||
this._getData();
|
||||
}
|
||||
|
||||
const currentPropBuckets: IKanbanBucket[] = mergeBucketsWithChoices(this.props.configuredBuckets, this.choices);
|
||||
if (!isEqual(this.state.buckets, currentPropBuckets)) {
|
||||
this.setState({ buckets: cloneDeep(currentPropBuckets) });
|
||||
}
|
||||
/*
|
||||
const currentbuckets: IKanbanBucket[] = mergeBucketsWithChoices(this.props.configuredBuckets, this.choices);
|
||||
console.log(this.props.configuredBuckets);
|
||||
console.log(currentbuckets);
|
||||
|
@ -68,7 +75,7 @@ export default class KanbanBoardV2 extends React.Component<IKanbanBoardV2Props,
|
|||
|
||||
this.setState({ buckets: currentbuckets });
|
||||
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IKanbanBoardV2Props> {
|
||||
|
@ -123,7 +130,15 @@ export default class KanbanBoardV2 extends React.Component<IKanbanBoardV2Props,
|
|||
const elementsIndex = findIndex(this.state.tasks, element => element.taskId == taskId);
|
||||
let newArray = [...this.state.tasks]; // same as Clone
|
||||
newArray[elementsIndex].bucket = targetBucket.bucket;
|
||||
this.setState({ tasks: newArray });
|
||||
sp.web.lists.getById(this.props.listId).items.getById(+taskId).update({
|
||||
Status: targetBucket.bucket
|
||||
}).then(res => {
|
||||
console.log("Task updated");
|
||||
this.setState({ tasks: newArray });
|
||||
}).catch(error=> {
|
||||
this.setState({ errorMessage: 'Error Update Task Item' });
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -146,16 +161,44 @@ export default class KanbanBoardV2 extends React.Component<IKanbanBoardV2Props,
|
|||
this.setState({ isConfigured: false, loading: false, errorMessage: 'No Buckets found' });
|
||||
return;
|
||||
}
|
||||
sp.web.lists.getById(listId).items.getAll().then(res => {
|
||||
//Map Items to task
|
||||
this.setState({
|
||||
isConfigured: true,
|
||||
loading: false,
|
||||
errorMessage: undefined,
|
||||
buckets: currentbuckets,
|
||||
tasks: []
|
||||
const odatafiels: string[] = ['AssignedTo/Id', 'AssignedTo/Title', 'AssignedTo/Name', 'AssignedTo/EMail',
|
||||
'ID', 'Title', 'Status', 'Priority', 'PercentComplete', 'Body'
|
||||
];
|
||||
|
||||
sp.web.lists.getById(listId).items
|
||||
.select(odatafiels.join(','))
|
||||
.expand('AssignedTo').getAll().then(res => {
|
||||
const tasks: IKanbanTask[] = res.map((x) => {
|
||||
return {
|
||||
taskId: '' + x.ID,
|
||||
title: x.Title,
|
||||
htmlDescription: x.Body,
|
||||
assignedTo: (x.AssignedTo && (x.AssignedTo).length === 1) ?
|
||||
{
|
||||
text: x.AssignedTo[0].Title
|
||||
}
|
||||
: undefined,
|
||||
priority: x.Priority,
|
||||
bucket: x.Status,
|
||||
mamagedProperties: [
|
||||
{
|
||||
name: 'PercentComplete',
|
||||
displayName: strings.PercentComplete,
|
||||
type: KanbanTaskMamagedPropertyType.percent,
|
||||
value: x.PercentComplete
|
||||
}
|
||||
]
|
||||
|
||||
};
|
||||
});
|
||||
this.setState({
|
||||
isConfigured: true,
|
||||
loading: false,
|
||||
errorMessage: undefined,
|
||||
buckets: currentbuckets,
|
||||
tasks: tasks
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ define([], function() {
|
|||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Basic Configuration",
|
||||
"ListTitleFieldLabel": "List Title"
|
||||
"ListTitleFieldLabel": "List Title",
|
||||
"PercentComplete": "Percent Complete"
|
||||
}
|
||||
});
|
|
@ -2,6 +2,7 @@ declare interface IKanbanBoardWebPartStrings {
|
|||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
ListTitleFieldLabel: string;
|
||||
PercentComplete: string;
|
||||
}
|
||||
|
||||
declare module 'KanbanBoardWebPartStrings' {
|
||||
|
|
Loading…
Reference in New Issue