make working under node 18
This commit is contained in:
parent
ecf6e215ca
commit
c410c973ba
|
@ -79,7 +79,7 @@ module.exports = {
|
|||
// This rule should be suppressed only in very special cases such as JSON.stringify()
|
||||
// where the type really can be anything. Even if the type is flexible, another type
|
||||
// may be more appropriate such as "unknown", "{}", or "Record<k,V>".
|
||||
'@typescript-eslint/no-explicit-any': 1,
|
||||
'@typescript-eslint/no-explicit-any': 0,
|
||||
// RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch()
|
||||
// handler. Thus wherever a Promise arises, the code must either append a catch handler,
|
||||
// or else return the object to a caller (who assumes this responsibility). Unterminated
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
v18.17.1
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"msjsdiag.debugger-for-chrome"
|
||||
]
|
||||
}
|
|
@ -1,8 +1,4 @@
|
|||
{
|
||||
/**
|
||||
* Install Chrome Debugger Extension for Visual Studio Code to debug your components with the
|
||||
* Chrome browser: https://aka.ms/spfx-debugger-extensions
|
||||
*/
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
"libraryName": "react-kanban-board",
|
||||
"libraryId": "cccbd72b-7b89-4128-9348-0a4850ded8fd",
|
||||
"packageManager": "npm",
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false,
|
||||
"plusBeta": false,
|
||||
"componentType": "webpart",
|
||||
"sdkVersions": {
|
||||
"@microsoft/teams-js": "2.12.0",
|
||||
|
|
|
@ -74,7 +74,7 @@ Version|Date|Comments
|
|||
1.0.1.0|April 21, 2020|Added support for Teams hosts
|
||||
2.0.0.0|July 10, 2020| jqwidgets replaced with a custom Kanban Board based on Office UI Component and IE11 Support
|
||||
3.0.0.0|October 29, 2021| SPFx 1.13, PnPJS v2, PnP Controls v3
|
||||
4.0.0.0|Jun 1, 2024| SPFx 1.19, PnPJS v4, Node 18
|
||||
4.0.0.0|Jun 1, 2024| SPFx 1.19, PnPJS v4, Node 18 (Property-ListPicker and Property-Order not used from @pnp/spfx-property-controls because of an issue )
|
||||
|
||||
[Read More about the implementation of this Board](./src/kanban/README.md)
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
"shortDescription": "This solution contains an SPFx web part which shows a Kanban board using jqxKanban ReactJS component (from JQWidgets). The web part uses the default columns of the SharePoint Tasks list for showing the board\u0027s columns and the tasks.",
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-kanban-board",
|
||||
"longDescription": [
|
||||
"This solution contains an SPFx web part which shows a Kanban board using jqxKanban ReactJS component (from JQWidgets). The web part uses the default columns of the SharePoint Tasks list for showing the board\u0027s columns and the tasks."
|
||||
"This solution contains an SPFx web part which shows a Kanban board. The web part uses the default columns of the SharePoint Tasks list for showing the board\u0027s columns and the tasks."
|
||||
],
|
||||
"creationDateTime": "2020-07-02",
|
||||
"updateDateTime": "2020-07-02",
|
||||
"updateDateTime": "2024-05-26",
|
||||
"products": [
|
||||
"SharePoint"
|
||||
],
|
||||
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.13.0"
|
||||
"value": "1.19.0"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-TEAMSTAB",
|
||||
|
@ -56,7 +56,7 @@
|
|||
},
|
||||
{
|
||||
"gitHubAccount": "petkir",
|
||||
"company": "Cubido Business Solutions GmbH",
|
||||
"company": "ACP CUBIDO Digital Solutions GmbH",
|
||||
"pictureUrl": "https://github.com/petkir.png",
|
||||
"name": "Peter Paul Kirschner",
|
||||
"twitter": "petkir_at"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"websiteUrl": "",
|
||||
"mpnId": ""
|
||||
"mpnId": "Undefined-1.19.0"
|
||||
},
|
||||
"metadata": {
|
||||
"shortDescription": {
|
||||
|
@ -30,10 +30,7 @@
|
|||
"title": "react-kanban-board KanbanBoardWebPart Feature",
|
||||
"description": "The feature that activates KanbanBoardWebPart from the react-kanban-board solution.",
|
||||
"id": "67cd5938-806b-4c79-b589-501f7f26998e",
|
||||
"version": "3.0.0.0",
|
||||
"componentIds": [
|
||||
"67cd5938-806b-4c79-b589-501f7f26998e"
|
||||
]
|
||||
"version": "4.0.0.0"
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -8389,6 +8389,23 @@
|
|||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/common": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/common/-/common-2.5.0.tgz",
|
||||
"integrity": "sha512-ea4zTNC3sjLolrHZXP+/2SrJM+yC8PygmPW/yRfgbErdvdwYMUSogT69dW+NUaqhkfYZfkkAoWn42irlLMSpdw==",
|
||||
"dependencies": {
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/patrick-rodgers/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/common/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@pnp/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/core/-/core-4.1.0.tgz",
|
||||
|
@ -8409,6 +8426,42 @@
|
|||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/@pnp/logging": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-2.5.0.tgz",
|
||||
"integrity": "sha512-SnmMCN6oADjiHKAIR23FfTqXeQZeXPBnWeVfyZAgzJfRn9uEQoUlkyET3jHjl9kkrFOVkiOD1CRI7TWMIxURbA==",
|
||||
"dependencies": {
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/patrick-rodgers/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/logging/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@pnp/odata": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/odata/-/odata-2.5.0.tgz",
|
||||
"integrity": "sha512-AeP01jDvnkiUVn7V+4FT07chz+G/yzrJDH0Gk+qzujJ393ZO6FwJpJEiOCRh9cxF48gqSj/f7r/IIyDHe0+IpQ==",
|
||||
"dependencies": {
|
||||
"@pnp/common": "2.5.0",
|
||||
"@pnp/logging": "2.5.0",
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/patrick-rodgers/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/odata/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@pnp/queryable": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/queryable/-/queryable-4.1.0.tgz",
|
||||
|
@ -9016,59 +9069,6 @@
|
|||
"react-dom": ">=16.8.0 <19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/common": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/common/-/common-2.5.0.tgz",
|
||||
"integrity": "sha512-ea4zTNC3sjLolrHZXP+/2SrJM+yC8PygmPW/yRfgbErdvdwYMUSogT69dW+NUaqhkfYZfkkAoWn42irlLMSpdw==",
|
||||
"dependencies": {
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/patrick-rodgers/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/common/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/logging": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-2.5.0.tgz",
|
||||
"integrity": "sha512-SnmMCN6oADjiHKAIR23FfTqXeQZeXPBnWeVfyZAgzJfRn9uEQoUlkyET3jHjl9kkrFOVkiOD1CRI7TWMIxURbA==",
|
||||
"dependencies": {
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/patrick-rodgers/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/logging/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/odata": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/odata/-/odata-2.5.0.tgz",
|
||||
"integrity": "sha512-AeP01jDvnkiUVn7V+4FT07chz+G/yzrJDH0Gk+qzujJ393ZO6FwJpJEiOCRh9cxF48gqSj/f7r/IIyDHe0+IpQ==",
|
||||
"dependencies": {
|
||||
"@pnp/common": "2.5.0",
|
||||
"@pnp/logging": "2.5.0",
|
||||
"tslib": "2.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/patrick-rodgers/"
|
||||
}
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/odata/node_modules/tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
},
|
||||
"node_modules/@pnp/spfx-controls-react/node_modules/@pnp/sp": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@pnp/sp/-/sp-2.5.0.tgz",
|
||||
|
@ -10261,6 +10261,67 @@
|
|||
"sudo": "~1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/debug-certificate-manager/node_modules/@rushstack/node-core-library": {
|
||||
"version": "3.53.2",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.2.tgz",
|
||||
"integrity": "sha512-FggLe5DQs0X9MNFeJN3/EXwb+8hyZUTEp2i+V1e8r4Va4JgkjBNY0BuEaQI+3DW6S4apV3UtXU3im17MSY00DA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "12.20.24",
|
||||
"colors": "~1.2.1",
|
||||
"fs-extra": "~7.0.1",
|
||||
"import-lazy": "~4.0.0",
|
||||
"jju": "~1.4.0",
|
||||
"resolve": "~1.17.0",
|
||||
"semver": "~7.3.0",
|
||||
"z-schema": "~5.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/debug-certificate-manager/node_modules/@types/node": {
|
||||
"version": "12.20.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz",
|
||||
"integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@rushstack/debug-certificate-manager/node_modules/commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/debug-certificate-manager/node_modules/validator": {
|
||||
"version": "13.12.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
|
||||
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/debug-certificate-manager/node_modules/z-schema": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
|
||||
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.7.0"
|
||||
},
|
||||
"bin": {
|
||||
"z-schema": "bin/z-schema"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"commander": "^9.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/eslint-config": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-config/-/eslint-config-2.5.1.tgz",
|
||||
|
@ -11086,9 +11147,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rushstack/node-core-library": {
|
||||
"version": "3.53.2",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.2.tgz",
|
||||
"integrity": "sha512-FggLe5DQs0X9MNFeJN3/EXwb+8hyZUTEp2i+V1e8r4Va4JgkjBNY0BuEaQI+3DW6S4apV3UtXU3im17MSY00DA==",
|
||||
"version": "3.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.53.3.tgz",
|
||||
"integrity": "sha512-H0+T5koi5MFhJUd5ND3dI3bwLhvlABetARl78L3lWftJVQEPyzcgTStvTTRiIM5mCltyTM8VYm6BuCtNUuxD0Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "12.20.24",
|
||||
|
@ -13159,9 +13220,9 @@
|
|||
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw=="
|
||||
},
|
||||
"node_modules/@types/minimatch": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
|
||||
"integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
|
||||
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/minimist": {
|
||||
|
@ -15964,9 +16025,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001625",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz",
|
||||
"integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==",
|
||||
"version": "1.0.30001626",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001626.tgz",
|
||||
"integrity": "sha512-JRW7kAH8PFJzoPCJhLSHgDgKg5348hsQ68aqb+slnzuB5QFERv846oA/mRChmlLAOdEDeOkRn3ynb1gSFnjt3w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -16725,9 +16786,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
|
@ -17069,6 +17130,58 @@
|
|||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-selector-tokenizer": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
|
||||
|
@ -18018,28 +18131,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"dev": true,
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dom7": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.6.tgz",
|
||||
|
@ -18070,12 +18173,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"dev": true,
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
|
@ -18085,14 +18187,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"dev": true,
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
|
@ -18287,6 +18388,15 @@
|
|||
"once": "~1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream/node_modules/once": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
|
||||
"integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.16.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz",
|
||||
|
@ -21799,20 +21909,6 @@
|
|||
"htmlparser2": "9.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-dom-parser/node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/html-encoding-sniffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
|
||||
|
@ -21901,20 +21997,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/html-react-parser/node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
|
||||
|
@ -21933,46 +22015,6 @@
|
|||
"entities": "^4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2/node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2/node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2/node_modules/domutils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||
|
@ -25984,6 +26026,12 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/multimatch/node_modules/@types/minimatch": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
|
||||
"integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/multimatch/node_modules/array-differ": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
|
||||
|
@ -26999,9 +27047,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
|
||||
"integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
|
@ -27136,6 +27184,15 @@
|
|||
"once": "~1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/orchestrator/node_modules/once": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
|
||||
"integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/ordered-read-streams": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
|
||||
|
@ -32803,6 +32860,12 @@
|
|||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/verror/node_modules/core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vinyl": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
|
||||
|
|
|
@ -44,20 +44,7 @@ export class KanbanBucketConfigurator extends React.Component<IKanbanBucketConfi
|
|||
}
|
||||
|
||||
public render(): React.ReactElement<IKanbanBucketConfiguratorProps> {
|
||||
/*
|
||||
const columnProps: Partial<IStackProps> = {
|
||||
gap: 15,
|
||||
styles: { root: { width: 300 } },
|
||||
};*/
|
||||
/*
|
||||
const colorPickerStyles: Partial<IColorPickerStyles> = {
|
||||
panel: { padding: 12 },
|
||||
root: {
|
||||
maxWidth: 352,
|
||||
minWidth: 352,
|
||||
},
|
||||
colorRectangle: { height: 268 },
|
||||
};*/
|
||||
|
||||
const statebucket = this.state.bucket;
|
||||
if (!statebucket) {
|
||||
return (<div />);
|
||||
|
|
|
@ -83,6 +83,7 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
|
|||
}
|
||||
|
||||
private _openDetails(): void {
|
||||
console.log('openDetails');
|
||||
if (this.props.openDetails) {
|
||||
this.props.openDetails(this.props.taskId);
|
||||
}
|
||||
|
|
|
@ -40,11 +40,11 @@ export default class KanbanTaskManagedProp extends React.Component<IKanbanTaskMa
|
|||
//TODO maybe Formater
|
||||
break;
|
||||
case KanbanTaskMamagedPropertyType.percent:
|
||||
return (<span>{`${(value as any) * 100}%`} </span>);
|
||||
return (value?<span>{`${(value as any) * 100}%`} </span>:<span/>);
|
||||
//TODO maybe better Formater
|
||||
break;
|
||||
case KanbanTaskMamagedPropertyType.html:
|
||||
return (<span>{HTMLReactParser(value)}</span>);
|
||||
return (value?<span>{HTMLReactParser(value)}</span>:<span/>);
|
||||
break;
|
||||
case KanbanTaskMamagedPropertyType.person:
|
||||
|
||||
|
|
|
@ -9,14 +9,18 @@ import {
|
|||
} from '@microsoft/sp-property-pane';
|
||||
import { cloneDeep } from '@microsoft/sp-lodash-subset';
|
||||
|
||||
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
||||
import { PropertyFieldOrder } from '@pnp/spfx-property-controls/lib/PropertyFieldOrder';
|
||||
//import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls';
|
||||
|
||||
import * as strings from 'KanbanBoardWebPartStrings';
|
||||
import { spfi, SPFx } from "@pnp/sp";
|
||||
import { spfi, SPFx } from "@pnp/sp";
|
||||
|
||||
import PropertyPaneBucketConfigComponent from './components/PropertyPaneBucketConfig';
|
||||
import KanbanBoardV2, { IKanbanBoardV2Props } from './components/KanbanBoardV2';
|
||||
|
||||
import { bucketOrder } from './components/bucketOrder';
|
||||
import { PropertyFieldOrder } from './components/PropertyOrderField/PropertyFieldOrder';
|
||||
|
||||
|
||||
import { mergeBucketsWithChoices } from './components/helper';
|
||||
|
||||
import { IKanbanBucket } from '../../kanban';
|
||||
|
@ -24,6 +28,7 @@ import { IKanbanBucket } from '../../kanban';
|
|||
import { ISPKanbanService } from './services/ISPKanbanService';
|
||||
import SPKanbanService from './services/SPKanbanService';
|
||||
import MockKanbanService from './services/MockKanbanService';
|
||||
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from './components/PropertyListPicker';
|
||||
|
||||
export interface IKanbanBoardWebPartProps {
|
||||
hideWPTitle: boolean;
|
||||
|
@ -42,9 +47,9 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
|
|||
|
||||
return super.onInit().then(_ => {
|
||||
|
||||
const sp = spfi().using(SPFx( this.context));
|
||||
const sp = spfi().using(SPFx(this.context));
|
||||
//.using(PnPLogging(LogLevel.Warning));
|
||||
if ( Environment.type === EnvironmentType.Test) {
|
||||
if (Environment.type === EnvironmentType.Test) {
|
||||
this.dataService = new MockKanbanService();
|
||||
} else {
|
||||
this.dataService = new SPKanbanService(sp);
|
||||
|
@ -107,7 +112,7 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
|
|||
onPropertyChange: this.listConfigurationChanged.bind(this),
|
||||
properties: this.properties,
|
||||
context: (this.context as any),
|
||||
onGetErrorMessage: ()=>'', //TODO
|
||||
onGetErrorMessage: () => '', //TODO
|
||||
deferredValidationTime: 0,
|
||||
key: 'listPickerFieldId',
|
||||
onListsRetrieved: (lists) => {
|
||||
|
@ -132,14 +137,14 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
|
|||
{
|
||||
groupName: strings.propertyPaneLabelOrderBuckets,
|
||||
groupFields: [
|
||||
PropertyFieldOrder("buckets", {
|
||||
PropertyFieldOrder("buckets", {
|
||||
key: "orderedItems",
|
||||
label: strings.propertyPaneLabelOrderBuckets,
|
||||
items: this.properties.buckets,
|
||||
properties: this.properties,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
onRenderItem: bucketOrder,
|
||||
})
|
||||
})
|
||||
]
|
||||
}
|
||||
);
|
||||
|
@ -174,12 +179,14 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
|
|||
};
|
||||
}
|
||||
|
||||
private listConfigurationChanged(propertyPath: string, oldValue: any, newValue: any):void {
|
||||
public listConfigurationChanged(propertyPath: string, oldValue: any, newValue: any): void {
|
||||
console.log('listConfigurationChanged');
|
||||
this.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
|
||||
|
||||
this.refreshBucket();
|
||||
|
||||
}
|
||||
private bucketConfigurationChanged(propertyPath: string, oldValue: any, newValue: any):void {
|
||||
private bucketConfigurationChanged(propertyPath: string, oldValue: any, newValue: any): void {
|
||||
//its an array part !!!!!
|
||||
if (propertyPath.indexOf('bucket_') !== -1) {
|
||||
const oribuckets: IKanbanBucket[] = cloneDeep(this.properties.buckets);
|
||||
|
@ -209,7 +216,7 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
|
|||
this.context.propertyPane.refresh();
|
||||
}
|
||||
)
|
||||
.catch(error => { throw new Error('Error loading Buckets by refreshBucket') });
|
||||
.catch(error => { throw new Error('Error loading Buckets by refreshBucket') });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
.errorMessage {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #a80000;
|
||||
margin: 0;
|
||||
padding-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.errorIcon {
|
||||
font-size: 14px;
|
||||
margin-right: 5px;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import * as React from 'react';
|
||||
import styles from './FieldErrorMessage.module.scss';
|
||||
import { Icon } from '@fluentui/react/lib/Icon';
|
||||
|
||||
export interface IFieldErrorMessageProps {
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that shows an error message when something went wront with the property control
|
||||
*/
|
||||
export default class FieldErrorMessage extends React.Component<IFieldErrorMessageProps> {
|
||||
public render(): JSX.Element {
|
||||
if (this.props.errorMessage !== 'undefined' && this.props.errorMessage !== null && this.props.errorMessage !== '') {
|
||||
return (
|
||||
<div aria-live="assertive">
|
||||
<p className={`ms-TextField-errorMessage ${styles.errorMessage}`}>
|
||||
<Icon iconName='Error' className={styles.errorIcon} />
|
||||
<span data-automation-id="error-message">{this.props.errorMessage}</span>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { IChoiceGroupOption } from '@fluentui/react/lib/ChoiceGroup';
|
||||
import { IPropertyFieldListPickerPropsInternal } from './IPropertyFieldListPicker';
|
||||
import { ISPLists } from './IPropertyFieldListPickerHost';
|
||||
|
||||
/**
|
||||
* PropertyFieldListPickerHost properties interface
|
||||
*/
|
||||
export interface IPropertyFieldListMultiPickerHostProps extends IPropertyFieldListPickerPropsInternal {
|
||||
|
||||
onChange: (targetProperty?: string, newValue?: any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
/**
|
||||
* PropertyFieldSPListMultiplePickerHost state interface
|
||||
*/
|
||||
export interface IPropertyFieldListMultiPickerHostState {
|
||||
loadedLists: ISPLists;
|
||||
results: IChoiceGroupOption[];
|
||||
selectedKeys: string[];
|
||||
loaded: boolean;
|
||||
errorMessage?: string;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
import { BaseComponentContext } from '@microsoft/sp-component-base';
|
||||
import { ISPList } from './IPropertyFieldListPickerHost';
|
||||
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
|
||||
|
||||
/**
|
||||
* Detailed list information
|
||||
*/
|
||||
export interface IPropertyFieldList {
|
||||
/**
|
||||
* List ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* List Title
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* List server relative URL
|
||||
*/
|
||||
url?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for specifying how the lists should be sorted
|
||||
*/
|
||||
export enum PropertyFieldListPickerOrderBy {
|
||||
Id = 1,
|
||||
Title
|
||||
}
|
||||
|
||||
/**
|
||||
* Public properties of the PropertyFieldListPicker custom field
|
||||
*/
|
||||
export interface IPropertyFieldListPickerProps {
|
||||
|
||||
/**
|
||||
* Property field label displayed on top
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* Context of the current web part
|
||||
*/
|
||||
context: BaseComponentContext;
|
||||
/**
|
||||
* Absolute Web Url of target site (user requires permissions)
|
||||
*/
|
||||
webAbsoluteUrl?: string;
|
||||
/**
|
||||
* Initial selected list set of the control
|
||||
*/
|
||||
selectedList?: string | string[] | IPropertyFieldList | IPropertyFieldList[];
|
||||
/**
|
||||
* BaseTemplate ID(s) of the lists or libraries you want to return.
|
||||
*/
|
||||
baseTemplate?: number | number[];
|
||||
/**
|
||||
* Specify if you want to include or exclude hidden lists. By default this is true.
|
||||
*/
|
||||
includeHidden?: boolean;
|
||||
/**
|
||||
* Specify the property on which you want to order the retrieve set of lists.
|
||||
*/
|
||||
orderBy?: PropertyFieldListPickerOrderBy;
|
||||
|
||||
|
||||
/**
|
||||
* Defines a onPropertyChange function to raise when the selected value changed.
|
||||
* Normally this function must be always defined with the 'this.onPropertyChange'
|
||||
* method of the web part object.
|
||||
*/
|
||||
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
/**
|
||||
* Parent Web Part properties
|
||||
*/
|
||||
properties: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
/**
|
||||
* An UNIQUE key indicates the identity of this control
|
||||
*/
|
||||
key?: string;
|
||||
/**
|
||||
* Whether the property pane field is enabled or not.
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* The method is used to get the validation error message and determine whether the input value is valid or not.
|
||||
*
|
||||
* When it returns string:
|
||||
* - If valid, it returns empty string.
|
||||
* - If invalid, it returns the error message string and the text field will
|
||||
* show a red border and show an error message below the text field.
|
||||
*
|
||||
* When it returns Promise<string>:
|
||||
* - The resolved value is display as error message.
|
||||
* - The rejected, the value is thrown away.
|
||||
*
|
||||
*/
|
||||
onGetErrorMessage?: (value: string) => string | Promise<string>;
|
||||
/**
|
||||
* Custom Field will start to validate after users stop typing for `deferredValidationTime` milliseconds.
|
||||
* Default value is 200.
|
||||
*/
|
||||
deferredValidationTime?: number;
|
||||
/**
|
||||
* Defines list titles which should be excluded from the list picker control
|
||||
*/
|
||||
listsToExclude?: string[];
|
||||
/**
|
||||
* Filter list from Odata query (takes precendents over Hidden and BaseTemplate Filters)
|
||||
*/
|
||||
filter?: string;
|
||||
/**
|
||||
* Callback that is called before the dropdown is populated
|
||||
*/
|
||||
onListsRetrieved?: (lists: ISPList[]) => PromiseLike<ISPList[]> | ISPList[];
|
||||
|
||||
/**
|
||||
* Specifies if the picker returns list id, title and url as an object instead on id.
|
||||
*/
|
||||
includeListTitleAndUrl?: boolean;
|
||||
/**
|
||||
* Content type id which, if present, must be on the list
|
||||
*/
|
||||
contentTypeId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private properties of the PropertyFieldListPicker custom field.
|
||||
* We separate public & private properties to include onRender & onDispose method waited
|
||||
* by the PropertyFieldCustom, witout asking to the developer to add it when he's using
|
||||
* the PropertyFieldListPicker.
|
||||
*
|
||||
*/
|
||||
export interface IPropertyFieldListPickerPropsInternal extends IPropertyFieldListPickerProps, IPropertyPaneCustomFieldProps {
|
||||
|
||||
label: string;
|
||||
targetProperty: string;
|
||||
context: BaseComponentContext;
|
||||
webAbsoluteUrl?: string;
|
||||
selectedList?: string | IPropertyFieldList;
|
||||
baseTemplate?: number | number[];
|
||||
orderBy?: PropertyFieldListPickerOrderBy;
|
||||
includeHidden?: boolean;
|
||||
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
properties: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
key: string;
|
||||
disabled?: boolean;
|
||||
onGetErrorMessage?: (value: string | string[]) => string | Promise<string>;
|
||||
deferredValidationTime?: number;
|
||||
listsToExclude?: string[];
|
||||
filter?: string;
|
||||
onListsRetrieved?: (lists: ISPList[]) => PromiseLike<ISPList[]> | ISPList[];
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { IPropertyFieldListPickerPropsInternal } from './IPropertyFieldListPicker';
|
||||
import { IDropdownOption } from '@fluentui/react/lib/Dropdown';
|
||||
|
||||
/**
|
||||
* PropertyFieldListPickerHost properties interface
|
||||
*/
|
||||
export interface IPropertyFieldListPickerHostProps extends IPropertyFieldListPickerPropsInternal {
|
||||
|
||||
onChange: (targetProperty?: string, newValue?: any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
/**
|
||||
* PropertyFieldListPickerHost state interface
|
||||
*/
|
||||
export interface IPropertyFieldListPickerHostState {
|
||||
loadedLists: ISPLists;
|
||||
results: IDropdownOption[];
|
||||
selectedKey?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a collection of SharePoint lists
|
||||
*/
|
||||
export interface ISPLists {
|
||||
|
||||
value: ISPList[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a Content Type
|
||||
*/
|
||||
export interface ISPContentType{
|
||||
StringId:string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a SharePoint list
|
||||
*/
|
||||
export interface ISPList {
|
||||
|
||||
Title: string;
|
||||
Id: string;
|
||||
BaseTemplate: string;
|
||||
RootFolder: {
|
||||
ServerRelativeUrl: string;
|
||||
};
|
||||
ContentTypes: Array<ISPContentType>;
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import {
|
||||
IPropertyPaneField,
|
||||
PropertyPaneFieldType
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseComponentContext } from '@microsoft/sp-component-base';
|
||||
import PropertyFieldListPickerHost from './PropertyFieldListPickerHost';
|
||||
import { IPropertyFieldListPickerHostProps, ISPList } from './IPropertyFieldListPickerHost';
|
||||
import { PropertyFieldListPickerOrderBy, IPropertyFieldListPickerProps, IPropertyFieldListPickerPropsInternal, IPropertyFieldList } from './IPropertyFieldListPicker';
|
||||
|
||||
/**
|
||||
* Represents a PropertyFieldListPicker object
|
||||
*/
|
||||
class PropertyFieldListPickerBuilder implements IPropertyPaneField<IPropertyFieldListPickerPropsInternal> {
|
||||
|
||||
//Properties defined by IPropertyPaneField
|
||||
public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
|
||||
public targetProperty: string;
|
||||
public properties: IPropertyFieldListPickerPropsInternal;
|
||||
|
||||
//Custom properties label: string;
|
||||
private label: string;
|
||||
private context: BaseComponentContext;
|
||||
private webAbsoluteUrl?: string;
|
||||
private selectedList: string | IPropertyFieldList|undefined;
|
||||
private baseTemplate: number | number[]|undefined;
|
||||
private orderBy: PropertyFieldListPickerOrderBy;
|
||||
private includeHidden: boolean;
|
||||
private listsToExclude: string[];
|
||||
private includeListTitleAndUrl: boolean;
|
||||
|
||||
public onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void { /* no-op; */ } // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
private customProperties: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
private key: string;
|
||||
private disabled: boolean = false;
|
||||
private onGetErrorMessage: (value: string) => string | Promise<string>;
|
||||
private deferredValidationTime: number = 200;
|
||||
private filter: string|undefined;
|
||||
private contentTypeId: string|undefined;
|
||||
private onListsRetrieved?: (lists: ISPList[]) => PromiseLike<ISPList[]> | ISPList[];
|
||||
/**
|
||||
* Constructor method
|
||||
*/
|
||||
public constructor(_targetProperty: string, _properties: IPropertyFieldListPickerPropsInternal) {
|
||||
this.render = this.render.bind(this);
|
||||
this.targetProperty = _targetProperty;
|
||||
this.properties = _properties;
|
||||
this.properties.onDispose = this.dispose;
|
||||
this.properties.onRender = this.render;
|
||||
this.label = _properties.label;
|
||||
this.context = _properties.context;
|
||||
this.webAbsoluteUrl = _properties.webAbsoluteUrl;
|
||||
this.selectedList = _properties.selectedList;
|
||||
this.baseTemplate = _properties.baseTemplate;
|
||||
this.orderBy = _properties.orderBy?_properties.orderBy:PropertyFieldListPickerOrderBy.Title;
|
||||
|
||||
this.includeHidden = _properties.includeHidden?_properties.includeHidden:false;
|
||||
this.onPropertyChange = _properties.onPropertyChange;
|
||||
this.customProperties = _properties.properties;
|
||||
this.key = _properties.key;
|
||||
this.onGetErrorMessage = _properties.onGetErrorMessage?_properties.onGetErrorMessage:() => '';
|
||||
this.listsToExclude = _properties.listsToExclude?_properties.listsToExclude:[];
|
||||
this.filter = _properties.filter;
|
||||
this.onListsRetrieved = _properties.onListsRetrieved;
|
||||
this.includeListTitleAndUrl = _properties.includeListTitleAndUrl?_properties.includeListTitleAndUrl:false;
|
||||
this.contentTypeId=_properties.contentTypeId;
|
||||
|
||||
if (_properties.disabled === true) {
|
||||
this.disabled = _properties.disabled;
|
||||
}
|
||||
if (_properties.deferredValidationTime) {
|
||||
this.deferredValidationTime = _properties.deferredValidationTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the SPListPicker field content
|
||||
*/
|
||||
private render(elem: HTMLElement, ctx?: any, changeCallback?: (targetProperty?: string, newValue?: any) => void): void { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const componentProps: IPropertyFieldListPickerHostProps = {
|
||||
label: this.label,
|
||||
targetProperty: this.targetProperty,
|
||||
context: this.context,
|
||||
webAbsoluteUrl: this.webAbsoluteUrl,
|
||||
baseTemplate: this.baseTemplate,
|
||||
orderBy: this.orderBy,
|
||||
|
||||
includeHidden: this.includeHidden,
|
||||
onDispose: this.dispose,
|
||||
onRender: this.render,
|
||||
onChange: (target,value) => ( changeCallback && changeCallback(target,value)),
|
||||
onPropertyChange: this.onPropertyChange,
|
||||
properties: this.customProperties,
|
||||
key: this.key,
|
||||
disabled: this.disabled,
|
||||
onGetErrorMessage: this.onGetErrorMessage,
|
||||
deferredValidationTime: this.deferredValidationTime,
|
||||
listsToExclude: this.listsToExclude,
|
||||
filter: this.filter,
|
||||
onListsRetrieved: this.onListsRetrieved,
|
||||
includeListTitleAndUrl: this.includeListTitleAndUrl,
|
||||
contentTypeId:this.contentTypeId
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Single selector
|
||||
componentProps.selectedList = this.selectedList;
|
||||
const element: React.ReactElement<IPropertyFieldListPickerHostProps> = React.createElement(PropertyFieldListPickerHost, componentProps);
|
||||
// Calls the REACT content generator
|
||||
ReactDom.render(element, elem);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the current object
|
||||
*/
|
||||
private dispose(elem: HTMLElement): void {
|
||||
ReactDom.unmountComponentAtNode(elem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a SPList Picker on the PropertyPane.
|
||||
* @param targetProperty - Target property the SharePoint list picker is associated to.
|
||||
* @param properties - Strongly typed SPList Picker properties.
|
||||
*/
|
||||
export function PropertyFieldListPicker(targetProperty: string, properties: IPropertyFieldListPickerProps): IPropertyPaneField<IPropertyFieldListPickerPropsInternal> {
|
||||
|
||||
//Create an internal properties object from the given properties
|
||||
const newProperties: IPropertyFieldListPickerPropsInternal = {
|
||||
label: properties.label,
|
||||
targetProperty: targetProperty,
|
||||
context: properties.context,
|
||||
webAbsoluteUrl: properties.webAbsoluteUrl,
|
||||
selectedList: !Array.isArray(properties.selectedList) ? properties.selectedList : undefined,
|
||||
baseTemplate: properties.baseTemplate,
|
||||
orderBy: properties.orderBy,
|
||||
|
||||
includeHidden: properties.includeHidden,
|
||||
onPropertyChange: properties.onPropertyChange,
|
||||
properties: properties.properties,
|
||||
onDispose: undefined,
|
||||
onRender: (elem: HTMLElement, ctx?: any, changeCallback?: (targetProperty?: string, newValue?: any) => void): void => { /* no-op; */ }, // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
key: "key"+properties.key,
|
||||
disabled: properties.disabled,
|
||||
onGetErrorMessage: properties.onGetErrorMessage,
|
||||
deferredValidationTime: properties.deferredValidationTime,
|
||||
listsToExclude: properties.listsToExclude,
|
||||
filter: properties.filter,
|
||||
onListsRetrieved: properties.onListsRetrieved,
|
||||
includeListTitleAndUrl: properties.includeListTitleAndUrl,
|
||||
contentTypeId:properties.contentTypeId
|
||||
};
|
||||
//Calls the PropertyFieldListPicker builder object
|
||||
//This object will simulate a PropertyFieldCustom to manage his rendering process
|
||||
return new PropertyFieldListPickerBuilder(targetProperty, newProperties);
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
import * as React from 'react';
|
||||
import { Dropdown, IDropdownOption } from '@fluentui/react/lib/Dropdown';
|
||||
import { Async } from '@fluentui/react/lib/Utilities';
|
||||
import { Label } from '@fluentui/react/lib/Label';
|
||||
import { IPropertyFieldListPickerHostProps, IPropertyFieldListPickerHostState, ISPList } from './IPropertyFieldListPickerHost';
|
||||
|
||||
import { IPropertyFieldList } from './IPropertyFieldListPicker';
|
||||
import SPListPickerService from './SPListPickerService';
|
||||
import { setPropertyValue } from '../PropertyOrderField/helper';
|
||||
import FieldErrorMessage from './FieldErrorMessage';
|
||||
|
||||
// Empty list value, to be checked for single list selection
|
||||
const EMPTY_LIST_KEY = 'NO_LIST_SELECTED';
|
||||
|
||||
/**
|
||||
* Renders the controls for PropertyFieldListPicker component
|
||||
*/
|
||||
export default class PropertyFieldListPickerHost extends React.Component<IPropertyFieldListPickerHostProps, IPropertyFieldListPickerHostState> {
|
||||
|
||||
private latestValidateValue: string;
|
||||
private async: Async;
|
||||
private delayedValidate: (value: string) => void;
|
||||
|
||||
/**
|
||||
* Constructor method
|
||||
*/
|
||||
constructor(props: IPropertyFieldListPickerHostProps) {
|
||||
super(props);
|
||||
|
||||
|
||||
this.state = {
|
||||
loadedLists: {
|
||||
value: []
|
||||
},
|
||||
results: [],
|
||||
errorMessage: ''
|
||||
};
|
||||
|
||||
this.async = new Async(this);
|
||||
this.validate = this.validate.bind(this);
|
||||
this.onChanged = this.onChanged.bind(this);
|
||||
this.notifyAfterValidate = this.notifyAfterValidate.bind(this);
|
||||
this.delayedValidate = this.async.debounce(this.validate, this.props.deferredValidationTime);
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
// Start retrieving the SharePoint lists
|
||||
this.loadLists().then(() => { /* no-op; */ }).catch(() => { /* no-op; */ });
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IPropertyFieldListPickerHostProps, prevState: IPropertyFieldListPickerHostState): void {
|
||||
if (this.props.baseTemplate !== prevProps.baseTemplate ||
|
||||
this.props.webAbsoluteUrl !== prevProps.webAbsoluteUrl) {
|
||||
this.loadLists().then(() => { /* no-op; */ }).catch(() => { /* no-op; */ });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the list from SharePoint current web site, or target site if specified by webRelativeUrl
|
||||
*/
|
||||
private async loadLists(): Promise<void> {
|
||||
|
||||
const {
|
||||
context,
|
||||
selectedList
|
||||
} = this.props;
|
||||
|
||||
const listService: SPListPickerService = new SPListPickerService(this.props, context);
|
||||
const listsToExclude: string[] = this.props.listsToExclude || [];
|
||||
const options = [];
|
||||
let selectedListKey: string = '';
|
||||
if (selectedList) {
|
||||
selectedListKey = typeof selectedList === 'string' ? selectedList : selectedList.id;
|
||||
}
|
||||
let selectedKey: string | undefined;
|
||||
const response = await listService.getLibs();
|
||||
// Start mapping the list that are selected
|
||||
response.value.forEach((list: ISPList) => {
|
||||
if (selectedListKey === list.Id) {
|
||||
selectedKey = list.Id;
|
||||
}
|
||||
|
||||
// Make sure that the current list is NOT in the 'listsToExclude' array
|
||||
if (listsToExclude.indexOf(list.Title) === -1 && listsToExclude.indexOf(list.Id) === -1) {
|
||||
options.push({
|
||||
key: list.Id,
|
||||
text: list.Title
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Option to unselect the list
|
||||
options.unshift({
|
||||
key: EMPTY_LIST_KEY,
|
||||
text: ''
|
||||
});
|
||||
|
||||
// Update the current component state
|
||||
this.setState({
|
||||
loadedLists: response,
|
||||
results: options,
|
||||
selectedKey: selectedKey
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises when a list has been selected
|
||||
*/
|
||||
private onChanged(option: IDropdownOption, index?: number): void {
|
||||
const newValue: string = option.key as string;
|
||||
this.delayedValidate(newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the new custom field value
|
||||
*/
|
||||
private validate(value: string): void {
|
||||
if (this.props.onGetErrorMessage === null || this.props.onGetErrorMessage === undefined) {
|
||||
this.notifyAfterValidate(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.latestValidateValue === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.latestValidateValue = value;
|
||||
|
||||
const errResult: string | Promise<string> = this.props.onGetErrorMessage(value || '');
|
||||
if (typeof errResult !== 'undefined') {
|
||||
if (typeof errResult === 'string') {
|
||||
if (errResult === '') {
|
||||
this.notifyAfterValidate(value);
|
||||
}
|
||||
this.setState({
|
||||
errorMessage: errResult
|
||||
});
|
||||
} else {
|
||||
errResult.then((errorMessage: string) => {
|
||||
if (!errorMessage) {
|
||||
this.notifyAfterValidate(value);
|
||||
}
|
||||
this.setState({
|
||||
errorMessage: errorMessage
|
||||
});
|
||||
}).catch(() => { /* no-op; */ });
|
||||
}
|
||||
} else {
|
||||
this.notifyAfterValidate(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the parent Web Part of a property value change
|
||||
*/
|
||||
private notifyAfterValidate(newValue: string): void {
|
||||
const {
|
||||
onPropertyChange,
|
||||
targetProperty,
|
||||
selectedList,
|
||||
includeListTitleAndUrl,
|
||||
properties,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
loadedLists
|
||||
} = this.state;
|
||||
|
||||
// Check if the user wanted to unselect the list
|
||||
let propValue: string | IPropertyFieldList | undefined;
|
||||
|
||||
if (includeListTitleAndUrl) {
|
||||
if (newValue === EMPTY_LIST_KEY) {
|
||||
propValue = undefined;
|
||||
}
|
||||
else {
|
||||
const spList = loadedLists.value.filter(l => l.Id === newValue)[0];
|
||||
propValue = {
|
||||
id: newValue,
|
||||
title: spList.Title,
|
||||
url: spList.RootFolder.ServerRelativeUrl
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
propValue = newValue === EMPTY_LIST_KEY ? '' : newValue;
|
||||
}
|
||||
|
||||
|
||||
// Deselect all options
|
||||
const options = this.state.results.map(option => {
|
||||
if (option.selected) {
|
||||
option.selected = false;
|
||||
}
|
||||
return option;
|
||||
});
|
||||
// Set the current selected key
|
||||
const selectedKey = newValue;
|
||||
// Update the state
|
||||
this.setState({
|
||||
selectedKey: selectedKey,
|
||||
results: options
|
||||
});
|
||||
|
||||
if (onPropertyChange && propValue !== null) {
|
||||
// Store the new property value
|
||||
setPropertyValue(properties, targetProperty, propValue);
|
||||
// Trigger the default onPrpertyChange event
|
||||
onPropertyChange(targetProperty, selectedList, propValue);
|
||||
// Trigger the apply button
|
||||
if (typeof onChange !== 'undefined' && onChange !== null) {
|
||||
onChange(targetProperty, propValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the component will unmount
|
||||
*/
|
||||
public componentWillUnmount(): void {
|
||||
if (typeof this.async !== 'undefined') {
|
||||
this.async.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the SPListpicker controls with Office UI Fabric
|
||||
*/
|
||||
public render(): JSX.Element {
|
||||
// Renders content
|
||||
return (
|
||||
<div>
|
||||
{this.props.label && <Label>{this.props.label}</Label>}
|
||||
<Dropdown
|
||||
disabled={this.props.disabled}
|
||||
label=''
|
||||
|
||||
onChange={(ev,options) => {
|
||||
this.onChanged(options as IDropdownOption);
|
||||
}
|
||||
}
|
||||
options={this.state.results}
|
||||
selectedKey={this.state.selectedKey}
|
||||
/>
|
||||
|
||||
<FieldErrorMessage errorMessage={""+this.state.errorMessage} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
import { SPHttpClient } from '@microsoft/sp-http';
|
||||
import { BaseComponentContext } from '@microsoft/sp-component-base';
|
||||
import { IPropertyFieldListPickerHostProps, ISPList, ISPLists } from './IPropertyFieldListPickerHost';
|
||||
import { PropertyFieldListPickerOrderBy } from './IPropertyFieldListPicker';
|
||||
|
||||
|
||||
/**
|
||||
* Service implementation to get list & list items from current SharePoint site
|
||||
*/
|
||||
export default class SPListPickerService {
|
||||
private context: BaseComponentContext;
|
||||
private props: IPropertyFieldListPickerHostProps;
|
||||
|
||||
/**
|
||||
* Service constructor
|
||||
*/
|
||||
constructor(
|
||||
_props: IPropertyFieldListPickerHostProps,
|
||||
pageContext: BaseComponentContext
|
||||
) {
|
||||
this.props = _props;
|
||||
this.context = pageContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection of libs in the current SharePoint site, or target site if specified by webRelativeUrl
|
||||
*/
|
||||
public async getLibs(): Promise<ISPLists> {
|
||||
// use the web relative url if provided, otherwise default to current SharePoint site
|
||||
const webAbsoluteUrl = this.props.webAbsoluteUrl
|
||||
? this.props.webAbsoluteUrl
|
||||
: this.context.pageContext.web.absoluteUrl;
|
||||
// If the running environment is SharePoint, request the lists REST service
|
||||
let queryUrl: string;
|
||||
if (this.props.contentTypeId) {
|
||||
queryUrl = `${webAbsoluteUrl}/_api/lists?$select=Title,id,BaseTemplate,RootFolder/ServerRelativeUrl,ContentTypes/StringId,ContentTypes/Name&$expand=RootFolder&$expand=ContentTypes`;
|
||||
} else {
|
||||
queryUrl = `${webAbsoluteUrl}/_api/lists?$select=Title,id,BaseTemplate,RootFolder/ServerRelativeUrl&$expand=RootFolder`;
|
||||
}
|
||||
// Check if the orderBy property is provided
|
||||
if (this.props.orderBy !== null) {
|
||||
queryUrl += '&$orderby=';
|
||||
switch (this.props.orderBy) {
|
||||
case PropertyFieldListPickerOrderBy.Id:
|
||||
queryUrl += 'Id';
|
||||
break;
|
||||
case PropertyFieldListPickerOrderBy.Title:
|
||||
queryUrl += 'Title';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds an OData Filter to the list
|
||||
if (this.props.filter) {
|
||||
queryUrl += `&$filter=${encodeURIComponent(this.props.filter)}`;
|
||||
}
|
||||
// Check if the list have get filtered based on the list base template type
|
||||
else if ((this.props.baseTemplate !== null && this.props.baseTemplate) || Array.isArray(this.props.baseTemplate)) {
|
||||
if (Array.isArray(this.props.baseTemplate)) {
|
||||
queryUrl += '&$filter=(';
|
||||
queryUrl += this.props.baseTemplate.map(temp => `(BaseTemplate%20eq%20${temp})`).join('%20or%20');
|
||||
queryUrl += ')';
|
||||
} else {
|
||||
queryUrl += '&$filter=BaseTemplate%20eq%20';
|
||||
queryUrl += this.props.baseTemplate;
|
||||
}
|
||||
|
||||
// Check if you also want to exclude hidden list in the list
|
||||
if (this.props.includeHidden === false) {
|
||||
queryUrl += '%20and%20Hidden%20eq%20false';
|
||||
}
|
||||
} else {
|
||||
if (this.props.includeHidden === false) {
|
||||
queryUrl += '&$filter=Hidden%20eq%20false';
|
||||
}
|
||||
}
|
||||
const response = await this.context.spHttpClient.get(
|
||||
queryUrl,
|
||||
SPHttpClient.configurations.v1
|
||||
);
|
||||
|
||||
let lists = (await response.json()) as ISPLists;
|
||||
//remove unwanted contenttypes
|
||||
|
||||
|
||||
if (this.props.contentTypeId) {
|
||||
const testct = this.props.contentTypeId.toUpperCase();
|
||||
lists.value = lists.value.filter((l) => {
|
||||
for (const ct of l.ContentTypes) {
|
||||
const ctid: string = ct.StringId.toUpperCase();
|
||||
if (ctid.substring(0, testct.length) === testct) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Check if onListsRetrieved callback is defined
|
||||
if (this.props.onListsRetrieved) {
|
||||
//Call onListsRetrieved
|
||||
const lr = this.props.onListsRetrieved(lists.value);
|
||||
let output: ISPList[];
|
||||
|
||||
//Conditional checking to see of PromiseLike object or array
|
||||
if (lr instanceof Array) {
|
||||
output = lr;
|
||||
} else {
|
||||
output = await lr;
|
||||
}
|
||||
|
||||
lists = {
|
||||
value: output,
|
||||
};
|
||||
}
|
||||
return lists;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export * from './PropertyFieldListPicker';
|
||||
export * from './IPropertyFieldListPicker';
|
||||
export * from './PropertyFieldListPickerHost';
|
||||
export * from './IPropertyFieldListPickerHost';
|
|
@ -0,0 +1,77 @@
|
|||
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
|
||||
|
||||
/**
|
||||
* Public properties of the PropertyFieldOrder custom field
|
||||
*/
|
||||
export interface IPropertyFieldOrderProps {
|
||||
|
||||
/**
|
||||
* Property field label displayed on top
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Defines an onPropertyChange function to raise when the items order changes.
|
||||
* Normally this function must be defined with the 'this.onPropertyChange'
|
||||
* method of the web part object.
|
||||
*/
|
||||
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
/**
|
||||
* An array of values to reorder
|
||||
*/
|
||||
items: Array<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
/**
|
||||
* The property to use for display, when undefined, the toString() method of the object is used (ignored when the onRenderItem function is specified)
|
||||
*/
|
||||
textProperty?: string;
|
||||
|
||||
/**
|
||||
* When true, drag and drop reordering is disabled (defaults to false)
|
||||
*/
|
||||
disableDragAndDrop?: boolean;
|
||||
|
||||
/**
|
||||
* When true, arrow buttons are not displayed (defaults to false)
|
||||
*/
|
||||
removeArrows?: boolean;
|
||||
|
||||
/**
|
||||
* The maximun height for the items in px (when not set, the control expands as necessary)
|
||||
*/
|
||||
maxHeight?: number;
|
||||
|
||||
/**
|
||||
* Whether the property pane field is enabled or not.
|
||||
*/
|
||||
disabled?: boolean;
|
||||
|
||||
/**
|
||||
* Optional callback to provide custom rendering of the item (default is simple text based on either item or the property identified in the textProperty)
|
||||
*/
|
||||
onRenderItem?: (item: any, index: number) => JSX.Element; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
/**
|
||||
* An UNIQUE key indicates the identity of this control
|
||||
*/
|
||||
key: string;
|
||||
|
||||
/**
|
||||
* Parent Web Part properties
|
||||
*/
|
||||
properties: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
/**
|
||||
* The name of the UI Fabric Font Icon to use for the move up button (defaults to ChevronUpSmall)
|
||||
*/
|
||||
moveUpIconName?: string;
|
||||
|
||||
/**
|
||||
* The name of the UI Fabric Font Icon to use for the move down button (defaults to ChevronDownSmall)
|
||||
*/
|
||||
moveDownIconName?: string;
|
||||
}
|
||||
|
||||
export interface IPropertyFieldOrderPropsInternal extends IPropertyFieldOrderProps, IPropertyPaneCustomFieldProps {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* PropertyFieldOrderHost properties interface
|
||||
*/
|
||||
export interface IPropertyFieldOrderHostProps {
|
||||
label: string;
|
||||
disabled: boolean;
|
||||
items: Array<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
textProperty?: string;
|
||||
moveUpIconName: string;
|
||||
moveDownIconName: string;
|
||||
disableDragAndDrop: boolean;
|
||||
removeArrows: boolean;
|
||||
maxHeight?: number;
|
||||
valueChanged: (newValue: Array<any>) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
onRenderItem?: (item: any, index: number) => JSX.Element; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
/**
|
||||
* PropertyFieldOrderHost state interface
|
||||
*/
|
||||
export interface IPropertyFieldOrderHostState {
|
||||
items: Array<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
import { IPropertyPaneField, PropertyPaneFieldType } from '@microsoft/sp-property-pane';
|
||||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
|
||||
|
||||
|
||||
import { IPropertyFieldOrderHostProps } from './IPropertyFieldOrderHost';
|
||||
import PropertyFieldOrderHost from './PropertyFieldOrderHost';
|
||||
import { IPropertyFieldOrderProps, IPropertyFieldOrderPropsInternal } from './IPropertyFieldOrder';
|
||||
import { setPropertyValue } from './helper';
|
||||
|
||||
|
||||
class PropertyFieldOrderBuilder implements IPropertyPaneField<IPropertyFieldOrderProps> {
|
||||
|
||||
//Properties defined by IPropertyPaneField
|
||||
public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
|
||||
public targetProperty: string;
|
||||
public properties: IPropertyFieldOrderPropsInternal;
|
||||
private elem: HTMLElement;
|
||||
private items: Array<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
private changeCB?: (targetProperty?: string, newValue?: any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
public constructor(_targetProperty: string, _properties: IPropertyFieldOrderProps) {
|
||||
this.targetProperty = _targetProperty;
|
||||
this.properties = {
|
||||
key: _properties.key,
|
||||
label: _properties.label,
|
||||
onPropertyChange: _properties.onPropertyChange,
|
||||
disabled: _properties.disabled,
|
||||
properties: _properties.properties,
|
||||
items: _properties.items,
|
||||
textProperty: _properties.textProperty,
|
||||
moveUpIconName: _properties.moveUpIconName,
|
||||
moveDownIconName: _properties.moveDownIconName,
|
||||
disableDragAndDrop: _properties.disableDragAndDrop,
|
||||
removeArrows: _properties.removeArrows,
|
||||
maxHeight: _properties.maxHeight,
|
||||
onRenderItem: _properties.onRenderItem,
|
||||
onRender: this.onRender.bind(this)
|
||||
};
|
||||
this.items = _properties.items;
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
if (!this.elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onRender(this.elem);
|
||||
}
|
||||
|
||||
public onDispose(element: HTMLElement): void {
|
||||
ReactDom.unmountComponentAtNode(element);
|
||||
}
|
||||
|
||||
private onRender(elem: HTMLElement, ctx?: any, changeCallback?: (targetProperty?: string, newValue?: any) => void): void { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (!this.elem) {
|
||||
this.elem = elem;
|
||||
}
|
||||
this.changeCB = changeCallback;
|
||||
|
||||
const element: React.ReactElement<IPropertyFieldOrderHostProps> = React.createElement(PropertyFieldOrderHost, {
|
||||
label: this.properties.label,
|
||||
disabled: this.properties.disabled ? this.properties.disabled : false,
|
||||
items: this.items,
|
||||
textProperty: this.properties.textProperty,
|
||||
moveUpIconName: this.properties.moveUpIconName || 'ChevronUpSmall',
|
||||
moveDownIconName: this.properties.moveDownIconName || 'ChevronDownSmall',
|
||||
disableDragAndDrop: this.properties.disableDragAndDrop ? this.properties.disableDragAndDrop : false,
|
||||
removeArrows: this.properties.removeArrows ? this.properties.removeArrows : false,
|
||||
maxHeight: this.properties.maxHeight,
|
||||
onRenderItem: this.properties.onRenderItem,
|
||||
valueChanged: this.onValueChanged.bind(this)
|
||||
});
|
||||
ReactDom.render(element, elem);
|
||||
}
|
||||
|
||||
private onValueChanged(newValue: Array<any>): void { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (this.properties.onPropertyChange && newValue !== null) {
|
||||
this.properties.onPropertyChange(this.targetProperty, this.items, newValue);
|
||||
this.items = newValue;
|
||||
setPropertyValue(this.properties.properties, this.targetProperty, newValue);
|
||||
if (typeof this.changeCB !== 'undefined' && this.changeCB !== null) {
|
||||
this.changeCB(this.targetProperty, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function PropertyFieldOrder(targetProperty: string, properties: IPropertyFieldOrderProps): IPropertyPaneField<IPropertyFieldOrderProps> {
|
||||
return new PropertyFieldOrderBuilder(targetProperty, properties);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
$ms-color-themePrimary: '[theme:themePrimary, default:#0078d7]';
|
||||
$ms-color-neutralLight: '[theme:neutralLight, default:#eaeaea]';
|
||||
$ms-color-neutralLighter: '[theme:neutralLighter, default:#f4f4f4]';
|
||||
$ms-color-neutralTertiary: '[theme:neutralTertiary, default:#a6a6a6]';
|
||||
$ms-color-white: '[theme:white, default:#ffffff]';
|
||||
|
||||
|
||||
.propertyFieldOrder {
|
||||
margin-bottom: 2px;
|
||||
|
||||
ul {
|
||||
padding: 0.5px;
|
||||
margin: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
|
||||
li {
|
||||
color: $ms-color-neutralTertiary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
background-color: $ms-color-white;
|
||||
border: 0.5px solid;
|
||||
border-color: $ms-color-neutralLight;
|
||||
outline: 0.5px solid;
|
||||
outline-color: $ms-color-neutralLight;
|
||||
|
||||
.enabled & :hover {
|
||||
background-color: $ms-color-neutralLighter;
|
||||
}
|
||||
|
||||
& > div {
|
||||
padding: 3px 6px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.itemBox {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.dragEnter {
|
||||
background-color: $ms-color-neutralLight;
|
||||
border-top: 2px dashed;
|
||||
border-top-color: $ms-color-themePrimary;
|
||||
}
|
||||
|
||||
.dragLast {
|
||||
background-color: $ms-color-neutralLight;
|
||||
border-bottom: 2px dashed;
|
||||
border-bottom-color: $ms-color-themePrimary;
|
||||
}
|
||||
|
||||
.lastBox {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
import { IButtonStyles, IconButton } from '@fluentui/react/lib/Button';
|
||||
//import { Selection } from '@fluentui/react/lib/DetailsList';
|
||||
import { Label } from '@fluentui/react/lib/Label';
|
||||
//import { DragDropHelper } from '@fluentui/react/lib/utilities/dragdrop';
|
||||
//import { IDragDropContext } from '@fluentui/react/lib/utilities/dragdrop/interfaces';
|
||||
import * as React from 'react';
|
||||
|
||||
|
||||
import { IPropertyFieldOrderHostProps, IPropertyFieldOrderHostState } from './IPropertyFieldOrderHost';
|
||||
import styles from './PropertyFieldOrderHost.module.scss';
|
||||
import { isEqual } from '@microsoft/sp-lodash-subset';
|
||||
//import { EventGroup } from '@fluentui/react/lib/Utilities'; //'@uifabric/utilities/lib/EventGroup';
|
||||
|
||||
export default class PropertyFieldOrderHost extends React.Component<IPropertyFieldOrderHostProps, IPropertyFieldOrderHostState> {
|
||||
|
||||
private _draggedItem: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
//private _selection: Selection;
|
||||
//private _ddHelper: DragDropHelper;
|
||||
private _refs: Array<HTMLElement>;
|
||||
private _ddSubs: Array<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
private _lastBox: HTMLDivElement;
|
||||
|
||||
constructor(props: IPropertyFieldOrderHostProps, state: IPropertyFieldOrderHostState) {
|
||||
super(props);
|
||||
// this._selection = new Selection();
|
||||
/*this._ddHelper = new DragDropHelper({
|
||||
selection: this._selection
|
||||
});
|
||||
*/
|
||||
this._refs = new Array<HTMLElement>();
|
||||
this._ddSubs = new Array<any>(); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
this._draggedItem = null;
|
||||
|
||||
this.state = {
|
||||
items: []
|
||||
};
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const {
|
||||
items
|
||||
} = this.state;
|
||||
return (
|
||||
<div className={styles.propertyFieldOrder}>
|
||||
{this.props.label && <Label>{this.props.label}</Label>}
|
||||
<ul style={{ maxHeight: this.props.maxHeight ? this.props.maxHeight + 'px' : '100%' }} className={!this.props.disabled ? styles.enabled : styles.disabled}>
|
||||
{
|
||||
(items && items.length > 0) && (
|
||||
items.map((value: any, index: number) => { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return (
|
||||
<li
|
||||
ref={this.registerRef}
|
||||
key={index}
|
||||
draggable={!this.props.disableDragAndDrop && !this.props.disabled}
|
||||
style={{ cursor: !this.props.disableDragAndDrop && !this.props.disabled ? 'pointer' : 'default' }}
|
||||
>{this.renderItem(value, index)}</li>
|
||||
);
|
||||
})
|
||||
)
|
||||
}
|
||||
{
|
||||
(items && items.length > 0) && <div className={styles.lastBox} ref={(ref:HTMLDivElement):void => { this._lastBox = ref; }} />
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderItem(item: any, index: number): JSX.Element { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.itemBox}>
|
||||
{this.renderDisplayValue(item, index)}
|
||||
</div>
|
||||
{!this.props.removeArrows &&
|
||||
<div>{this.renderArrows(index)}</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderDisplayValue(item: any, index: number): JSX.Element { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (typeof this.props.onRenderItem === "function") {
|
||||
return this.props.onRenderItem(item, index);
|
||||
} else {
|
||||
return (
|
||||
<span>{this.props.textProperty ? item[this.props.textProperty] : item.toString()}</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private renderArrows(index: number): JSX.Element {
|
||||
const arrowButtonStyles: Partial<IButtonStyles> = {
|
||||
root: {
|
||||
width: '14px',
|
||||
height: '100%',
|
||||
display: 'inline-block'
|
||||
},
|
||||
rootDisabled: {
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
icon: {
|
||||
fontSize: "10px"
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
disabled={this.props.disabled || index === 0}
|
||||
iconProps={{ iconName: this.props.moveUpIconName }}
|
||||
onClick={() => { this.onMoveUpClick(index); }}
|
||||
styles={arrowButtonStyles}
|
||||
/>
|
||||
<IconButton
|
||||
disabled={this.props.disabled || index === this.props.items.length - 1}
|
||||
iconProps={{ iconName: this.props.moveDownIconName }}
|
||||
onClick={() => { this.onMoveDownClick(index); }}
|
||||
styles={arrowButtonStyles}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public UNSAFE_componentWillMount(): void {
|
||||
this.setState({
|
||||
items: this.props.items || []
|
||||
});
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.setupSubscriptions();
|
||||
}
|
||||
|
||||
public UNSAFE_componentWillUpdate(nextProps: IPropertyFieldOrderHostProps): void {
|
||||
// Check if the provided items are still the same
|
||||
if (!isEqual(nextProps.items, this.state.items)) {
|
||||
this.setState({
|
||||
items: this.props.items || []
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate(): void {
|
||||
this.cleanupSubscriptions();
|
||||
this.setupSubscriptions();
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.cleanupSubscriptions();
|
||||
}
|
||||
|
||||
private registerRef = (ref: HTMLLIElement): void => {
|
||||
this._refs.push(ref);
|
||||
}
|
||||
|
||||
private setupSubscriptions = (): void => {
|
||||
if (!this.props.disableDragAndDrop && !this.props.disabled) {
|
||||
this._refs.forEach((value: HTMLElement, index: number) => {
|
||||
/* this._ddSubs.push(this._ddHelper.subscribe(value, new EventGroup(value), {
|
||||
eventMap: [
|
||||
{
|
||||
callback: (context: IDragDropContext) => {
|
||||
this._draggedItem = context.data;
|
||||
},
|
||||
eventName: 'dragstart'
|
||||
}
|
||||
],
|
||||
selectionIndex: index,
|
||||
context: { data: this.state.items[index], index: index },
|
||||
updateDropState: (isDropping: boolean, event: DragEvent) => {
|
||||
if (isDropping) {
|
||||
value.classList.add(styles.dragEnter);
|
||||
} else {
|
||||
value.classList.remove(styles.dragEnter);
|
||||
}
|
||||
},
|
||||
canDrop: (dropContext?: IDragDropContext, dragContext?: IDragDropContext) => {
|
||||
return true;
|
||||
},
|
||||
canDrag: (item?: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return true;
|
||||
},
|
||||
onDrop: (item?: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (this._draggedItem) {
|
||||
this.insertBeforeItem(item);
|
||||
}
|
||||
},
|
||||
onDragEnd: () => {
|
||||
this._draggedItem = null;
|
||||
}
|
||||
}));*/
|
||||
});
|
||||
|
||||
//Create dropable area below list to allow items to be dragged to the bottom
|
||||
if (this._refs.length && typeof this._lastBox !== "undefined") {
|
||||
/*this._ddSubs.push(this._ddHelper.subscribe(this._lastBox, new EventGroup(this._lastBox), {
|
||||
selectionIndex: this._refs.length,
|
||||
context: { data: {}, index: this._refs.length },
|
||||
updateDropState: (isDropping: boolean, event: DragEvent) => {
|
||||
if (isDropping) {
|
||||
this._refs[this._refs.length - 1].classList.add(styles.dragLast);
|
||||
} else {
|
||||
this._refs[this._refs.length - 1].classList.remove(styles.dragLast);
|
||||
}
|
||||
},
|
||||
canDrop: (dropContext?: IDragDropContext, dragContext?: IDragDropContext) => {
|
||||
return true;
|
||||
},
|
||||
onDrop: (item?: any, event?: DragEvent) => { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (this._draggedItem) {
|
||||
const itemIndex: number = this.state.items.indexOf(this._draggedItem);
|
||||
this.moveItemAtIndexToTargetIndex(itemIndex, this.state.items.length - 1);
|
||||
}
|
||||
}
|
||||
}));*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private cleanupSubscriptions = (): void => {
|
||||
while (this._ddSubs.length) {
|
||||
const sub: any = this._ddSubs.pop(); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
sub.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public insertBeforeItem = (item: any): void => { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const itemIndex: number = this.state.items.indexOf(this._draggedItem);
|
||||
let targetIndex: number = this.state.items.indexOf(item);
|
||||
if (itemIndex < targetIndex) {
|
||||
targetIndex -= 1;
|
||||
}
|
||||
this.moveItemAtIndexToTargetIndex(itemIndex, targetIndex);
|
||||
}
|
||||
|
||||
|
||||
private onMoveUpClick = (itemIndex: number): void => {
|
||||
if (itemIndex > 0) {
|
||||
this.moveItemAtIndexToTargetIndex(itemIndex, itemIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private onMoveDownClick = (itemIndex: number): void => {
|
||||
if (itemIndex < this.state.items.length - 1) {
|
||||
this.moveItemAtIndexToTargetIndex(itemIndex, itemIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private moveItemAtIndexToTargetIndex = (itemIndex: number, targetIndex: number): void => {
|
||||
if (itemIndex !== targetIndex && itemIndex > -1 && targetIndex > -1 && itemIndex < this.state.items.length && targetIndex < this.state.items.length) {
|
||||
const items: Array<any> = this.state.items; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
items.splice(targetIndex, 0, ...items.splice(itemIndex, 1));
|
||||
|
||||
this.setState({
|
||||
items: items
|
||||
});
|
||||
|
||||
this.props.valueChanged(items);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
export const setPropertyValue = (properties: any, targetProperty: string, value: any): void => { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (!properties) {
|
||||
return;
|
||||
}
|
||||
if (targetProperty.indexOf('.') === -1) { // simple prop
|
||||
properties[targetProperty] = value;
|
||||
}
|
||||
else {
|
||||
throw new Error('Nested properties are not supported');
|
||||
// .set(properties, targetProperty, value);
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue