Added fix for May 2020 Adaptive Card breaking changes and CodeTour

This commit is contained in:
Hugo Bernier 2020-06-11 01:46:40 -04:00
parent ffd43e6400
commit 7ac1743715
17 changed files with 502 additions and 717 deletions

View File

@ -0,0 +1,396 @@
{
"title": "Code Walk-through",
"steps": [
{
"title": "Introduction",
"description": "This web part was designed to demonstrate how to use a new custom Adaptive Card host component, along with a few concepts:\r\n* Loading property pane resources only when the property pane is displayed\r\n* Supporting themes and section background colors\r\n\r\nYou can use the `AdaptiveCard` component in your own web part, our web part isn't intended to be used in production.",
"file": "README.md",
"line": 1
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 29,
"description": "Adding these imports are crucial for adding theme and section background support."
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 96,
"description": "The `_themeProvider` and `_themeVariant` will be used at render time to pass theme information to our components.",
"selection": {
"start": {
"line": 96,
"character": 3
},
"end": {
"line": 97,
"character": 53
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 113,
"description": "This is how we let the web part know that we want to be notified when there are theme changes.",
"selection": {
"start": {
"line": 107,
"character": 5
},
"end": {
"line": 113,
"character": 84
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 364,
"description": "This event handler will get called when the theme changes. It stores the `_themeVariant` and calls `render` to update the web part body.",
"selection": {
"start": {
"line": 364,
"character": 1
},
"end": {
"line": 367,
"character": 4
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 137,
"description": "We pass the theme variant to the component that will render the web part body so that it can query the theme colors at render time.",
"selection": {
"start": {
"line": 137,
"character": 9
},
"end": {
"line": 137,
"character": 42
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 162,
"description": "`loadPropertyPaneResources` is a standard web part event that gets called before the property pane is rendered.\\\r\n\r\nYou can use this to load resource-intensive components that only need to be shown in the property pane. That way, when the web part is showing in \"view\" mode (for most users), we don't need to load the extra resources. When the web part is in \"edit\" mode, and when we load the property pane, we load all the heavy stuff.",
"selection": {
"start": {
"line": 162,
"character": 19
},
"end": {
"line": 162,
"character": 44
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 169,
"description": "For example, this `_templatePropertyPaneHelper` defines a @pnp code editor control. That way, we don't need to load all the code editing and syntax highlighting resources unless we're actually editing the web part properties.",
"selection": {
"start": {
"line": 169,
"character": 5
},
"end": {
"line": 169,
"character": 37
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 193,
"description": "Because we pre-defined property pane controls in the `loadPropertyPaneResources` event handler, we can use the controls in this method..."
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 238,
"description": "...when it is time to render the property pane, we simply use the pre-created `_templatePropertyPaneHelper`.",
"selection": {
"start": {
"line": 238,
"character": 17
},
"end": {
"line": 238,
"character": 72
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 117,
"description": "We also set up the pnpjs `spfxContent` with the web part's context so that we can make it easy to get the data later.",
"selection": {
"start": {
"line": 117,
"character": 5
},
"end": {
"line": 120,
"character": 1
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 372,
"description": "If we need to, we load the data from a SharePoint list so that we can pass the data to the `AdaptiveCard` component.",
"selection": {
"start": {
"line": 372,
"character": 17
},
"end": {
"line": 372,
"character": 34
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 386,
"description": "We load the view that was selected so we can get the schema and the query.",
"selection": {
"start": {
"line": 383,
"character": 5
},
"end": {
"line": 386,
"character": 6
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 391,
"description": "Calling `renderListDataAsStream` returns not only the data, but everything we need to render the complete data -- including looking field views, user info, etc.\r\n\r\nThis is similar to how SharePoint renders lists out-of-the-box. (Don't believe me? Use the network tab in your browser's Developer Tools on a SharePoint page that shows a list. You'll find calls to `renderListDataAsStream`)",
"selection": {
"start": {
"line": 389,
"character": 4
},
"end": {
"line": 391,
"character": 8
}
}
},
{
"file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts",
"line": 140,
"description": "When it is time to render the web part's body, our `AdaptiveCard` component only needs the template JSON, the data (if used), and a flag to tell us whether we're using Adaptive Card Templating or not.",
"selection": {
"start": {
"line": 138,
"character": 9
},
"end": {
"line": 140,
"character": 63
}
}
},
{
"file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx",
"line": 17,
"description": "This renders the web part's body",
"selection": {
"start": {
"line": 17,
"character": 22
},
"end": {
"line": 17,
"character": 38
}
}
},
{
"file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx",
"line": 37,
"description": "We detect if the web part is configured by looking at the `template` prop, the `data` prop, and whether the template contains the string `$data` -- which is an indicator that the template uses Adaptive Card templating.",
"selection": {
"start": {
"line": 30,
"character": 5
},
"end": {
"line": 38,
"character": 1
}
}
},
{
"file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx",
"line": 47,
"description": "If we need a template, we show a placeholder",
"selection": {
"start": {
"line": 40,
"character": 5
},
"end": {
"line": 47,
"character": 9
}
}
},
{
"file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx",
"line": 56,
"description": "If we need data, we show another friendly placeholder.",
"selection": {
"start": {
"line": 48,
"character": 7
},
"end": {
"line": 56,
"character": 9
}
}
},
{
"file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx",
"line": 70,
"description": "If we detect that the template uses Adaptive Card templating, we display a friendly message.",
"selection": {
"start": {
"line": 73,
"character": 11
},
"end": {
"line": 80,
"character": 13
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 29,
"description": "This is where all the Adaptive Card processing gets done. You can use this component in your own web parts -- just pass the props you need.",
"selection": {
"start": {
"line": 29,
"character": 14
},
"end": {
"line": 29,
"character": 26
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 61,
"description": "This `div` will contain the rendered HTML.",
"selection": {
"start": {
"line": 61,
"character": 6
},
"end": {
"line": 61,
"character": 95
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 59,
"description": "I don't really like showing the errors in the `AdaptiveCard` component itself (I would have preferred to let the web part handle it), but that's all I could get working for now.",
"selection": {
"start": {
"line": 54,
"character": 9
},
"end": {
"line": 59,
"character": 22
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 49,
"description": "Once the component is mounted and/or when the properties change, we render the Adaptive Card.",
"selection": {
"start": {
"line": 40,
"character": 2
},
"end": {
"line": 49,
"character": 4
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 4,
"description": "We use the Adaptive Card team's npm package to render the cards."
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 5,
"description": "We use the npm package to support Adaptive Card templating."
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 6,
"description": "And we use this npm package to make the Adaptive Cards look like they belong to SharePoint by giving them a Office Fabric look."
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 14,
"description": "We also use `markdown-it` to parse the Markdown from the rendered HTML so that we fully support the Adaptive Card schema."
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 84,
"description": "We have to do a little workaround here, but that's a temporary issue.\r\n\r\nThe May 2020 Adaptive Card templating library change the syntax from `{}` to `${}`, but the npm package doesn't seem to be updated yet. So we just replace all `${}` to `{}` so that you can use all the latest Adaptive Card templating samples without issues. \r\n\r\nWe'll fix this when the npm package is updated.",
"selection": {
"start": {
"line": 79,
"character": 8
},
"end": {
"line": 84,
"character": 61
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 132,
"description": "This is how we render the specify to use Office Fabric, adjust the theme colors, and handle Markdown before rendering the card.",
"selection": {
"start": {
"line": 123,
"character": 4
},
"end": {
"line": 133,
"character": 1
}
}
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 136,
"description": "This is a generic handler to raise Adaptive Card actions back to the component's parent."
},
{
"file": "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"line": 197,
"description": "This is pretty much a brute force method where we change the Adaptive Card's host configuration with the theme's colors. \r\n\r\nWe used trial and error to find what theme slots match which host configuration styles. \r\n\r\nWould love to get your feedback!"
}
]
}

View File

@ -36,6 +36,7 @@ Version|Date|Comments
-------|----|-------- -------|----|--------
1.0|March 24, 2020|Initial release 1.0|March 24, 2020|Initial release
2.0|April 06, 2020|Added data and template URLs 2.0|April 06, 2020|Added data and template URLs
2.1|June 11, 2020|Fixed breaking changes introduced with Adaptive Card Templating in May update
## Disclaimer ## Disclaimer
@ -423,16 +424,6 @@ The web part sample conditionally hides and shows property pane controls dependi
![Dependent Property Pane Controls](./assets/DependentControls.gif) ![Dependent Property Pane Controls](./assets/DependentControls.gif)
### View Picker
To create this sample, we had to create our own **View picker** control, which allows you to select a view from the list or document library you selected.
The sample includes the source code for the `PropertyFieldViewPicker`, which renders the control, and `SPViewPickerService` which retrieves the views.
The code for both components is largely derived from the [@pnp/spfx-property-controls](https://sharepoint.github.io/) library's [PropertyFieldListPicker control](https://sharepoint.github.io/sp-dev-fx-property-controls/controls/PropertyFieldListPicker/).
We have submitted a [pull request](https://github.com/SharePoint/sp-dev-fx-property-controls/pull/230) to add the `PropertyFieldViewPicker` control to the @pnp/spfx-property-controls. If the pull request is accepted, we'll update this sample to remove the extraneous code and refer to the version of the @pnp/spfx-property-controls `PropertyFieldViewPicker`.
## For More Information ## For More Information
If you'd like to read more about the various concepts illustrated in this sample, please refer to the following links: If you'd like to read more about the various concepts illustrated in this sample, please refer to the following links:

View File

@ -3,7 +3,7 @@
"solution": { "solution": {
"name": "adaptive-cards", "name": "adaptive-cards",
"id": "ce1e3712-fb7a-4564-b2d3-c81e45936afd", "id": "ce1e3712-fb7a-4564-b2d3-c81e45936afd",
"version": "1.0.0.0", "version": "2.1.0.0",
"includeClientSideAssets": true, "includeClientSideAssets": true,
"isDomainIsolated": false "isDomainIsolated": false
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "adaptive-card-host", "name": "adaptive-card-host",
"version": "0.0.1", "version": "2.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -2741,9 +2741,9 @@
} }
}, },
"@pnp/sp-clientsvc": { "@pnp/sp-clientsvc": {
"version": "1.3.10", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@pnp/sp-clientsvc/-/sp-clientsvc-1.3.10.tgz", "resolved": "https://registry.npmjs.org/@pnp/sp-clientsvc/-/sp-clientsvc-1.3.11.tgz",
"integrity": "sha512-4WiWkCPJsvxDbd0ijyZAUDhsANbQrUvJl3rp5KSanasTDWLmGqUt0DqPb36JTs/RP6Qijjg9zImAcCyI8iB/UQ==", "integrity": "sha512-eIUnmDWjizcWJzhWxAbfsxEyHF1dabkGlihnDnlcYGhtvh8BwuM67A57qc5fbxzCS59c0YU57szB1EucoNmV4A==",
"requires": { "requires": {
"tslib": "1.10.0" "tslib": "1.10.0"
}, },
@ -2756,9 +2756,9 @@
} }
}, },
"@pnp/sp-taxonomy": { "@pnp/sp-taxonomy": {
"version": "1.3.10", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@pnp/sp-taxonomy/-/sp-taxonomy-1.3.10.tgz", "resolved": "https://registry.npmjs.org/@pnp/sp-taxonomy/-/sp-taxonomy-1.3.11.tgz",
"integrity": "sha512-aauwNCaa5oNq22Bgl8Wnmb47UabY69fXcE93PT7gEzQzv6VKFCFmJfE44MEj/7XoPS5HCHumctTsv+PEu6vNIA==", "integrity": "sha512-shzCSjmOlr6mojCXJkfD8Xf9lJnhphq4Fj6mdUQGwpak+VIU+Fogf6AI0j6AReCKtKsKyqfud9X7C8tH07C3DA==",
"requires": { "requires": {
"tslib": "1.10.0" "tslib": "1.10.0"
}, },
@ -2885,9 +2885,9 @@
} }
}, },
"@pnp/spfx-property-controls": { "@pnp/spfx-property-controls": {
"version": "1.16.0", "version": "1.18.0",
"resolved": "https://registry.npmjs.org/@pnp/spfx-property-controls/-/spfx-property-controls-1.16.0.tgz", "resolved": "https://registry.npmjs.org/@pnp/spfx-property-controls/-/spfx-property-controls-1.18.0.tgz",
"integrity": "sha512-1WAY9baY1qXB50vVNUmNDJhv0L9SfSALQ5IFmR0ZqWI9AiKgXxDEMIL652dR3W4GV71TeS+MsI4a0vTKIDrJcA==", "integrity": "sha512-9aeTRy/MS2SkDWLFsnHNq4mU00xGHCUjCJ5btTQrQb0CcT85AY604cwbVvj4VB3MdfdXYnS3ZYOR3HvENeCtyw==",
"requires": { "requires": {
"@pnp/common": "^1.2.8", "@pnp/common": "^1.2.8",
"@pnp/logging": "^1.2.8", "@pnp/logging": "^1.2.8",
@ -2895,70 +2895,51 @@
"@pnp/sp": "^1.2.8", "@pnp/sp": "^1.2.8",
"@pnp/sp-clientsvc": "^1.2.8", "@pnp/sp-clientsvc": "^1.2.8",
"@pnp/sp-taxonomy": "^1.2.8", "@pnp/sp-taxonomy": "^1.2.8",
"@pnp/telemetry-js": "1.0.0", "@pnp/telemetry-js": "2.0.0",
"lodash.omit": "^4.5.0",
"office-ui-fabric-react": "5.131.0", "office-ui-fabric-react": "5.131.0",
"react-ace": "5.8.0" "react-ace": "5.8.0"
}, },
"dependencies": { "dependencies": {
"@pnp/common": { "@pnp/common": {
"version": "1.3.10", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@pnp/common/-/common-1.3.10.tgz", "resolved": "https://registry.npmjs.org/@pnp/common/-/common-1.3.11.tgz",
"integrity": "sha512-5Qlx876LSLu36RW1l74hIlPffQi/5Z+LMgGCQT3moA5qguXuDtSxh0Mmahfx/Ku3yd+xgm4ELHLCifu67NR1zg==", "integrity": "sha512-RhYKcfMP+h0pAzORZRHSPPLOBB58djN/pfnorpWPjsx6ZxMqbiDqTzAtTF4m8z/mdNnxJr0Q3kwt4ImU3FjwnA==",
"requires": { "requires": {
"adal-angular": "1.0.17", "adal-angular": "1.0.17",
"tslib": "1.10.0" "tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
} }
}, },
"@pnp/logging": { "@pnp/logging": {
"version": "1.3.10", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-1.3.10.tgz", "resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-1.3.11.tgz",
"integrity": "sha512-lMPT9NowkyFGQvEJYKy6HRiP/tTeqR6lTqb83ZPMxI3xU57AUlSqfcGFlwvgWTkXXV6XrWkSrXiAVx5f5Rbr2g==", "integrity": "sha512-hADlIXwvF/wjee7425nFJ6NhqaWpWTJ5yg02bpwBUsiSuFqEUf+LwuAcyHQre2lMs6KyNa65FWoRQok9BlZuxA==",
"requires": { "requires": {
"tslib": "1.10.0" "tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
} }
}, },
"@pnp/odata": { "@pnp/odata": {
"version": "1.3.10", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@pnp/odata/-/odata-1.3.10.tgz", "resolved": "https://registry.npmjs.org/@pnp/odata/-/odata-1.3.11.tgz",
"integrity": "sha512-uqXxE9SZXfQtseoYESct2ViyjTgi43HC+c9ByXZh6ym7Qctjen7b0tyhkgn3RXVO5WN7VqpJa+k4crnr0ca+og==", "integrity": "sha512-yMaRiuVZRei2pkryCOqsw3ZXD2Lw30IJv136WQmQPQPOxG4cvsS9+woXkfMqbWV2KQ1evFUqVXbitIz6eDVfNA==",
"requires": { "requires": {
"tslib": "1.10.0" "tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
} }
}, },
"@pnp/sp": { "@pnp/sp": {
"version": "1.3.10", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/@pnp/sp/-/sp-1.3.10.tgz", "resolved": "https://registry.npmjs.org/@pnp/sp/-/sp-1.3.11.tgz",
"integrity": "sha512-TWah8FCtQ1RRaiQa7qq2QuJdiv6lAQjq6pacurBI27CWuDEYf3aIwg7imjSnE/N5WG7Kne3lgt5ugDbj50YH9Q==", "integrity": "sha512-NjdeGe81aukiSPelSPjgAFRC1+SrNPTXvTdEqTH+Q1ZvgNtk8bdZp6K6xf9emfeM2qZDOu9GpKZpg0W/emq++g==",
"requires": { "requires": {
"tslib": "1.10.0" "tslib": "1.10.0"
}, }
"dependencies": { },
"tslib": { "@pnp/telemetry-js": {
"version": "1.10.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@pnp/telemetry-js/-/telemetry-js-2.0.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" "integrity": "sha512-qFNm3mTerTnxgTR6c/4iMMt8EUKrQn5z0XG/IQtpNlp6m7KXRDFR87mQKeBVtSv2LhxGO0VNFndKJIibBw52zQ==",
} "requires": {
"whatwg-fetch": "2.0.4"
} }
}, },
"@uifabric/icons": { "@uifabric/icons": {
@ -3017,6 +2998,16 @@
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"tslib": "^1.7.1" "tslib": "^1.7.1"
} }
},
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
},
"whatwg-fetch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
} }
} }
}, },
@ -4044,9 +4035,9 @@
"integrity": "sha1-4rwxvHEqr/ugU6pN1GvITrXSCQ8=" "integrity": "sha1-4rwxvHEqr/ugU6pN1GvITrXSCQ8="
}, },
"adaptivecards": { "adaptivecards": {
"version": "1.2.5", "version": "1.2.6",
"resolved": "https://registry.npmjs.org/adaptivecards/-/adaptivecards-1.2.5.tgz", "resolved": "https://registry.npmjs.org/adaptivecards/-/adaptivecards-1.2.6.tgz",
"integrity": "sha512-Rj+QK0qtBOfLGy3ClXylKxL4ze/a6mtPiJL7Ctjyc1Uso9O1x/LAAu49F36ZQbgAa8vWkKW91RKcwBBOxk3HDg==" "integrity": "sha512-/l34rvdRzQ20QdGLk+awRUotexu3N4Ih3O0qR8cM+2wWe0pggvWhmFdwVFmM+YgIS5pWtl2u7XAJynUaFIQAIw=="
}, },
"adaptivecards-fabric": { "adaptivecards-fabric": {
"version": "1.0.4", "version": "1.0.4",
@ -4054,9 +4045,9 @@
"integrity": "sha512-ovjp0f6xfzEBdTXVpBwNTovxjM3S7q/aJe39F58Ybe1+AO+warRFdpIT5v1HcxBwYoDsnllwo9U9Ne52TcL96A==" "integrity": "sha512-ovjp0f6xfzEBdTXVpBwNTovxjM3S7q/aJe39F58Ybe1+AO+warRFdpIT5v1HcxBwYoDsnllwo9U9Ne52TcL96A=="
}, },
"adaptivecards-templating": { "adaptivecards-templating": {
"version": "0.1.1-alpha.0", "version": "0.1.1-alpha.1",
"resolved": "https://registry.npmjs.org/adaptivecards-templating/-/adaptivecards-templating-0.1.1-alpha.0.tgz", "resolved": "https://registry.npmjs.org/adaptivecards-templating/-/adaptivecards-templating-0.1.1-alpha.1.tgz",
"integrity": "sha512-rG17v9nKdX60SRDPSFabTU3HynTEvACmlN6Du0hMCf1x/HFzF1Y0fwTrpIfoxf0mVhM4okBupPOLL5f7K+JX+Q==" "integrity": "sha512-pK34y5tcqmtcUZaaEK1EgrTLJX8yq6RYc2hp3x/IsLdDZm6pFGWliYD8pAQnJdyvblpxV82XTnAMhnBw0HUi7A=="
}, },
"agent-base": { "agent-base": {
"version": "4.3.0", "version": "4.3.0",
@ -8277,7 +8268,8 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -8298,12 +8290,14 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -8318,17 +8312,20 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -8445,7 +8442,8 @@
"inherits": { "inherits": {
"version": "2.0.4", "version": "2.0.4",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -8457,6 +8455,7 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -8471,6 +8470,7 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -8478,12 +8478,14 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.9.0", "version": "2.9.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -8502,6 +8504,7 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -8591,7 +8594,8 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -8603,6 +8607,7 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -8688,7 +8693,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -8724,6 +8730,7 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -8743,6 +8750,7 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -8786,12 +8794,14 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.1.1", "version": "3.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
} }
} }
}, },
@ -12913,6 +12923,11 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true "dev": true
}, },
"lodash.omit": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
"integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA="
},
"lodash.restparam": { "lodash.restparam": {
"version": "3.6.1", "version": "3.6.1",
"resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "adaptive-card-host", "name": "adaptive-card-host",
"version": "0.0.1", "version": "2.1.0",
"private": true, "private": true,
"main": "lib/index.js", "main": "lib/index.js",
"engines": { "engines": {
@ -21,14 +21,14 @@
"@microsoft/sp-webpart-base": "1.10.0", "@microsoft/sp-webpart-base": "1.10.0",
"@pnp/sp": "^2.0.3", "@pnp/sp": "^2.0.3",
"@pnp/spfx-controls-react": "1.16.0", "@pnp/spfx-controls-react": "1.16.0",
"@pnp/spfx-property-controls": "1.16.0", "@pnp/spfx-property-controls": "^1.18.0",
"@types/es6-promise": "0.0.33", "@types/es6-promise": "0.0.33",
"@types/react": "16.8.8", "@types/react": "16.8.8",
"@types/react-dom": "16.8.3", "@types/react-dom": "16.8.3",
"@types/webpack-env": "1.13.1", "@types/webpack-env": "1.13.1",
"adaptivecards": "^1.2.5", "adaptivecards": "^1.2.6",
"adaptivecards-fabric": "^1.0.4", "adaptivecards-fabric": "^1.0.4",
"adaptivecards-templating": "^0.1.1-alpha.0", "adaptivecards-templating": "^0.1.1-alpha.1",
"markdown-it": "^10.0.0", "markdown-it": "^10.0.0",
"office-ui-fabric-react": "6.189.2", "office-ui-fabric-react": "6.189.2",
"react": "16.8.5", "react": "16.8.5",

View File

@ -73,10 +73,17 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
if (this.props.data && this.props.useTemplating) { if (this.props.data && this.props.useTemplating) {
// Define a template payload // Define a template payload
console.log("Using templating");
var templatePayload = {}; var templatePayload = {};
try { try {
templatePayload = JSON.parse(this.props.template); // KLUDGE: Temporary fix for Adaptive Templating May 2020 change
// to be updated when new version of Adapting Template package is available
var templating:string = this.props.template.split("${").join('{');
templatePayload = JSON.parse(templating);
//
//templatePayload = JSON.parse(this.props.template);
} catch (error) { } catch (error) {
console.error("Something went wrong with the template", error);
this._errorHandler(strings.TemplatingJsonError + error); this._errorHandler(strings.TemplatingJsonError + error);
return; return;
} }
@ -86,6 +93,13 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
// Create a data binding context, and set its $root property to the // Create a data binding context, and set its $root property to the
// data object to bind the template to // data object to bind the template to
// BUG: According to https://docs.microsoft.com/en-us/adaptive-cards/templating/ we're supposed to use
//var card = template.expand({
//$root: {
// // Your data goes here
//}
//});
// ...but that doesn't work
var context = new ACData.EvaluationContext(); var context = new ACData.EvaluationContext();
try { try {
context.$root = JSON.parse(this.props.data); context.$root = JSON.parse(this.props.data);

View File

@ -1,126 +0,0 @@
import { IWebPartContext, IPropertyPaneCustomFieldProps } from '@microsoft/sp-webpart-base';
import { ISPView } from './ISPView';
/**
* Enum for specifying how the views should be sorted
*/
export enum PropertyFieldViewPickerOrderBy {
Id = 1,
Title
}
/**
* Public properties of the PropertyFieldViewPicker custom field
*/
export interface IPropertyFieldViewPickerProps {
/**
* Context of the current web part
*/
context: IWebPartContext;
/**
* Custom Field will start to validate after users stop typing for `deferredValidationTime` milliseconds.
* Default value is 200.
*/
deferredValidationTime?: number;
/**
* Whether the property pane field is enabled or not.
*/
disabled?: boolean;
/**
* Filter views from Odata query
*/
filter?: string;
/**
* An UNIQUE key indicates the identity of this control
*/
key?: string;
/**
* Property field label displayed on top
*/
label: string;
/**
* The List Id of the list where you want to get the views
*/
listId?: string;
/**
* Specify the property on which you want to order the retrieve set of views.
*/
orderBy?: PropertyFieldViewPickerOrderBy;
/**
* Parent Web Part properties
*/
properties: any;
/**
* Initial selected view of the control
*/
selectedView?: string | string[];
/**
* Defines view titles which should be excluded from the view picker control
*/
viewsToExclude?: string[];
/**
* Absolute Web Url of target site (user requires permissions)
*/
webAbsoluteUrl?: string;
/**
* 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>;
/**
* 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;
/**
* Callback that is called before the dropdown is populated
*/
onViewsRetrieved?: (views: ISPView[]) => PromiseLike<ISPView[]> | ISPView[];
}
/**
* Private properties of the PropertyFieldViewPicker custom field.
* We separate public & private properties to include onRender & onDispose method waited
* by the PropertyFieldCustom, without asking to the developer to add it when he's using
* the PropertyFieldViewPicker.
*/
export interface IPropertyFieldViewPickerPropsInternal extends IPropertyFieldViewPickerProps, IPropertyPaneCustomFieldProps {
context: IWebPartContext;
deferredValidationTime?: number;
disabled?: boolean;
filter?: string;
key: string;
label: string;
listId?: string;
orderBy?: PropertyFieldViewPickerOrderBy;
properties: any;
selectedView?: string;
targetProperty: string;
viewsToExclude?: string[];
webAbsoluteUrl?: string;
onGetErrorMessage?: (value: string | string[]) => string | Promise<string>;
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void;
onViewsRetrieved?: (views: ISPView[]) => PromiseLike<ISPView[]> | ISPView[];
}

View File

@ -1,19 +0,0 @@
import { IPropertyFieldViewPickerPropsInternal } from './IPropertyFieldViewPicker';
import { IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
/**
* PropertyFieldViewPickerHost properties interface
*/
export interface IPropertyFieldViewPickerHostProps extends IPropertyFieldViewPickerPropsInternal {
onChange: (targetProperty?: string, newValue?: any) => void;
}
/**
* PropertyFieldViewPickerHost state interface
*/
export interface IPropertyFieldViewPickerHostState {
results: IDropdownOption[];
selectedKey?: string;
errorMessage?: string;
}

View File

@ -1,4 +0,0 @@
export interface ISPView {
Id: string;
Title: string;
}

View File

@ -1,9 +0,0 @@
import { ISPView } from ".";
/**
* Defines a collection of SharePoint list views
*/
export interface ISPViews {
value: ISPView[];
}

View File

@ -1,143 +0,0 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import {
IPropertyPaneField,
PropertyPaneFieldType,
IWebPartContext
} from '@microsoft/sp-webpart-base';
import PropertyFieldViewPickerHost from './PropertyFieldViewPickerHost';
import { IPropertyFieldViewPickerHostProps } from './IPropertyFieldViewPickerHost';
import { PropertyFieldViewPickerOrderBy, IPropertyFieldViewPickerProps, IPropertyFieldViewPickerPropsInternal } from './IPropertyFieldViewPicker';
import { ISPView } from '.';
/**
* Represents a PropertyFieldViewPicker object
*/
class PropertyFieldViewPickerBuilder implements IPropertyPaneField<IPropertyFieldViewPickerPropsInternal> {
//Properties defined by IPropertyPaneField
public properties: IPropertyFieldViewPickerPropsInternal;
public targetProperty: string;
public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
//Custom properties label: string;
private context: IWebPartContext;
private label: string;
private listId?: string;
private orderBy: PropertyFieldViewPickerOrderBy;
private selectedView: string;
private viewsToExclude: string[];
private customProperties: any;
private deferredValidationTime: number = 200;
private disabled: boolean = false;
private disableReactivePropertyChanges: boolean = false;
private filter: string;
private key: string;
private webAbsoluteUrl?: string;
private onGetErrorMessage: (value: string) => string | Promise<string>;
private onViewsRetrieved?: (views: ISPView[]) => PromiseLike<ISPView[]> | ISPView[];
public onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void { }
private renderWebPart: () => void;
/**
* Constructor method
*/
public constructor(_targetProperty: string, _properties: IPropertyFieldViewPickerPropsInternal) {
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.listId = _properties.listId;
this.selectedView = _properties.selectedView;
this.orderBy = _properties.orderBy;
this.onPropertyChange = _properties.onPropertyChange;
this.customProperties = _properties.properties;
this.key = _properties.key;
this.viewsToExclude = _properties.viewsToExclude;
this.filter = _properties.filter;
this.onGetErrorMessage = _properties.onGetErrorMessage;
this.onViewsRetrieved = _properties.onViewsRetrieved;
if (_properties.disabled === true) {
this.disabled = _properties.disabled;
}
if (_properties.deferredValidationTime) {
this.deferredValidationTime = _properties.deferredValidationTime;
}
}
/**
* Renders the SPViewPicker field content
*/
private render(elem: HTMLElement, ctx?: any, changeCallback?: (targetProperty?: string, newValue?: any) => void): void {
const componentProps = {
label: this.label,
targetProperty: this.targetProperty,
context: this.context,
webAbsoluteUrl: this.webAbsoluteUrl,
listId: this.listId,
orderBy: this.orderBy,
onDispose: this.dispose,
onRender: this.render,
onChange: changeCallback,
onPropertyChange: this.onPropertyChange,
properties: this.customProperties,
key: this.key,
disabled: this.disabled,
onGetErrorMessage: this.onGetErrorMessage,
deferredValidationTime: this.deferredValidationTime,
viewsToExclude: this.viewsToExclude,
filter: this.filter,
onViewsRetrieved: this.onViewsRetrieved
};
// Single selector
componentProps['selectedView'] = this.selectedView;
const element: React.ReactElement<IPropertyFieldViewPickerHostProps> = React.createElement(PropertyFieldViewPickerHost, componentProps);
// Calls the REACT content generator
ReactDom.render(element, elem);
}
/**
* Disposes the current object
*/
private dispose(_elem: HTMLElement): void {
}
}
/**
* Helper method to create a SPView Picker on the PropertyPane.
* @param targetProperty - Target property the SharePoint view picker is associated to.
* @param properties - Strongly typed SPView Picker properties.
*/
export function PropertyFieldViewPicker(targetProperty: string, properties: IPropertyFieldViewPickerProps): IPropertyPaneField<IPropertyFieldViewPickerPropsInternal> {
//Create an internal properties object from the given properties
const newProperties: IPropertyFieldViewPickerPropsInternal = {
label: properties.label,
targetProperty: targetProperty,
context: properties.context,
listId: properties.listId,
selectedView: typeof properties.selectedView === 'string' ? properties.selectedView : null,
onPropertyChange: properties.onPropertyChange,
properties: properties.properties,
onDispose: null,
onRender: null,
key: properties.key,
disabled: properties.disabled,
viewsToExclude: properties.viewsToExclude,
filter: properties.filter,
onGetErrorMessage: properties.onGetErrorMessage,
deferredValidationTime: properties.deferredValidationTime,
onViewsRetrieved: properties.onViewsRetrieved
};
//Calls the PropertyFieldViewPicker builder object
//This object will simulate a PropertyFieldCustom to manage his rendering process
return new PropertyFieldViewPickerBuilder(targetProperty, newProperties);
}

View File

@ -1,202 +0,0 @@
import * as React from 'react';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { Async } from 'office-ui-fabric-react/lib/Utilities';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { IPropertyFieldViewPickerHostProps, IPropertyFieldViewPickerHostState } from './IPropertyFieldViewPickerHost';
import { SPViewPickerService } from '../../services/SPViewPickerService';
import FieldErrorMessage from '@pnp/spfx-property-controls/lib/propertyFields/errorMessage/FieldErrorMessage';
import { ISPView } from '.';
import { ISPViews } from './ISPViews';
// Empty view value
const EMPTY_VIEW_KEY = 'NO_VIEW_SELECTED';
/**
* Renders the controls for PropertyFieldViewPicker component
*/
export default class PropertyFieldViewPickerHost extends React.Component<IPropertyFieldViewPickerHostProps, IPropertyFieldViewPickerHostState> {
private options: IDropdownOption[] = [];
private selectedKey: string;
private latestValidateValue: string;
private async: Async;
private delayedValidate: (value: string) => void;
/**
* Constructor method
*/
constructor(props: IPropertyFieldViewPickerHostProps) {
super(props);
this.state = {
results: this.options,
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 list views
this.loadViews();
}
public componentDidUpdate(prevProps: IPropertyFieldViewPickerHostProps, _prevState: IPropertyFieldViewPickerHostState): void {
if (this.props.listId !== prevProps.listId || this.props.webAbsoluteUrl !== prevProps.webAbsoluteUrl) {
this.loadViews();
}
}
/**
* Loads the views from a SharePoint list
*/
private loadViews(): void {
const viewService: SPViewPickerService = new SPViewPickerService(this.props, this.props.context);
const viewsToExclude: string[] = this.props.viewsToExclude || [];
this.options = [];
viewService.getViews().then((response: ISPViews) => {
// Start mapping the views that are selected
response.value.forEach((view: ISPView) => {
if (this.props.selectedView === view.Id) {
this.selectedKey = view.Id;
}
// Make sure that the current view is NOT in the 'viewsToExclude' array
if (viewsToExclude.indexOf(view.Title) === -1 && viewsToExclude.indexOf(view.Id) === -1) {
this.options.push({
key: view.Id,
text: view.Title
});
}
});
// Option to unselect the view
this.options.unshift({
key: EMPTY_VIEW_KEY,
text: ''
});
// Update the current component state
this.setState({
results: this.options,
selectedKey: this.selectedKey
});
});
}
/**
* Raises when a view 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(this.props.selectedView, value);
return;
}
if (this.latestValidateValue === value) {
return;
}
this.latestValidateValue = value;
const errResult: string | PromiseLike<string> = this.props.onGetErrorMessage(value || '');
if (typeof errResult !== 'undefined') {
if (typeof errResult === 'string') {
if (errResult === '') {
this.notifyAfterValidate(this.props.selectedView, value);
}
this.setState({
errorMessage: errResult
});
} else {
errResult.then((errorMessage: string) => {
if (!errorMessage) {
this.notifyAfterValidate(this.props.selectedView, value);
}
this.setState({
errorMessage: errorMessage
});
});
}
} else {
this.notifyAfterValidate(this.props.selectedView, value);
}
}
/**
* Notifies the parent Web Part of a property value change
*/
private notifyAfterValidate(oldValue: string, newValue: string) {
// Check if the user wanted to unselect the view
const propValue = newValue === EMPTY_VIEW_KEY ? '' : newValue;
// Deselect all options
this.options = this.state.results.map(option => {
if (option.selected) {
option.selected = false;
}
return option;
});
// Set the current selected key
this.selectedKey = newValue;
// Update the state
this.setState({
selectedKey: this.selectedKey,
results: this.options
});
if (this.props.onPropertyChange && propValue !== null) {
// Store the new property value
this.props.properties[this.props.targetProperty] = propValue;
// Trigger the default onPropertyChange event
this.props.onPropertyChange(this.props.targetProperty, oldValue, propValue);
// Trigger the apply button
if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) {
this.props.onChange(this.props.targetProperty, propValue);
}
}
}
/**
* Called when the component will unmount
*/
public componentWillUnmount() {
if (typeof this.async !== 'undefined') {
this.async.dispose();
}
}
/**
* Renders the SPViewPicker 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=''
onChanged={this.onChanged}
options={this.state.results}
selectedKey={this.state.selectedKey}
/>
<FieldErrorMessage errorMessage={this.state.errorMessage} />
</div>
);
}
}

View File

@ -1,6 +0,0 @@
export * from './PropertyFieldViewPicker';
export * from './IPropertyFieldViewPicker';
export * from './PropertyFieldViewPickerHost';
export * from './IPropertyFieldViewPickerHost';
export * from './ISPView';
export * from './ISPViews';

View File

@ -1,6 +0,0 @@
import { ISPViews } from "../../controls/PropertyFieldViewPicker";
export interface ISPViewPickerService {
getViews(): Promise<ISPViews>;
}

View File

@ -1,113 +0,0 @@
import { SPHttpClientResponse } from '@microsoft/sp-http';
import { SPHttpClient } from '@microsoft/sp-http';
import { Environment, EnvironmentType } from '@microsoft/sp-core-library';
import { IWebPartContext } from '@microsoft/sp-webpart-base';
import { ISPView, IPropertyFieldViewPickerHostProps, PropertyFieldViewPickerOrderBy } from '../../controls/PropertyFieldViewPicker';
import { ISPViewPickerService } from './ISPViewPickerService';
import { ISPViews } from '../../controls/PropertyFieldViewPicker/ISPViews';
/**
* Service implementation to get list & list items from current SharePoint site
*/
export class SPViewPickerService implements ISPViewPickerService {
private context: IWebPartContext;
private props: IPropertyFieldViewPickerHostProps;
/**
* Service constructor
*/
constructor(_props: IPropertyFieldViewPickerHostProps, pageContext: IWebPartContext) {
this.props = _props;
this.context = pageContext;
}
/**
* Gets the collection of view for a selected list
*/
public async getViews(): Promise<ISPViews> {
if (Environment.type === EnvironmentType.Local) {
// If the running environment is local, load the data from the mock
return this.getViewsFromMock();
}
else {
if (this.props.listId === undefined || this.props.listId === "") {
return this.getEmptyViews();
}
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 = `${webAbsoluteUrl}/_api/lists(guid'${this.props.listId}')/Views?$select=Title,Id`;
// Check if the orderBy property is provided
if (this.props.orderBy !== null) {
queryUrl += '&$orderby=';
switch (this.props.orderBy) {
case PropertyFieldViewPickerOrderBy.Id:
queryUrl += 'Id';
break;
case PropertyFieldViewPickerOrderBy.Title:
queryUrl += 'Title';
break;
}
// Adds an OData Filter to the list
if (this.props.filter){
queryUrl += `&$filter=${encodeURIComponent(this.props.filter)}`;
}
let response = await this.context.spHttpClient.get(queryUrl, SPHttpClient.configurations.v1);
let views = (await response.json()) as ISPViews;
// Check if onViewsRetrieved callback is defined
if (this.props.onViewsRetrieved) {
//Call onViewsRetrieved
let lr = this.props.onViewsRetrieved(views.value);
let output: ISPView[];
//Conditional checking to see of PromiseLike object or array
if (lr instanceof Array) {
output = lr;
} else {
output = await lr;
}
views.value = output;
}
return views;
}
}
}
/**
* Returns an empty view for when a list isn't selected
*/
private getEmptyViews(): Promise<ISPViews> {
return new Promise<ISPViews>((resolve) => {
const listData: ISPViews = {
value:[
]
};
resolve(listData);
});
}
/**
* Returns 3 fake SharePoint views for the Mock mode
*/
private getViewsFromMock(): Promise<ISPViews> {
return new Promise<ISPViews>((resolve) => {
const listData: ISPViews = {
value:[
{ Title: 'Mock View One', Id: '3bacd87b-b7df-439a-bb20-4d4d13523431' },
{ Title: 'Mock View Two', Id: '5e37c820-e2cb-49f7-93f5-14003c07788b' },
{ Title: 'Mock View Three', Id: '5fda7245-c4a7-403b-adc1-8bd8b481b4ee' }
]
};
resolve(listData);
});
}
}

View File

@ -1,2 +0,0 @@
export * from './SPViewPickerService';
export * from './ISPViewPickerService';

View File

@ -3,7 +3,7 @@ import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library'; import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { DisplayMode } from '@microsoft/sp-core-library'; import { DisplayMode } from '@microsoft/sp-core-library';
import { HttpClient, HttpClientConfiguration, HttpClientResponse } from '@microsoft/sp-http'; import { HttpClient, HttpClientResponse } from '@microsoft/sp-http';
// Used for property pane // Used for property pane
import { import {
@ -17,7 +17,7 @@ import {
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker'; import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
// Used to pick which view you want // Used to pick which view you want
import { PropertyFieldViewPicker, PropertyFieldViewPickerOrderBy } from '../../controls/PropertyFieldViewPicker'; import { PropertyFieldViewPicker, PropertyFieldViewPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldViewPicker';
// Used by the code editor fields // Used by the code editor fields
import { PropertyFieldCodeEditorLanguages } from '@pnp/spfx-property-controls/lib/PropertyFieldCodeEditor'; import { PropertyFieldCodeEditorLanguages } from '@pnp/spfx-property-controls/lib/PropertyFieldCodeEditor';
@ -124,7 +124,6 @@ export default class AdaptiveCardHostWebPart extends BaseClientSideWebPart<IAdap
} }
public async render(): Promise<void> { public async render(): Promise<void> {
const { template } = this.properties;
const templateJson: string = this.properties.templateSource === 'url' && this.properties.templateUrl ? this._templateJSON: this.properties.template; const templateJson: string = this.properties.templateSource === 'url' && this.properties.templateUrl ? this._templateJSON: this.properties.template;
const dataJson: string = (this.properties.dataSource === 'list' && this.properties.list && this.properties.view) || const dataJson: string = (this.properties.dataSource === 'list' && this.properties.list && this.properties.view) ||