Merge pull request #1988 from pnp/adaptive-cards-fix

Updated AdaptiveCards and fixed error handling
This commit is contained in:
Hugo Bernier 2021-08-02 21:27:25 -04:00 committed by GitHub
commit 0a0ef4f315
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 11058 additions and 9892 deletions

View File

@ -1,328 +0,0 @@
{
"always-semicolon": true,
"color-case": "lower",
"block-indent": "\t",
"color-shorthand": true,
"element-case": "lower",
"leading-zero": false,
"quotes": "double",
"sort-order-fallback": "abc",
"space-before-colon": "",
"space-after-colon": " ",
"space-before-combinator": " ",
"space-after-combinator": " ",
"space-between-declarations": "\n",
"space-before-opening-brace": "",
"space-after-opening-brace": "\n",
"space-after-selector-delimiter": "\n",
"space-before-selector-delimiter": "",
"space-before-closing-brace": "\n",
"strip-spaces": true,
"tab-size": true,
"unitless-zero": true,
"vendor-prefix-align": true,
"sort-order": [
[
"$extend",
"$include"
],
[
"font",
"font-family",
"font-size",
"font-weight",
"font-style",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"line-height"
],
[
"position",
"z-index",
"top",
"right",
"bottom",
"left"
],
[
"display",
"visibility",
"float",
"clear",
"overflow",
"overflow-x",
"overflow-y",
"-ms-overflow-x",
"-ms-overflow-y",
"clip",
"zoom",
"flex-direction",
"flex-order",
"flex-pack",
"flex-align"
],
[
"-webkit-box-sizing",
"-moz-box-sizing",
"box-sizing",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left"
],
[
"table-layout",
"empty-cells",
"caption-side",
"border-spacing",
"border-collapse",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image"
],
[
"content",
"quotes",
"counter-reset",
"counter-increment",
"resize",
"cursor",
"-webkit-user-select",
"-moz-user-select",
"-ms-user-select",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"-webkit-transition",
"-moz-transition",
"-ms-transition",
"-o-transition",
"transition",
"-webkit-transition-delay",
"-moz-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"transition-delay",
"-webkit-transition-timing-function",
"-moz-transition-timing-function",
"-ms-transition-timing-function",
"-o-transition-timing-function",
"transition-timing-function",
"-webkit-transition-duration",
"-moz-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"transition-duration",
"-webkit-transition-property",
"-moz-transition-property",
"-ms-transition-property",
"-o-transition-property",
"transition-property",
"-webkit-transform",
"-moz-transform",
"-ms-transform",
"-o-transform",
"transform",
"-webkit-transform-origin",
"-moz-transform-origin",
"-ms-transform-origin",
"-o-transform-origin",
"transform-origin",
"-webkit-animation",
"-moz-animation",
"-ms-animation",
"-o-animation",
"animation",
"-webkit-animation-name",
"-moz-animation-name",
"-ms-animation-name",
"-o-animation-name",
"animation-name",
"-webkit-animation-duration",
"-moz-animation-duration",
"-ms-animation-duration",
"-o-animation-duration",
"animation-duration",
"-webkit-animation-play-state",
"-moz-animation-play-state",
"-ms-animation-play-state",
"-o-animation-play-state",
"animation-play-state",
"-webkit-animation-timing-function",
"-moz-animation-timing-function",
"-ms-animation-timing-function",
"-o-animation-timing-function",
"animation-timing-function",
"-webkit-animation-delay",
"-moz-animation-delay",
"-ms-animation-delay",
"-o-animation-delay",
"animation-delay",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-direction",
"-moz-animation-direction",
"-ms-animation-direction",
"-o-animation-direction",
"animation-direction",
"text-align",
"-webkit-text-align-last",
"-moz-text-align-last",
"-ms-text-align-last",
"text-align-last",
"vertical-align",
"white-space",
"text-decoration",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-indent",
"-ms-text-justify",
"text-justify",
"letter-spacing",
"word-spacing",
"-ms-writing-mode",
"text-outline",
"text-transform",
"text-wrap",
"text-overflow",
"-ms-text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"-ms-word-wrap",
"word-wrap",
"word-break",
"-ms-word-break",
"-moz-tab-size",
"-o-tab-size",
"tab-size",
"-webkit-hyphens",
"-moz-hyphens",
"hyphens",
"pointer-events"
],
[
"opacity",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
"-ms-interpolation-mode",
"color",
"border",
"border-width",
"border-style",
"border-color",
"border-top",
"border-top-width",
"border-top-style",
"border-top-color",
"border-right",
"border-right-width",
"border-right-style",
"border-right-color",
"border-bottom",
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
"border-left",
"border-left-width",
"border-left-style",
"border-left-color",
"-webkit-border-radius",
"-moz-border-radius",
"border-radius",
"-webkit-border-top-left-radius",
"-moz-border-radius-topleft",
"border-top-left-radius",
"-webkit-border-top-right-radius",
"-moz-border-radius-topright",
"border-top-right-radius",
"-webkit-border-bottom-right-radius",
"-moz-border-radius-bottomright",
"border-bottom-right-radius",
"-webkit-border-bottom-left-radius",
"-moz-border-radius-bottomleft",
"border-bottom-left-radius",
"-webkit-border-image",
"-moz-border-image",
"-o-border-image",
"border-image",
"-webkit-border-image-source",
"-moz-border-image-source",
"-o-border-image-source",
"border-image-source",
"-webkit-border-image-slice",
"-moz-border-image-slice",
"-o-border-image-slice",
"border-image-slice",
"-webkit-border-image-width",
"-moz-border-image-width",
"-o-border-image-width",
"border-image-width",
"-webkit-border-image-outset",
"-moz-border-image-outset",
"-o-border-image-outset",
"border-image-outset",
"-webkit-border-image-repeat",
"-moz-border-image-repeat",
"-o-border-image-repeat",
"border-image-repeat",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"background",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"background-color",
"background-image",
"background-repeat",
"background-attachment",
"background-position",
"background-position-x",
"-ms-background-position-x",
"background-position-y",
"-ms-background-position-y",
"-webkit-background-clip",
"-moz-background-clip",
"background-clip",
"background-origin",
"-webkit-background-size",
"-moz-background-size",
"-o-background-size",
"background-size",
"box-decoration-break",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"filter:progid:DXImageTransform.Microsoft.gradient",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
"text-shadow"
]
]
}

View File

@ -1,25 +0,0 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 2
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

View File

@ -9,6 +9,7 @@ node_modules
# Build generated files
dist
lib
release
solution
temp
*.sppkg

View File

@ -1,10 +0,0 @@
{
"extends": "stylelint-config-standard",
"plugins": [
"stylelint-scss"
],
"rules": {
"at-rule-no-unknown": null,
"scss/at-rule-no-unknown": true
}
}

View File

@ -1,381 +0,0 @@
{
"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": 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

@ -1,29 +1,12 @@
{
"@pnp/generator-spfx": {
"framework": "react",
"pnpFramework": "reactjs.plus",
"pnp-libraries": [
"@pnp/spfx-property-controls",
"rush@3.3"
],
"pnp-ci": "no-devops",
"pnp-vetting": [
"webpack-analyzer",
"stylelint",
"csscomb"
],
"spfxenv": "spo",
"pnp-testing": []
},
"@microsoft/generator-sharepoint": {
"isCreatingSolution": true,
"environment": "spo",
"framework": "react",
"isCreatingSolution": false,
"version": "1.11.0",
"libraryName": "adaptive-card-host",
"libraryId": "ce1e3712-fb7a-4564-b2d3-c81e45936afd",
"version": "1.12.1",
"libraryName": "react-adaptivecards",
"libraryId": "f504f00b-ee99-4184-97cd-114c9b9e75ca",
"packageManager": "npm",
"isDomainIsolated": false,
"componentType": "webpart"
}
}
}

View File

@ -13,12 +13,11 @@ This sample creates an Adaptive Cards Host web part that you can use to display
## Compatibility
![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
![Node.js LTS 10.x](https://img.shields.io/badge/Node.js-LTS%2010.x-green.svg)
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
![Workbench Local (Partially) | Hosted](https://img.shields.io/badge/Workbench-Local%20%7C%20Hosted-yellow.svg)
![Workbench Local | Hosted](https://img.shields.io/badge/Workbench-Local%20%7C%20Hosted-green.svg)
## Applies to
@ -45,6 +44,7 @@ Version|Date|Comments
2.1.0|June 11, 2020|Fixed breaking changes introduced with Adaptive Card Templating in May update
2.2.0|August 25, 2020|Upgraded to SPFx 1.11
2.2.1|February 23, 2021|Fixed FluentUI dependencies introduced with newer versions of Adaptive Cards React.
2.3.0|August 2, 2021|Upgraded to SPFx 1.12.1
## Disclaimer

View File

@ -9,7 +9,7 @@
"This sample creates an Adaptive Cards Host web part that you can use to display Adaptive Cards in your SharePoint applications."
],
"creationDateTime": "2021-02-23",
"updateDateTime": "2021-02-23",
"updateDateTime": "2021-08-02",
"products": [
"SharePoint",
"Office"
@ -21,7 +21,7 @@
},
{
"key": "SPFX-VERSION",
"value": "1.11.0"
"value": "1.12.1"
},
{
"key": "SPFX-SUPPORTSTHEMEVARIANTS",

View File

@ -14,7 +14,7 @@
"externals": {},
"localizedResources": {
"AdaptiveCardHostWebPartStrings": "lib/webparts/adaptiveCardHost/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js",
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
}
}
}

View File

@ -1,4 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
"deployCdnPath": "temp/deploy"
"deployCdnPath": "./release/assets/"
}

View File

@ -1,7 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"workingDir": "./release/assets/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "adaptive-card-host",
"container": "react-adaptivecards",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -1,9 +1,9 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "adaptive-cards",
"id": "ce1e3712-fb7a-4564-b2d3-c81e45936afd",
"version": "2.2.1.0",
"name": "react-adaptivecards-client-side-solution",
"id": "f504f00b-ee99-4184-97cd-114c9b9e75ca",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false,
"developer": {
@ -11,10 +11,10 @@
"websiteUrl": "",
"privacyUrl": "",
"termsOfUseUrl": "",
"mpnId": "m365pnp"
"mpnId": ""
}
},
"paths": {
"zippedPackage": "solution/adaptive-cars.sppkg"
"zippedPackage": "solution/react-adaptivecards.sppkg"
}
}

View File

@ -1,77 +1,16 @@
'use strict';
// check if gulp dist was called
if (process.argv.indexOf('dist') !== -1) {
// add ship options to command call
process.argv.push('--ship');
}
const path = require('path');
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
const gulpSequence = require('gulp-sequence');
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
// Create clean distrubution package
gulp.task('dist', gulpSequence('clean', 'bundle', 'package-solution'));
// Create clean development package
gulp.task('dev', gulpSequence('clean', 'bundle', 'package-solution'));
var getTasks = build.rig.getTasks;
build.rig.getTasks = function () {
var result = getTasks.call(build.rig);
result.set('serve', result.get('serve-deprecated'));
return result;
};
/**
* Webpack Bundle Anlayzer
* Reference and gulp task
*/
const bundleAnalyzer = require('webpack-bundle-analyzer');
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
const lastDirName = path.basename(__dirname);
const dropPath = path.join(__dirname, 'temp', 'stats');
generatedConfiguration.plugins.push(new bundleAnalyzer.BundleAnalyzerPlugin({
openAnalyzer: false,
analyzerMode: 'static',
reportFilename: path.join(dropPath, `${lastDirName}.stats.html`),
generateStatsFile: true,
statsFilename: path.join(dropPath, `${lastDirName}.stats.json`),
logLevel: 'error'
}));
return generatedConfiguration;
}
});
/**
* StyleLinter configuration
* Reference and custom gulp task
*/
const stylelint = require('gulp-stylelint');
/* Stylelinter sub task */
let styleLintSubTask = build.subTask('stylelint', (gulp) => {
return gulp
.src('src/**/*.scss')
.pipe(stylelint({
failAfterError: false,
reporters: [{
formatter: 'string',
console: true
}]
}));
});
/* end sub task */
build.rig.addPreBuildTask(styleLintSubTask);
/**
* Custom Framework Specific gulp tasks
*/
build.initialize(gulp);
build.initialize(require('gulp'));

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,42 @@
{
"name": "adaptive-card-host",
"version": "2.2.1",
"name": "react-adaptivecards",
"version": "0.0.1",
"private": true,
"main": "lib/index.js",
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test",
"preversion": "node ./tools/pre-version.js",
"postversion": "gulp dist"
"test": "gulp test"
},
"dependencies": {
"@fluentui/react": "^7.161.0",
"@microsoft/sp-core-library": "1.11.0",
"@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
"@microsoft/sp-property-pane": "1.11.0",
"@microsoft/sp-webpart-base": "1.11.0",
"@fluentui/react": "^8.26.1",
"@microsoft/sp-core-library": "1.12.1",
"@microsoft/sp-lodash-subset": "1.12.1",
"@microsoft/sp-office-ui-fabric-core": "1.12.1",
"@microsoft/sp-property-pane": "1.12.1",
"@microsoft/sp-webpart-base": "1.12.1",
"@pnp/sp": "^2.0.3",
"@pnp/spfx-controls-react": "1.16.0",
"@pnp/spfx-property-controls": "^1.18.0",
"@uifabric/fluent-theme": "^7.4.3",
"adaptivecards": "^1.2.6",
"adaptivecards-fabric": "^1.1.1",
"adaptivecards-templating": "1.1.0",
"adaptive-expressions": "^4.14.1",
"adaptivecards": "^2.9.0",
"adaptivecards-fluentui": "^0.5.3",
"adaptivecards-templating": "^2.1.0",
"markdown-it": "^10.0.0",
"office-ui-fabric-react": "^6.189.2",
"react": "16.8.5",
"react-dom": "16.8.5",
"save": "^2.4.0"
},
"resolutions": {
"@types/react": "16.8.8"
"office-ui-fabric-react": "7.156.0",
"react": "16.9.0",
"react-dom": "16.9.0"
},
"devDependencies": {
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
"@microsoft/sp-build-web": "1.11.0",
"@microsoft/sp-module-interfaces": "1.11.0",
"@microsoft/sp-tslint-rules": "1.11.0",
"@microsoft/sp-webpart-workbench": "1.11.0",
"@types/chai": "3.4.34",
"@types/es6-promise": "0.0.33",
"@types/mocha": "2.2.38",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.3",
"@types/webpack-env": "1.13.1",
"@types/react": "16.9.36",
"@types/react-dom": "16.9.8",
"@microsoft/sp-build-web": "1.12.1",
"@microsoft/sp-tslint-rules": "1.12.1",
"@microsoft/sp-module-interfaces": "1.12.1",
"@microsoft/sp-webpart-workbench": "1.12.1",
"@microsoft/rush-stack-compiler-3.7": "0.2.3",
"gulp": "~4.0.2",
"ajv": "~5.2.2",
"gulp": "~3.9.1",
"gulp-sequence": "1.0.0",
"gulp-stylelint": "^13.0.0",
"stylelint": "^13.0.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.14.2",
"webpack-bundle-analyzer": "^3.6.0"
"@types/webpack-env": "1.13.1"
}
}

View File

@ -1,9 +1,9 @@
import * as React from 'react';
import { IAdaptiveCardProps } from './IAdaptiveCardProps';
import * as AdaptiveCards from "adaptivecards";
import * as AC from "adaptivecards";
import * as ACData from "adaptivecards-templating";
import * as ACFabric from "adaptivecards-fabric";
import * as ACFluentUI from "adaptivecards-fluentui";
// Support for theme and section color
import { IReadonlyTheme } from '@microsoft/sp-component-base';
@ -16,8 +16,6 @@ import * as markdownit from "markdown-it";
import { IAdaptiveCardState } from '.';
import { MessageBar, MessageBarType } from 'office-ui-fabric-react';
// Localization
import * as strings from 'AdaptiveCardHostWebPartStrings';
@ -49,15 +47,10 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
}
public render(): React.ReactElement<IAdaptiveCardProps> {
const hasErrorHander: boolean = (this.state.errors && this.state.errors.length > 0 && this.props.errorTemplate) ? true : false;
return <>
{this.state.errors.length > 0 &&
<MessageBar messageBarType={MessageBarType.error} isMultiline={true}>
{strings.AdaptiveCardErrorIntro}<br />
{this.state.errors.map((error: string) => {
return <p>{error}</p>;
})}
</MessageBar>
}
{ hasErrorHander && typeof this.props.errorTemplate === "function" && this.props.errorTemplate(this.state.errors) }
{ hasErrorHander && this.props.errorTemplate && typeof this.props.errorTemplate !== "function" && this.props.errorTemplate }
<div className={this.props.className} ref={(elm) => { this._acContainer = elm; }}></div>
</>;
}
@ -78,7 +71,7 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
templatePayload = JSON.parse(this.props.template);
} catch (error) {
console.error("Something went wrong with the template", error);
this._errorHandler(strings.TemplatingJsonError + error);
this._errorHandler([strings.TemplatingJsonError + error]);
return;
}
@ -86,23 +79,23 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
var template = new ACData.Template(templatePayload);
var context: any = {
"$root":{}
"$root": {}
};
try {
context.$root = JSON.parse(this.props.data);
} catch (error) {
console.error("Error parsing the data JSON", error);
this._errorHandler(strings.DataJsonError + error);
this._errorHandler([strings.DataJsonError + error]);
return;
}
try {
// Expand the card by combining the template and data
card = template.expand(context);
// Expand the card by combining the template and data
card = template.expand(context);
} catch (error) {
console.error("Error combining template and data", error);
this._errorHandler(strings.DataJsonError + error);
this._errorHandler([strings.DataJsonError + error]);
return;
}
} else {
@ -110,35 +103,51 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
card = JSON.parse(this.props.template);
} catch (error) {
console.error("Error parsing template", error);
this._errorHandler(strings.TemplateJsonError + error);
this._errorHandler([strings.TemplateJsonError + error]);
return;
}
}
// Create an AdaptiveCard instance
let adaptiveCard = new AdaptiveCards.AdaptiveCard();
const adaptiveCard: AC.AdaptiveCard = new AC.AdaptiveCard();
// Use Fabric controls when rendering Adaptive Cards
ACFabric.useFabricComponents();
ACFluentUI.useFluentUI();
// Get the semantic colors to adapt to changing section colors
this._adjustThemeColors(adaptiveCard);
// Handle parsing markdown from HTML
AdaptiveCards.AdaptiveCard.onProcessMarkdown = this._processMarkdownHandler;
AC.AdaptiveCard.onProcessMarkdown = this._processMarkdownHandler;
// Set the adaptive card's event handlers. onExecuteAction is invoked
// whenever an action is clicked in the card
adaptiveCard.onExecuteAction = this._executeActionHandler;
// Parse the card payload
adaptiveCard.parse(card, errors);
let serializationContext = new AC.SerializationContext();
this.setState({
errors: errors.map((error: IValidationError) => {
return error.message;
})
});
serializationContext.onParseElement = (element: AC.CardElement, _source: any, _sercontext: AC.SerializationContext) => {
let violations: Array<string> = [];
if (_sercontext.eventCount > 0) {
for (let errorIndex = 0; errorIndex < _sercontext.eventCount; errorIndex++) {
const errorItem: AC.IValidationEvent = _sercontext.getEventAt(errorIndex);
violations.push(errorItem.message);
}
if (this.props.onParseError) {
this.props.onParseError(violations);
}
}
this.setState({
errors: violations
});
};
// Parse the card payload
adaptiveCard.parse(card, serializationContext);
// Empty the div so we can replace it
while (this._acContainer.firstChild) {
@ -190,7 +199,7 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
* Adjust Adaptive Card colors based on theme colors
* @param adaptiveCard the Adaptive Cards for which you want to adjust the theme colors
*/
private _adjustThemeColors(adaptiveCard: AdaptiveCards.AdaptiveCard) {
private _adjustThemeColors(adaptiveCard: AC.AdaptiveCard) {
// Get the theme colors from the props -- if any
const { semanticColors }: IReadonlyTheme = this.props.themeVariant;
@ -200,7 +209,7 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
// Host Config defines the style and behavior of a card
// I mapped as many theme colors as I could. Feel free to adjust the colours
adaptiveCard.hostConfig = new AdaptiveCards.HostConfig({
adaptiveCard.hostConfig = new AC.HostConfig({
"separator": {
"lineThickness": 1,
"lineColor": semanticColors.bodyFrameDivider
@ -232,9 +241,12 @@ export class AdaptiveCard extends React.Component<IAdaptiveCardProps, IAdaptiveC
}
}
private _errorHandler(error: string) {
private _errorHandler(errors: string[]) {
if (this.props.onParseError && errors.length > 0) {
this.props.onParseError(errors);
}
this.setState({
errors: [error]
errors: errors
});
}
}

View File

@ -2,12 +2,44 @@ import { IReadonlyTheme } from '@microsoft/sp-component-base';
import { IAdaptiveCardActionResult } from './IAdaptiveCardActionResult';
export interface IAdaptiveCardProps {
/**
* The theme variant of the current host section
*/
themeVariant?: IReadonlyTheme | undefined;
/**
* The Adaptive Card template
*/
template: string;
/**
* The data JSON, if using Adapive Card templating
*/
data: string;
/**
* Whether we should use Adaptive Card templating?
* True will use the data property, false will use the template property
*/
useTemplating: boolean;
/**
* The CSS classname to use for the rendering the Adaptive Card
*/
className?: string;
/**
* If an action is triggered, this will be the result of the action
*/
onExecuteAction?: (action: IAdaptiveCardActionResult) => void;
onParseSuccess?: () => void;
/**
* Get notified where an error is found in the Adaptive Card
*/
onParseError?: (errors: Array<string>) => void;
/**
* The template or function to use when an error is found in the Adaptive Card
*/
errorTemplate?: JSX.Element | Function;
}

View File

@ -1,18 +1,22 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "778241d6-2ee8-47c8-857a-df3a3b1f1302",
"id": "16f46d20-f1db-4464-9516-7b23db8b069d",
"alias": "AdaptiveCardHostWebPart",
"componentType": "WebPart",
"supportsThemeVariants": true,
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
"supportsThemeVariants": true,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"supportedHosts": ["SharePointWebPart"],
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "Adaptive Card Host" },
"description": { "default": "Displays Adaptive Cards within SharePoint" },

View File

@ -1,10 +1,6 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { DisplayMode } from '@microsoft/sp-core-library';
import { HttpClient, HttpClientResponse } from '@microsoft/sp-http';
// Used for property pane
import {
IPropertyPaneConfiguration,
@ -13,6 +9,14 @@ import {
PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { DisplayMode } from '@microsoft/sp-core-library';
import { HttpClient, HttpClientResponse } from '@microsoft/sp-http';
import * as strings from 'AdaptiveCardHostWebPartStrings';
import AdaptiveCardHost from './components/AdaptiveCardHost';
import { IAdaptiveCardHostProps } from './components/IAdaptiveCardHostProps';
// Used to select which list
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
@ -35,13 +39,6 @@ import '@pnp/sp/lists';
import "@pnp/sp/views";
//import '@pnp/sp/items';
// Used for localizations
import * as strings from 'AdaptiveCardHostWebPartStrings';
// Used to render adaptive cards
import AdaptiveCardHost from './components/AdaptiveCardHost';
import { IAdaptiveCardHostProps } from './components/IAdaptiveCardHostProps';
export type TemplateSourceType = 'json' | 'url';
export type DataSourceType = 'list' | 'json' | 'url';
@ -92,6 +89,7 @@ export interface IAdaptiveCardHostWebPartProps {
dataUrl: string | undefined;
}
export default class AdaptiveCardHostWebPart extends BaseClientSideWebPart<IAdaptiveCardHostWebPartProps> {
private _themeProvider: ThemeProvider;
private _themeVariant: IReadonlyTheme | undefined;
@ -123,11 +121,11 @@ export default class AdaptiveCardHostWebPart extends BaseClientSideWebPart<IAdap
await this._loadDataFromUrl();
}
public async render(): Promise<void> {
const templateJson: string = this.properties.templateSource === 'url' && this.properties.templateUrl ? this._templateJSON: this.properties.template;
public render(): void {
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) ||
(this.properties.dataSource === 'url' && this.properties.dataUrl) ? this._dataJSON : this.properties.data;
(this.properties.dataSource === 'url' && this.properties.dataUrl) ? this._dataJSON : this.properties.data;
// The Adaptive Card control does not care where the template and data are coming from.
// Pass a valid template JSON and -- if using -- some data JSON
@ -159,7 +157,7 @@ export default class AdaptiveCardHostWebPart extends BaseClientSideWebPart<IAdap
* we load it dynamically only when we need to display the property pane.
*
*/
protected async loadPropertyPaneResources(): Promise<void> {
protected async loadPropertyPaneResources(): Promise<void> {
// load the property field code editor asynchronously
const codeEditor = await import(
'@pnp/spfx-property-controls/lib/PropertyFieldCodeEditor'
@ -189,7 +187,6 @@ export default class AdaptiveCardHostWebPart extends BaseClientSideWebPart<IAdap
language: PropertyFieldCodeEditorLanguages.JSON
});
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
const isTemplateJSONBound: boolean = this.properties.templateSource === 'json';
const isTemplateUrlBound: boolean = this.properties.templateSource === 'url';

View File

@ -14,6 +14,8 @@ import { MessageBar, MessageBarType, MessageBarButton } from 'office-ui-fabric-r
// Localization
import * as strings from 'AdaptiveCardHostWebPartStrings';
import { DisplayMode } from '@microsoft/sp-core-library';
export default class AdaptiveCardHost extends React.Component<IAdaptiveCardHostProps, {}> {
/**
@ -70,6 +72,7 @@ export default class AdaptiveCardHost extends React.Component<IAdaptiveCardHostP
>
{strings.AdaptingTemplatingWarningIntro}<a href={strings.AdaptiveCardTemplatingMoreInfoLinkUrl} target='_blank'>{strings.AdaptiveCardTemplating}</a>{strings.AdaptiveCardWarningPartTwo}<strong>{strings.UseAdaptiveTemplatingLabel}</strong>{strings.AdaptiveTemplatingEnd}
</MessageBar>}
<AdaptiveCard
template={template}
data={data}
@ -77,6 +80,22 @@ export default class AdaptiveCardHost extends React.Component<IAdaptiveCardHostP
themeVariant={themeVariant}
onExecuteAction={this._executeActionHandler}
className={styles.adaptiveCardHost}
onParseError={(errors: string[]) => {
console.log("Errors parsing adpative cards", errors);
}}
errorTemplate={(errors: string[]) => {
if (this.props.displayMode === DisplayMode.Edit) {
return (
<MessageBar messageBarType={MessageBarType.error} isMultiline={true}>
{strings.AdaptiveCardErrorIntro}<br />
{errors.map((error: string) => {
return <p>{error}</p>;
})}
</MessageBar>);
} else {
return null;
}
}}
/></>);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,64 +0,0 @@
/**
* This script updates the package-solution version analogue to the
* the package.json file.
*/
if (process.env.npm_package_version === undefined) {
throw 'Package version cannot be evaluated';
}
// define path to package-solution file
const solution = './config/package-solution.json',
teams = './teams/manifest.json';
// require filesystem instance
const fs = require('fs');
// get next automated package version from process variable
const nextPkgVersion = process.env.npm_package_version;
// make sure next build version match
const nextVersion = nextPkgVersion.indexOf('-') === -1 ?
nextPkgVersion : nextPkgVersion.split('-')[0];
// Update version in SPFx package-solution if exists
if (fs.existsSync(solution)) {
// read package-solution file
const solutionFileContent = fs.readFileSync(solution, 'UTF-8');
// parse file as json
const solutionContents = JSON.parse(solutionFileContent);
// set property of version to next version
solutionContents.solution.version = nextVersion + '.0';
// save file
fs.writeFileSync(
solution,
// convert file back to proper json
JSON.stringify(solutionContents, null, 2),
'UTF-8');
}
// Update version in teams manifest if exists
if (fs.existsSync(teams)) {
// read package-solution file
const teamsManifestContent = fs.readFileSync(teams, 'UTF-8');
// parse file as json
const teamsContent = JSON.parse(teamsManifestContent);
// set property of version to next version
teamsContent.version = nextVersion;
// save file
fs.writeFileSync(
teams,
// convert file back to proper json
JSON.stringify(teamsContent, null, 2),
'UTF-8');
}

View File

@ -1,5 +1,5 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.7/includes/tsconfig-web.json",
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
@ -19,22 +19,17 @@
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
],
"esModuleInterop": true
"es2015.collection",
"es2015.promise"
]
},
"include": [
"src/**/*.ts", "src/controls/AdaptiveCard/AdaptiveCard.tsx",
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": [
"node_modules",
"lib"
]
}

View File

@ -1,5 +1,5 @@
{
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
"rules": {
"class-name": false,
"export-name": false,